diff options
Diffstat (limited to 'drivers/scsi/device_handler')
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh.c | 56 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_alua.c | 2 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_emc.c | 59 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_rdac.c | 116 |
4 files changed, 198 insertions, 35 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index a518f2eff19a..3ee1cbc89479 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -153,12 +153,24 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev, if (sdev->scsi_dh_data) { if (sdev->scsi_dh_data->scsi_dh != scsi_dh) err = -EBUSY; - } else if (scsi_dh->attach) + else + kref_get(&sdev->scsi_dh_data->kref); + } else if (scsi_dh->attach) { err = scsi_dh->attach(sdev); - + if (!err) { + kref_init(&sdev->scsi_dh_data->kref); + sdev->scsi_dh_data->sdev = sdev; + } + } return err; } +static void __detach_handler (struct kref *kref) +{ + struct scsi_dh_data *scsi_dh_data = container_of(kref, struct scsi_dh_data, kref); + scsi_dh_data->scsi_dh->detach(scsi_dh_data->sdev); +} + /* * scsi_dh_handler_detach - Detach a device handler from a device * @sdev - SCSI device the device handler should be detached from @@ -180,7 +192,7 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev, scsi_dh = sdev->scsi_dh_data->scsi_dh; if (scsi_dh && scsi_dh->detach) - scsi_dh->detach(sdev); + kref_put(&sdev->scsi_dh_data->kref, __detach_handler); } /* @@ -440,6 +452,39 @@ int scsi_dh_activate(struct request_queue *q) EXPORT_SYMBOL_GPL(scsi_dh_activate); /* + * scsi_dh_set_params - set the parameters for the device as per the + * string specified in params. + * @q - Request queue that is associated with the scsi_device for + * which the parameters to be set. + * @params - parameters in the following format + * "no_of_params\0param1\0param2\0param3\0...\0" + * for example, string for 2 parameters with value 10 and 21 + * is specified as "2\010\021\0". + */ +int scsi_dh_set_params(struct request_queue *q, const char *params) +{ + int err = -SCSI_DH_NOSYS; + unsigned long flags; + struct scsi_device *sdev; + struct scsi_device_handler *scsi_dh = NULL; + + spin_lock_irqsave(q->queue_lock, flags); + sdev = q->queuedata; + if (sdev && sdev->scsi_dh_data) + scsi_dh = sdev->scsi_dh_data->scsi_dh; + if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev)) + err = 0; + spin_unlock_irqrestore(q->queue_lock, flags); + + if (err) + return err; + err = scsi_dh->set_params(sdev, params); + put_device(&sdev->sdev_gendev); + return err; +} +EXPORT_SYMBOL_GPL(scsi_dh_set_params); + +/* * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for * the given name. FALSE(0) otherwise. * @name - name of the device handler. @@ -474,7 +519,6 @@ int scsi_dh_attach(struct request_queue *q, const char *name) if (!err) { err = scsi_dh_handler_attach(sdev, scsi_dh); - put_device(&sdev->sdev_gendev); } return err; @@ -505,10 +549,8 @@ void scsi_dh_detach(struct request_queue *q) return; if (sdev->scsi_dh_data) { - /* if sdev is not on internal list, detach */ scsi_dh = sdev->scsi_dh_data->scsi_dh; - if (!device_handler_match(scsi_dh, sdev)) - scsi_dh_handler_detach(sdev, scsi_dh); + scsi_dh_handler_detach(sdev, scsi_dh); } put_device(&sdev->sdev_gendev); } diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index dba154c8ff64..b5cdefaf2608 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -663,7 +663,7 @@ static int alua_activate(struct scsi_device *sdev) goto out; } - if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) + if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h); out: diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 0e572d2c5b0a..0cffe84976fe 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -561,6 +561,61 @@ done: return result; } +/* + * params - parameters in the following format + * "no_of_params\0param1\0param2\0param3\0...\0" + * for example, string for 2 parameters with value 10 and 21 + * is specified as "2\010\021\0". + */ +static int clariion_set_params(struct scsi_device *sdev, const char *params) +{ + struct clariion_dh_data *csdev = get_clariion_data(sdev); + unsigned int hr = 0, st = 0, argc; + const char *p = params; + int result = SCSI_DH_OK; + + if ((sscanf(params, "%u", &argc) != 1) || (argc != 2)) + return -EINVAL; + + while (*p++) + ; + if ((sscanf(p, "%u", &st) != 1) || (st > 1)) + return -EINVAL; + + while (*p++) + ; + if ((sscanf(p, "%u", &hr) != 1) || (hr > 1)) + return -EINVAL; + + if (st) + csdev->flags |= CLARIION_SHORT_TRESPASS; + else + csdev->flags &= ~CLARIION_SHORT_TRESPASS; + + if (hr) + csdev->flags |= CLARIION_HONOR_RESERVATIONS; + else + csdev->flags &= ~CLARIION_HONOR_RESERVATIONS; + + /* + * If this path is owned, we have to send a trespass command + * with the new parameters. If not, simply return. Next trespass + * command would use the parameters. + */ + if (csdev->lun_state != CLARIION_LUN_OWNED) + goto done; + + csdev->lun_state = CLARIION_LUN_UNINITIALIZED; + result = send_trespass_cmd(sdev, csdev); + if (result != SCSI_DH_OK) + goto done; + + /* Update status */ + result = clariion_send_inquiry(sdev, csdev); + +done: + return result; +} static const struct scsi_dh_devlist clariion_dev_list[] = { {"DGC", "RAID"}, @@ -581,11 +636,9 @@ static struct scsi_device_handler clariion_dh = { .check_sense = clariion_check_sense, .activate = clariion_activate, .prep_fn = clariion_prep_fn, + .set_params = clariion_set_params, }; -/* - * TODO: need some interface so we can set trespass values - */ static int clariion_bus_attach(struct scsi_device *sdev) { struct scsi_dh_data *scsi_dh_data; diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index fd0544f7da81..11c89311427e 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -112,6 +112,7 @@ struct c9_inquiry { #define SUBSYS_ID_LEN 16 #define SLOT_ID_LEN 2 +#define ARRAY_LABEL_LEN 31 struct c4_inquiry { u8 peripheral_info; @@ -135,6 +136,8 @@ struct rdac_controller { struct rdac_pg_legacy legacy; struct rdac_pg_expanded expanded; } mode_select; + u8 index; + u8 array_name[ARRAY_LABEL_LEN]; }; struct c8_inquiry { u8 peripheral_info; @@ -198,6 +201,31 @@ static const char *lun_state[] = static LIST_HEAD(ctlr_list); static DEFINE_SPINLOCK(list_lock); +/* + * module parameter to enable rdac debug logging. + * 2 bits for each type of logging, only two types defined for now + * Can be enhanced if required at later point + */ +static int rdac_logging = 1; +module_param(rdac_logging, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(rdac_logging, "A bit mask of rdac logging levels, " + "Default is 1 - failover logging enabled, " + "set it to 0xF to enable all the logs"); + +#define RDAC_LOG_FAILOVER 0 +#define RDAC_LOG_SENSE 2 + +#define RDAC_LOG_BITS 2 + +#define RDAC_LOG_LEVEL(SHIFT) \ + ((rdac_logging >> (SHIFT)) & ((1 << (RDAC_LOG_BITS)) - 1)) + +#define RDAC_LOG(SHIFT, sdev, f, arg...) \ +do { \ + if (unlikely(RDAC_LOG_LEVEL(SHIFT))) \ + sdev_printk(KERN_INFO, sdev, RDAC_NAME ": " f "\n", ## arg); \ +} while (0); + static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev) { struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; @@ -303,7 +331,8 @@ static void release_controller(struct kref *kref) kfree(ctlr); } -static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id) +static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id, + char *array_name) { struct rdac_controller *ctlr, *tmp; @@ -324,6 +353,14 @@ static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id) /* initialize fields of controller */ memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN); memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN); + memcpy(ctlr->array_name, array_name, ARRAY_LABEL_LEN); + + /* update the controller index */ + if (slot_id[1] == 0x31) + ctlr->index = 0; + else + ctlr->index = 1; + kref_init(&ctlr->kref); ctlr->use_ms10 = -1; list_add(&ctlr->node, &ctlr_list); @@ -363,9 +400,10 @@ done: return err; } -static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h) +static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h, + char *array_name) { - int err; + int err, i; struct c8_inquiry *inqp; err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h); @@ -377,6 +415,11 @@ static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h) inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd') return SCSI_DH_NOSYS; h->lun = inqp->lun[7]; /* Uses only the last byte */ + + for(i=0; i<ARRAY_LABEL_LEN-1; ++i) + *(array_name+i) = inqp->array_user_label[(2*i)+1]; + + *(array_name+ARRAY_LABEL_LEN-1) = '\0'; } return err; } @@ -410,7 +453,7 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) } static int initialize_controller(struct scsi_device *sdev, - struct rdac_dh_data *h) + struct rdac_dh_data *h, char *array_name) { int err; struct c4_inquiry *inqp; @@ -418,7 +461,8 @@ static int initialize_controller(struct scsi_device *sdev, err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h); if (err == SCSI_DH_OK) { inqp = &h->inq.c4; - h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id); + h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id, + array_name); if (!h->ctlr) err = SCSI_DH_RES_TEMP_UNAVAIL; } @@ -450,6 +494,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev, { struct scsi_sense_hdr sense_hdr; int err = SCSI_DH_IO, ret; + struct rdac_dh_data *h = get_rdac_data(sdev); ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr); if (!ret) @@ -478,11 +523,14 @@ static int mode_select_handle_sense(struct scsi_device *sdev, err = SCSI_DH_RETRY; break; default: - sdev_printk(KERN_INFO, sdev, - "MODE_SELECT failed with sense %02x/%02x/%02x.\n", - sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); + break; } + RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " + "MODE_SELECT returned with sense %02x/%02x/%02x", + (char *) h->ctlr->array_name, h->ctlr->index, + sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); + done: return err; } @@ -499,7 +547,9 @@ retry: if (!rq) goto done; - sdev_printk(KERN_INFO, sdev, "%s MODE_SELECT command.\n", + RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " + "%s MODE_SELECT command", + (char *) h->ctlr->array_name, h->ctlr->index, (retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying"); err = blk_execute_rq(q, NULL, rq, 1); @@ -509,8 +559,12 @@ retry: if (err == SCSI_DH_RETRY && retry_cnt--) goto retry; } - if (err == SCSI_DH_OK) + if (err == SCSI_DH_OK) { h->state = RDAC_STATE_ACTIVE; + RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " + "MODE_SELECT completed", + (char *) h->ctlr->array_name, h->ctlr->index); + } done: return err; @@ -525,17 +579,6 @@ static int rdac_activate(struct scsi_device *sdev) if (err != SCSI_DH_OK) goto done; - if (!h->ctlr) { - err = initialize_controller(sdev, h); - if (err != SCSI_DH_OK) - goto done; - } - - if (h->ctlr->use_ms10 == -1) { - err = set_mode_select(sdev, h); - if (err != SCSI_DH_OK) - goto done; - } if (h->lun_state == RDAC_LUN_UNOWNED) err = send_mode_select(sdev, h); done: @@ -559,6 +602,12 @@ static int rdac_check_sense(struct scsi_device *sdev, struct scsi_sense_hdr *sense_hdr) { struct rdac_dh_data *h = get_rdac_data(sdev); + + RDAC_LOG(RDAC_LOG_SENSE, sdev, "array %s, ctlr %d, " + "I/O returned with sense %02x/%02x/%02x", + (char *) h->ctlr->array_name, h->ctlr->index, + sense_hdr->sense_key, sense_hdr->asc, sense_hdr->ascq); + switch (sense_hdr->sense_key) { case NOT_READY: if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01) @@ -628,11 +677,18 @@ static const struct scsi_dh_devlist rdac_dev_list[] = { {"SGI", "IS"}, {"STK", "OPENstorage D280"}, {"SUN", "CSM200_R"}, + {"SUN", "LCSM100_I"}, + {"SUN", "LCSM100_S"}, + {"SUN", "LCSM100_E"}, {"SUN", "LCSM100_F"}, {"DELL", "MD3000"}, {"DELL", "MD3000i"}, + {"DELL", "MD32xx"}, + {"DELL", "MD32xxi"}, {"LSI", "INF-01-00"}, {"ENGENIO", "INF-01-00"}, + {"STK", "FLEXLINE 380"}, + {"SUN", "CSM100_R_FC"}, {NULL, NULL}, }; @@ -656,6 +712,7 @@ static int rdac_bus_attach(struct scsi_device *sdev) struct rdac_dh_data *h; unsigned long flags; int err; + char array_name[ARRAY_LABEL_LEN]; scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) + sizeof(*h) , GFP_KERNEL); @@ -670,16 +727,24 @@ static int rdac_bus_attach(struct scsi_device *sdev) h->lun = UNINITIALIZED_LUN; h->state = RDAC_STATE_ACTIVE; - err = get_lun(sdev, h); + err = get_lun_info(sdev, h, array_name); if (err != SCSI_DH_OK) goto failed; - err = check_ownership(sdev, h); + err = initialize_controller(sdev, h, array_name); if (err != SCSI_DH_OK) goto failed; + err = check_ownership(sdev, h); + if (err != SCSI_DH_OK) + goto clean_ctlr; + + err = set_mode_select(sdev, h); + if (err != SCSI_DH_OK) + goto clean_ctlr; + if (!try_module_get(THIS_MODULE)) - goto failed; + goto clean_ctlr; spin_lock_irqsave(sdev->request_queue->queue_lock, flags); sdev->scsi_dh_data = scsi_dh_data; @@ -691,6 +756,9 @@ static int rdac_bus_attach(struct scsi_device *sdev) return 0; +clean_ctlr: + kref_put(&h->ctlr->kref, release_controller); + failed: kfree(scsi_dh_data); sdev_printk(KERN_ERR, sdev, "%s: not attached\n", |