Commit fbd7ab3eb53a3b88fefa7873139a62e439860155

Authored by Chandra Seetharaman
Committed by James Bottomley
1 parent a6a8d9f87e

[SCSI] scsi_dh: add lsi rdac device handler

This patch provides the device handler to support the LSI RDAC SCSI
based storage devices.

Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

Showing 3 changed files with 698 additions and 0 deletions Side-by-side Diff

drivers/scsi/device_handler/Kconfig
... ... @@ -10,4 +10,10 @@
10 10 SCSI Device Handlers provide device specific support for
11 11 devices utilized in multipath configurations. Say Y here to
12 12 select support for specific hardware.
  13 +
  14 +config SCSI_DH_RDAC
  15 + tristate "LSI RDAC Device Handler"
  16 + depends on SCSI_DH
  17 + help
  18 + If you have a LSI RDAC select y. Otherwise, say N.
drivers/scsi/device_handler/Makefile
... ... @@ -2,4 +2,5 @@
2 2 # SCSI Device Handler
3 3 #
4 4 obj-$(CONFIG_SCSI_DH) += scsi_dh.o
  5 +obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o
drivers/scsi/device_handler/scsi_dh_rdac.c
  1 +/*
  2 + * Engenio/LSI RDAC SCSI Device Handler
  3 + *
  4 + * Copyright (C) 2005 Mike Christie. All rights reserved.
  5 + * Copyright (C) Chandra Seetharaman, IBM Corp. 2007
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License as published by
  9 + * the Free Software Foundation; either version 2 of the License, or
  10 + * (at your option) any later version.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20 + *
  21 + */
  22 +#include <scsi/scsi.h>
  23 +#include <scsi/scsi_eh.h>
  24 +#include <scsi/scsi_dh.h>
  25 +
  26 +#define RDAC_NAME "rdac"
  27 +
  28 +/*
  29 + * LSI mode page stuff
  30 + *
  31 + * These struct definitions and the forming of the
  32 + * mode page were taken from the LSI RDAC 2.4 GPL'd
  33 + * driver, and then converted to Linux conventions.
  34 + */
  35 +#define RDAC_QUIESCENCE_TIME 20;
  36 +/*
  37 + * Page Codes
  38 + */
  39 +#define RDAC_PAGE_CODE_REDUNDANT_CONTROLLER 0x2c
  40 +
  41 +/*
  42 + * Controller modes definitions
  43 + */
  44 +#define RDAC_MODE_TRANSFER_SPECIFIED_LUNS 0x02
  45 +
  46 +/*
  47 + * RDAC Options field
  48 + */
  49 +#define RDAC_FORCED_QUIESENCE 0x02
  50 +
  51 +#define RDAC_TIMEOUT (60 * HZ)
  52 +#define RDAC_RETRIES 3
  53 +
  54 +struct rdac_mode_6_hdr {
  55 + u8 data_len;
  56 + u8 medium_type;
  57 + u8 device_params;
  58 + u8 block_desc_len;
  59 +};
  60 +
  61 +struct rdac_mode_10_hdr {
  62 + u16 data_len;
  63 + u8 medium_type;
  64 + u8 device_params;
  65 + u16 reserved;
  66 + u16 block_desc_len;
  67 +};
  68 +
  69 +struct rdac_mode_common {
  70 + u8 controller_serial[16];
  71 + u8 alt_controller_serial[16];
  72 + u8 rdac_mode[2];
  73 + u8 alt_rdac_mode[2];
  74 + u8 quiescence_timeout;
  75 + u8 rdac_options;
  76 +};
  77 +
  78 +struct rdac_pg_legacy {
  79 + struct rdac_mode_6_hdr hdr;
  80 + u8 page_code;
  81 + u8 page_len;
  82 + struct rdac_mode_common common;
  83 +#define MODE6_MAX_LUN 32
  84 + u8 lun_table[MODE6_MAX_LUN];
  85 + u8 reserved2[32];
  86 + u8 reserved3;
  87 + u8 reserved4;
  88 +};
  89 +
  90 +struct rdac_pg_expanded {
  91 + struct rdac_mode_10_hdr hdr;
  92 + u8 page_code;
  93 + u8 subpage_code;
  94 + u8 page_len[2];
  95 + struct rdac_mode_common common;
  96 + u8 lun_table[256];
  97 + u8 reserved3;
  98 + u8 reserved4;
  99 +};
  100 +
  101 +struct c9_inquiry {
  102 + u8 peripheral_info;
  103 + u8 page_code; /* 0xC9 */
  104 + u8 reserved1;
  105 + u8 page_len;
  106 + u8 page_id[4]; /* "vace" */
  107 + u8 avte_cvp;
  108 + u8 path_prio;
  109 + u8 reserved2[38];
  110 +};
  111 +
  112 +#define SUBSYS_ID_LEN 16
  113 +#define SLOT_ID_LEN 2
  114 +
  115 +struct c4_inquiry {
  116 + u8 peripheral_info;
  117 + u8 page_code; /* 0xC4 */
  118 + u8 reserved1;
  119 + u8 page_len;
  120 + u8 page_id[4]; /* "subs" */
  121 + u8 subsys_id[SUBSYS_ID_LEN];
  122 + u8 revision[4];
  123 + u8 slot_id[SLOT_ID_LEN];
  124 + u8 reserved[2];
  125 +};
  126 +
  127 +struct rdac_controller {
  128 + u8 subsys_id[SUBSYS_ID_LEN];
  129 + u8 slot_id[SLOT_ID_LEN];
  130 + int use_ms10;
  131 + struct kref kref;
  132 + struct list_head node; /* list of all controllers */
  133 + union {
  134 + struct rdac_pg_legacy legacy;
  135 + struct rdac_pg_expanded expanded;
  136 + } mode_select;
  137 +};
  138 +struct c8_inquiry {
  139 + u8 peripheral_info;
  140 + u8 page_code; /* 0xC8 */
  141 + u8 reserved1;
  142 + u8 page_len;
  143 + u8 page_id[4]; /* "edid" */
  144 + u8 reserved2[3];
  145 + u8 vol_uniq_id_len;
  146 + u8 vol_uniq_id[16];
  147 + u8 vol_user_label_len;
  148 + u8 vol_user_label[60];
  149 + u8 array_uniq_id_len;
  150 + u8 array_unique_id[16];
  151 + u8 array_user_label_len;
  152 + u8 array_user_label[60];
  153 + u8 lun[8];
  154 +};
  155 +
  156 +struct c2_inquiry {
  157 + u8 peripheral_info;
  158 + u8 page_code; /* 0xC2 */
  159 + u8 reserved1;
  160 + u8 page_len;
  161 + u8 page_id[4]; /* "swr4" */
  162 + u8 sw_version[3];
  163 + u8 sw_date[3];
  164 + u8 features_enabled;
  165 + u8 max_lun_supported;
  166 + u8 partitions[239]; /* Total allocation length should be 0xFF */
  167 +};
  168 +
  169 +struct rdac_dh_data {
  170 + struct rdac_controller *ctlr;
  171 +#define UNINITIALIZED_LUN (1 << 8)
  172 + unsigned lun;
  173 +#define RDAC_STATE_ACTIVE 0
  174 +#define RDAC_STATE_PASSIVE 1
  175 + unsigned char state;
  176 + unsigned char sense[SCSI_SENSE_BUFFERSIZE];
  177 + union {
  178 + struct c2_inquiry c2;
  179 + struct c4_inquiry c4;
  180 + struct c8_inquiry c8;
  181 + struct c9_inquiry c9;
  182 + } inq;
  183 +};
  184 +
  185 +static LIST_HEAD(ctlr_list);
  186 +static DEFINE_SPINLOCK(list_lock);
  187 +
  188 +static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev)
  189 +{
  190 + struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
  191 + BUG_ON(scsi_dh_data == NULL);
  192 + return ((struct rdac_dh_data *) scsi_dh_data->buf);
  193 +}
  194 +
  195 +static struct request *get_rdac_req(struct scsi_device *sdev,
  196 + void *buffer, unsigned buflen, int rw)
  197 +{
  198 + struct request *rq;
  199 + struct request_queue *q = sdev->request_queue;
  200 + struct rdac_dh_data *h = get_rdac_data(sdev);
  201 +
  202 + rq = blk_get_request(q, rw, GFP_KERNEL);
  203 +
  204 + if (!rq) {
  205 + sdev_printk(KERN_INFO, sdev,
  206 + "get_rdac_req: blk_get_request failed.\n");
  207 + return NULL;
  208 + }
  209 +
  210 + if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) {
  211 + blk_put_request(rq);
  212 + sdev_printk(KERN_INFO, sdev,
  213 + "get_rdac_req: blk_rq_map_kern failed.\n");
  214 + return NULL;
  215 + }
  216 +
  217 + memset(&rq->cmd, 0, BLK_MAX_CDB);
  218 + rq->sense = h->sense;
  219 + memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
  220 + rq->sense_len = 0;
  221 +
  222 + rq->cmd_type = REQ_TYPE_BLOCK_PC;
  223 + rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
  224 + rq->retries = RDAC_RETRIES;
  225 + rq->timeout = RDAC_TIMEOUT;
  226 +
  227 + return rq;
  228 +}
  229 +
  230 +static struct request *rdac_failover_get(struct scsi_device *sdev)
  231 +{
  232 + struct request *rq;
  233 + struct rdac_mode_common *common;
  234 + unsigned data_size;
  235 + struct rdac_dh_data *h = get_rdac_data(sdev);
  236 +
  237 + if (h->ctlr->use_ms10) {
  238 + struct rdac_pg_expanded *rdac_pg;
  239 +
  240 + data_size = sizeof(struct rdac_pg_expanded);
  241 + rdac_pg = &h->ctlr->mode_select.expanded;
  242 + memset(rdac_pg, 0, data_size);
  243 + common = &rdac_pg->common;
  244 + rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER + 0x40;
  245 + rdac_pg->subpage_code = 0x1;
  246 + rdac_pg->page_len[0] = 0x01;
  247 + rdac_pg->page_len[1] = 0x28;
  248 + rdac_pg->lun_table[h->lun] = 0x81;
  249 + } else {
  250 + struct rdac_pg_legacy *rdac_pg;
  251 +
  252 + data_size = sizeof(struct rdac_pg_legacy);
  253 + rdac_pg = &h->ctlr->mode_select.legacy;
  254 + memset(rdac_pg, 0, data_size);
  255 + common = &rdac_pg->common;
  256 + rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER;
  257 + rdac_pg->page_len = 0x68;
  258 + rdac_pg->lun_table[h->lun] = 0x81;
  259 + }
  260 + common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS;
  261 + common->quiescence_timeout = RDAC_QUIESCENCE_TIME;
  262 + common->rdac_options = RDAC_FORCED_QUIESENCE;
  263 +
  264 + /* get request for block layer packet command */
  265 + rq = get_rdac_req(sdev, &h->ctlr->mode_select, data_size, WRITE);
  266 + if (!rq)
  267 + return NULL;
  268 +
  269 + /* Prepare the command. */
  270 + if (h->ctlr->use_ms10) {
  271 + rq->cmd[0] = MODE_SELECT_10;
  272 + rq->cmd[7] = data_size >> 8;
  273 + rq->cmd[8] = data_size & 0xff;
  274 + } else {
  275 + rq->cmd[0] = MODE_SELECT;
  276 + rq->cmd[4] = data_size;
  277 + }
  278 + rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
  279 +
  280 + return rq;
  281 +}
  282 +
  283 +static void release_controller(struct kref *kref)
  284 +{
  285 + struct rdac_controller *ctlr;
  286 + ctlr = container_of(kref, struct rdac_controller, kref);
  287 +
  288 + spin_lock(&list_lock);
  289 + list_del(&ctlr->node);
  290 + spin_unlock(&list_lock);
  291 + kfree(ctlr);
  292 +}
  293 +
  294 +static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id)
  295 +{
  296 + struct rdac_controller *ctlr, *tmp;
  297 +
  298 + spin_lock(&list_lock);
  299 +
  300 + list_for_each_entry(tmp, &ctlr_list, node) {
  301 + if ((memcmp(tmp->subsys_id, subsys_id, SUBSYS_ID_LEN) == 0) &&
  302 + (memcmp(tmp->slot_id, slot_id, SLOT_ID_LEN) == 0)) {
  303 + kref_get(&tmp->kref);
  304 + spin_unlock(&list_lock);
  305 + return tmp;
  306 + }
  307 + }
  308 + ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC);
  309 + if (!ctlr)
  310 + goto done;
  311 +
  312 + /* initialize fields of controller */
  313 + memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN);
  314 + memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN);
  315 + kref_init(&ctlr->kref);
  316 + ctlr->use_ms10 = -1;
  317 + list_add(&ctlr->node, &ctlr_list);
  318 +done:
  319 + spin_unlock(&list_lock);
  320 + return ctlr;
  321 +}
  322 +
  323 +static int submit_inquiry(struct scsi_device *sdev, int page_code,
  324 + unsigned int len)
  325 +{
  326 + struct request *rq;
  327 + struct request_queue *q = sdev->request_queue;
  328 + struct rdac_dh_data *h = get_rdac_data(sdev);
  329 + int err = SCSI_DH_RES_TEMP_UNAVAIL;
  330 +
  331 + rq = get_rdac_req(sdev, &h->inq, len, READ);
  332 + if (!rq)
  333 + goto done;
  334 +
  335 + /* Prepare the command. */
  336 + rq->cmd[0] = INQUIRY;
  337 + rq->cmd[1] = 1;
  338 + rq->cmd[2] = page_code;
  339 + rq->cmd[4] = len;
  340 + rq->cmd_len = COMMAND_SIZE(INQUIRY);
  341 + err = blk_execute_rq(q, NULL, rq, 1);
  342 + if (err == -EIO)
  343 + err = SCSI_DH_IO;
  344 +done:
  345 + return err;
  346 +}
  347 +
  348 +static int get_lun(struct scsi_device *sdev)
  349 +{
  350 + int err;
  351 + struct c8_inquiry *inqp;
  352 + struct rdac_dh_data *h = get_rdac_data(sdev);
  353 +
  354 + err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry));
  355 + if (err == SCSI_DH_OK) {
  356 + inqp = &h->inq.c8;
  357 + h->lun = inqp->lun[7]; /* currently it uses only one byte */
  358 + }
  359 + return err;
  360 +}
  361 +
  362 +#define RDAC_OWNED 0
  363 +#define RDAC_UNOWNED 1
  364 +#define RDAC_FAILED 2
  365 +static int check_ownership(struct scsi_device *sdev)
  366 +{
  367 + int err;
  368 + struct c9_inquiry *inqp;
  369 + struct rdac_dh_data *h = get_rdac_data(sdev);
  370 +
  371 + err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry));
  372 + if (err == SCSI_DH_OK) {
  373 + err = RDAC_UNOWNED;
  374 + inqp = &h->inq.c9;
  375 + /*
  376 + * If in AVT mode or if the path already owns the LUN,
  377 + * return RDAC_OWNED;
  378 + */
  379 + if (((inqp->avte_cvp >> 7) == 0x1) ||
  380 + ((inqp->avte_cvp & 0x1) != 0))
  381 + err = RDAC_OWNED;
  382 + } else
  383 + err = RDAC_FAILED;
  384 + return err;
  385 +}
  386 +
  387 +static int initialize_controller(struct scsi_device *sdev)
  388 +{
  389 + int err;
  390 + struct c4_inquiry *inqp;
  391 + struct rdac_dh_data *h = get_rdac_data(sdev);
  392 +
  393 + err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry));
  394 + if (err == SCSI_DH_OK) {
  395 + inqp = &h->inq.c4;
  396 + h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id);
  397 + if (!h->ctlr)
  398 + err = SCSI_DH_RES_TEMP_UNAVAIL;
  399 + }
  400 + return err;
  401 +}
  402 +
  403 +static int set_mode_select(struct scsi_device *sdev)
  404 +{
  405 + int err;
  406 + struct c2_inquiry *inqp;
  407 + struct rdac_dh_data *h = get_rdac_data(sdev);
  408 +
  409 + err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry));
  410 + if (err == SCSI_DH_OK) {
  411 + inqp = &h->inq.c2;
  412 + /*
  413 + * If more than MODE6_MAX_LUN luns are supported, use
  414 + * mode select 10
  415 + */
  416 + if (inqp->max_lun_supported >= MODE6_MAX_LUN)
  417 + h->ctlr->use_ms10 = 1;
  418 + else
  419 + h->ctlr->use_ms10 = 0;
  420 + }
  421 + return err;
  422 +}
  423 +
  424 +static int mode_select_handle_sense(struct scsi_device *sdev)
  425 +{
  426 + struct scsi_sense_hdr sense_hdr;
  427 + struct rdac_dh_data *h = get_rdac_data(sdev);
  428 + int sense, err = SCSI_DH_IO, ret;
  429 +
  430 + ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
  431 + if (!ret)
  432 + goto done;
  433 +
  434 + err = SCSI_DH_OK;
  435 + sense = (sense_hdr.sense_key << 16) | (sense_hdr.asc << 8) |
  436 + sense_hdr.ascq;
  437 + /* If it is retryable failure, submit the c9 inquiry again */
  438 + if (sense == 0x59136 || sense == 0x68b02 || sense == 0xb8b02 ||
  439 + sense == 0x62900) {
  440 + /* 0x59136 - Command lock contention
  441 + * 0x[6b]8b02 - Quiesense in progress or achieved
  442 + * 0x62900 - Power On, Reset, or Bus Device Reset
  443 + */
  444 + err = SCSI_DH_RETRY;
  445 + }
  446 +
  447 + if (sense)
  448 + sdev_printk(KERN_INFO, sdev,
  449 + "MODE_SELECT failed with sense 0x%x.\n", sense);
  450 +done:
  451 + return err;
  452 +}
  453 +
  454 +static int send_mode_select(struct scsi_device *sdev)
  455 +{
  456 + struct request *rq;
  457 + struct request_queue *q = sdev->request_queue;
  458 + struct rdac_dh_data *h = get_rdac_data(sdev);
  459 + int err = SCSI_DH_RES_TEMP_UNAVAIL;
  460 +
  461 + rq = rdac_failover_get(sdev);
  462 + if (!rq)
  463 + goto done;
  464 +
  465 + sdev_printk(KERN_INFO, sdev, "queueing MODE_SELECT command.\n");
  466 +
  467 + err = blk_execute_rq(q, NULL, rq, 1);
  468 + if (err != SCSI_DH_OK)
  469 + err = mode_select_handle_sense(sdev);
  470 + if (err == SCSI_DH_OK)
  471 + h->state = RDAC_STATE_ACTIVE;
  472 +done:
  473 + return err;
  474 +}
  475 +
  476 +static int rdac_activate(struct scsi_device *sdev)
  477 +{
  478 + struct rdac_dh_data *h = get_rdac_data(sdev);
  479 + int err = SCSI_DH_OK;
  480 +
  481 + if (h->lun == UNINITIALIZED_LUN) {
  482 + err = get_lun(sdev);
  483 + if (err != SCSI_DH_OK)
  484 + goto done;
  485 + }
  486 +
  487 + err = check_ownership(sdev);
  488 + switch (err) {
  489 + case RDAC_UNOWNED:
  490 + break;
  491 + case RDAC_OWNED:
  492 + err = SCSI_DH_OK;
  493 + goto done;
  494 + case RDAC_FAILED:
  495 + default:
  496 + err = SCSI_DH_IO;
  497 + goto done;
  498 + }
  499 +
  500 + if (!h->ctlr) {
  501 + err = initialize_controller(sdev);
  502 + if (err != SCSI_DH_OK)
  503 + goto done;
  504 + }
  505 +
  506 + if (h->ctlr->use_ms10 == -1) {
  507 + err = set_mode_select(sdev);
  508 + if (err != SCSI_DH_OK)
  509 + goto done;
  510 + }
  511 +
  512 + err = send_mode_select(sdev);
  513 +done:
  514 + return err;
  515 +}
  516 +
  517 +static int rdac_prep_fn(struct scsi_device *sdev, struct request *req)
  518 +{
  519 + struct rdac_dh_data *h = get_rdac_data(sdev);
  520 + int ret = BLKPREP_OK;
  521 +
  522 + if (h->state != RDAC_STATE_ACTIVE) {
  523 + ret = BLKPREP_KILL;
  524 + req->cmd_flags |= REQ_QUIET;
  525 + }
  526 + return ret;
  527 +
  528 +}
  529 +
  530 +static int rdac_check_sense(struct scsi_device *sdev,
  531 + struct scsi_sense_hdr *sense_hdr)
  532 +{
  533 + struct rdac_dh_data *h = get_rdac_data(sdev);
  534 + switch (sense_hdr->sense_key) {
  535 + case NOT_READY:
  536 + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x81)
  537 + /* LUN Not Ready - Storage firmware incompatible
  538 + * Manual code synchonisation required.
  539 + *
  540 + * Nothing we can do here. Try to bypass the path.
  541 + */
  542 + return SUCCESS;
  543 + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0xA1)
  544 + /* LUN Not Ready - Quiescense in progress
  545 + *
  546 + * Just retry and wait.
  547 + */
  548 + return NEEDS_RETRY;
  549 + break;
  550 + case ILLEGAL_REQUEST:
  551 + if (sense_hdr->asc == 0x94 && sense_hdr->ascq == 0x01) {
  552 + /* Invalid Request - Current Logical Unit Ownership.
  553 + * Controller is not the current owner of the LUN,
  554 + * Fail the path, so that the other path be used.
  555 + */
  556 + h->state = RDAC_STATE_PASSIVE;
  557 + return SUCCESS;
  558 + }
  559 + break;
  560 + case UNIT_ATTENTION:
  561 + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
  562 + /*
  563 + * Power On, Reset, or Bus Device Reset, just retry.
  564 + */
  565 + return NEEDS_RETRY;
  566 + break;
  567 + }
  568 + /* success just means we do not care what scsi-ml does */
  569 + return SCSI_RETURN_NOT_HANDLED;
  570 +}
  571 +
  572 +static const struct {
  573 + char *vendor;
  574 + char *model;
  575 +} rdac_dev_list[] = {
  576 + {"IBM", "1722"},
  577 + {"IBM", "1724"},
  578 + {"IBM", "1726"},
  579 + {"IBM", "1742"},
  580 + {"IBM", "1814"},
  581 + {"IBM", "1815"},
  582 + {"IBM", "1818"},
  583 + {"IBM", "3526"},
  584 + {"SGI", "TP9400"},
  585 + {"SGI", "TP9500"},
  586 + {"SGI", "IS"},
  587 + {"STK", "OPENstorage D280"},
  588 + {"SUN", "CSM200_R"},
  589 + {"SUN", "LCSM100_F"},
  590 + {NULL, NULL},
  591 +};
  592 +
  593 +static int rdac_bus_notify(struct notifier_block *, unsigned long, void *);
  594 +
  595 +static struct scsi_device_handler rdac_dh = {
  596 + .name = RDAC_NAME,
  597 + .module = THIS_MODULE,
  598 + .nb.notifier_call = rdac_bus_notify,
  599 + .prep_fn = rdac_prep_fn,
  600 + .check_sense = rdac_check_sense,
  601 + .activate = rdac_activate,
  602 +};
  603 +
  604 +/*
  605 + * TODO: need some interface so we can set trespass values
  606 + */
  607 +static int rdac_bus_notify(struct notifier_block *nb,
  608 + unsigned long action, void *data)
  609 +{
  610 + struct device *dev = data;
  611 + struct scsi_device *sdev = to_scsi_device(dev);
  612 + struct scsi_dh_data *scsi_dh_data;
  613 + struct rdac_dh_data *h;
  614 + int i, found = 0;
  615 + unsigned long flags;
  616 +
  617 + if (action == BUS_NOTIFY_ADD_DEVICE) {
  618 + for (i = 0; rdac_dev_list[i].vendor; i++) {
  619 + if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor,
  620 + strlen(rdac_dev_list[i].vendor)) &&
  621 + !strncmp(sdev->model, rdac_dev_list[i].model,
  622 + strlen(rdac_dev_list[i].model))) {
  623 + found = 1;
  624 + break;
  625 + }
  626 + }
  627 + if (!found)
  628 + goto out;
  629 +
  630 + scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
  631 + + sizeof(*h) , GFP_KERNEL);
  632 + if (!scsi_dh_data) {
  633 + sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
  634 + RDAC_NAME);
  635 + goto out;
  636 + }
  637 +
  638 + scsi_dh_data->scsi_dh = &rdac_dh;
  639 + h = (struct rdac_dh_data *) scsi_dh_data->buf;
  640 + h->lun = UNINITIALIZED_LUN;
  641 + h->state = RDAC_STATE_ACTIVE;
  642 + spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
  643 + sdev->scsi_dh_data = scsi_dh_data;
  644 + spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
  645 + try_module_get(THIS_MODULE);
  646 +
  647 + sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME);
  648 +
  649 + } else if (action == BUS_NOTIFY_DEL_DEVICE) {
  650 + if (sdev->scsi_dh_data == NULL ||
  651 + sdev->scsi_dh_data->scsi_dh != &rdac_dh)
  652 + goto out;
  653 +
  654 + spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
  655 + scsi_dh_data = sdev->scsi_dh_data;
  656 + sdev->scsi_dh_data = NULL;
  657 + spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
  658 +
  659 + h = (struct rdac_dh_data *) scsi_dh_data->buf;
  660 + if (h->ctlr)
  661 + kref_put(&h->ctlr->kref, release_controller);
  662 + kfree(scsi_dh_data);
  663 + module_put(THIS_MODULE);
  664 + sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME);
  665 + }
  666 +
  667 +out:
  668 + return 0;
  669 +}
  670 +
  671 +static int __init rdac_init(void)
  672 +{
  673 + int r;
  674 +
  675 + r = scsi_register_device_handler(&rdac_dh);
  676 + if (r != 0)
  677 + printk(KERN_ERR "Failed to register scsi device handler.");
  678 + return r;
  679 +}
  680 +
  681 +static void __exit rdac_exit(void)
  682 +{
  683 + scsi_unregister_device_handler(&rdac_dh);
  684 +}
  685 +
  686 +module_init(rdac_init);
  687 +module_exit(rdac_exit);
  688 +
  689 +MODULE_DESCRIPTION("Multipath LSI/Engenio RDAC driver");
  690 +MODULE_AUTHOR("Mike Christie, Chandra Seetharaman");
  691 +MODULE_LICENSE("GPL");