diff options
Diffstat (limited to 'drivers/scsi/device_handler')
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh.c | 29 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_alua.c | 142 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_emc.c | 14 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_hp_sw.c | 95 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_rdac.c | 118 |
5 files changed, 276 insertions, 122 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 3ee1cbc89479..6fae3d285ae7 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c | |||
@@ -21,6 +21,7 @@ | |||
21 | * Mike Anderson <andmike@linux.vnet.ibm.com> | 21 | * Mike Anderson <andmike@linux.vnet.ibm.com> |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/slab.h> | ||
24 | #include <scsi/scsi_dh.h> | 25 | #include <scsi/scsi_dh.h> |
25 | #include "../scsi_priv.h" | 26 | #include "../scsi_priv.h" |
26 | 27 | ||
@@ -226,7 +227,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr, | |||
226 | * Activate a device handler | 227 | * Activate a device handler |
227 | */ | 228 | */ |
228 | if (scsi_dh->activate) | 229 | if (scsi_dh->activate) |
229 | err = scsi_dh->activate(sdev); | 230 | err = scsi_dh->activate(sdev, NULL, NULL); |
230 | else | 231 | else |
231 | err = 0; | 232 | err = 0; |
232 | } | 233 | } |
@@ -304,18 +305,15 @@ static int scsi_dh_notifier(struct notifier_block *nb, | |||
304 | sdev = to_scsi_device(dev); | 305 | sdev = to_scsi_device(dev); |
305 | 306 | ||
306 | if (action == BUS_NOTIFY_ADD_DEVICE) { | 307 | if (action == BUS_NOTIFY_ADD_DEVICE) { |
308 | err = device_create_file(dev, &scsi_dh_state_attr); | ||
309 | /* don't care about err */ | ||
307 | devinfo = device_handler_match(NULL, sdev); | 310 | devinfo = device_handler_match(NULL, sdev); |
308 | if (!devinfo) | 311 | if (devinfo) |
309 | goto out; | 312 | err = scsi_dh_handler_attach(sdev, devinfo); |
310 | |||
311 | err = scsi_dh_handler_attach(sdev, devinfo); | ||
312 | if (!err) | ||
313 | err = device_create_file(dev, &scsi_dh_state_attr); | ||
314 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | 313 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { |
315 | device_remove_file(dev, &scsi_dh_state_attr); | 314 | device_remove_file(dev, &scsi_dh_state_attr); |
316 | scsi_dh_handler_detach(sdev, NULL); | 315 | scsi_dh_handler_detach(sdev, NULL); |
317 | } | 316 | } |
318 | out: | ||
319 | return err; | 317 | return err; |
320 | } | 318 | } |
321 | 319 | ||
@@ -423,10 +421,17 @@ EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); | |||
423 | /* | 421 | /* |
424 | * scsi_dh_activate - activate the path associated with the scsi_device | 422 | * scsi_dh_activate - activate the path associated with the scsi_device |
425 | * corresponding to the given request queue. | 423 | * corresponding to the given request queue. |
426 | * @q - Request queue that is associated with the scsi_device to be | 424 | * Returns immediately without waiting for activation to be completed. |
427 | * activated. | 425 | * @q - Request queue that is associated with the scsi_device to be |
426 | * activated. | ||
427 | * @fn - Function to be called upon completion of the activation. | ||
428 | * Function fn is called with data (below) and the error code. | ||
429 | * Function fn may be called from the same calling context. So, | ||
430 | * do not hold the lock in the caller which may be needed in fn. | ||
431 | * @data - data passed to the function fn upon completion. | ||
432 | * | ||
428 | */ | 433 | */ |
429 | int scsi_dh_activate(struct request_queue *q) | 434 | int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) |
430 | { | 435 | { |
431 | int err = 0; | 436 | int err = 0; |
432 | unsigned long flags; | 437 | unsigned long flags; |
@@ -445,7 +450,7 @@ int scsi_dh_activate(struct request_queue *q) | |||
445 | return err; | 450 | return err; |
446 | 451 | ||
447 | if (scsi_dh->activate) | 452 | if (scsi_dh->activate) |
448 | err = scsi_dh->activate(sdev); | 453 | err = scsi_dh->activate(sdev, fn, data); |
449 | put_device(&sdev->sdev_gendev); | 454 | put_device(&sdev->sdev_gendev); |
450 | return err; | 455 | return err; |
451 | } | 456 | } |
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index b5cdefaf2608..1a970a76b1b9 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c | |||
@@ -19,6 +19,7 @@ | |||
19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | #include <linux/slab.h> | ||
22 | #include <scsi/scsi.h> | 23 | #include <scsi/scsi.h> |
23 | #include <scsi/scsi_eh.h> | 24 | #include <scsi/scsi_eh.h> |
24 | #include <scsi/scsi_dh.h> | 25 | #include <scsi/scsi_dh.h> |
@@ -60,11 +61,17 @@ struct alua_dh_data { | |||
60 | int bufflen; | 61 | int bufflen; |
61 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | 62 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; |
62 | int senselen; | 63 | int senselen; |
64 | struct scsi_device *sdev; | ||
65 | activate_complete callback_fn; | ||
66 | void *callback_data; | ||
63 | }; | 67 | }; |
64 | 68 | ||
65 | #define ALUA_POLICY_SWITCH_CURRENT 0 | 69 | #define ALUA_POLICY_SWITCH_CURRENT 0 |
66 | #define ALUA_POLICY_SWITCH_ALL 1 | 70 | #define ALUA_POLICY_SWITCH_ALL 1 |
67 | 71 | ||
72 | static char print_alua_state(int); | ||
73 | static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *); | ||
74 | |||
68 | static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev) | 75 | static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev) |
69 | { | 76 | { |
70 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | 77 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; |
@@ -231,18 +238,71 @@ done: | |||
231 | } | 238 | } |
232 | 239 | ||
233 | /* | 240 | /* |
241 | * alua_stpg - Evaluate SET TARGET GROUP STATES | ||
242 | * @sdev: the device to be evaluated | ||
243 | * @state: the new target group state | ||
244 | * | ||
245 | * Send a SET TARGET GROUP STATES command to the device. | ||
246 | * We only have to test here if we should resubmit the command; | ||
247 | * any other error is assumed as a failure. | ||
248 | */ | ||
249 | static void stpg_endio(struct request *req, int error) | ||
250 | { | ||
251 | struct alua_dh_data *h = req->end_io_data; | ||
252 | struct scsi_sense_hdr sense_hdr; | ||
253 | unsigned err = SCSI_DH_IO; | ||
254 | |||
255 | if (error || host_byte(req->errors) != DID_OK || | ||
256 | msg_byte(req->errors) != COMMAND_COMPLETE) | ||
257 | goto done; | ||
258 | |||
259 | if (err == SCSI_DH_IO && h->senselen > 0) { | ||
260 | err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, | ||
261 | &sense_hdr); | ||
262 | if (!err) { | ||
263 | err = SCSI_DH_IO; | ||
264 | goto done; | ||
265 | } | ||
266 | err = alua_check_sense(h->sdev, &sense_hdr); | ||
267 | if (err == ADD_TO_MLQUEUE) { | ||
268 | err = SCSI_DH_RETRY; | ||
269 | goto done; | ||
270 | } | ||
271 | sdev_printk(KERN_INFO, h->sdev, | ||
272 | "%s: stpg sense code: %02x/%02x/%02x\n", | ||
273 | ALUA_DH_NAME, sense_hdr.sense_key, | ||
274 | sense_hdr.asc, sense_hdr.ascq); | ||
275 | err = SCSI_DH_IO; | ||
276 | } | ||
277 | if (err == SCSI_DH_OK) { | ||
278 | h->state = TPGS_STATE_OPTIMIZED; | ||
279 | sdev_printk(KERN_INFO, h->sdev, | ||
280 | "%s: port group %02x switched to state %c\n", | ||
281 | ALUA_DH_NAME, h->group_id, | ||
282 | print_alua_state(h->state)); | ||
283 | } | ||
284 | done: | ||
285 | blk_put_request(req); | ||
286 | if (h->callback_fn) { | ||
287 | h->callback_fn(h->callback_data, err); | ||
288 | h->callback_fn = h->callback_data = NULL; | ||
289 | } | ||
290 | return; | ||
291 | } | ||
292 | |||
293 | /* | ||
234 | * submit_stpg - Issue a SET TARGET GROUP STATES command | 294 | * submit_stpg - Issue a SET TARGET GROUP STATES command |
235 | * @sdev: sdev the command should be sent to | ||
236 | * | 295 | * |
237 | * Currently we're only setting the current target port group state | 296 | * Currently we're only setting the current target port group state |
238 | * to 'active/optimized' and let the array firmware figure out | 297 | * to 'active/optimized' and let the array firmware figure out |
239 | * the states of the remaining groups. | 298 | * the states of the remaining groups. |
240 | */ | 299 | */ |
241 | static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) | 300 | static unsigned submit_stpg(struct alua_dh_data *h) |
242 | { | 301 | { |
243 | struct request *rq; | 302 | struct request *rq; |
244 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | 303 | int err = SCSI_DH_RES_TEMP_UNAVAIL; |
245 | int stpg_len = 8; | 304 | int stpg_len = 8; |
305 | struct scsi_device *sdev = h->sdev; | ||
246 | 306 | ||
247 | /* Prepare the data buffer */ | 307 | /* Prepare the data buffer */ |
248 | memset(h->buff, 0, stpg_len); | 308 | memset(h->buff, 0, stpg_len); |
@@ -252,7 +312,7 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) | |||
252 | 312 | ||
253 | rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); | 313 | rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); |
254 | if (!rq) | 314 | if (!rq) |
255 | goto done; | 315 | return SCSI_DH_RES_TEMP_UNAVAIL; |
256 | 316 | ||
257 | /* Prepare the command. */ | 317 | /* Prepare the command. */ |
258 | rq->cmd[0] = MAINTENANCE_OUT; | 318 | rq->cmd[0] = MAINTENANCE_OUT; |
@@ -266,17 +326,9 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) | |||
266 | rq->sense = h->sense; | 326 | rq->sense = h->sense; |
267 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | 327 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); |
268 | rq->sense_len = h->senselen = 0; | 328 | rq->sense_len = h->senselen = 0; |
329 | rq->end_io_data = h; | ||
269 | 330 | ||
270 | err = blk_execute_rq(rq->q, NULL, rq, 1); | 331 | blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio); |
271 | if (err == -EIO) { | ||
272 | sdev_printk(KERN_INFO, sdev, | ||
273 | "%s: stpg failed with %x\n", | ||
274 | ALUA_DH_NAME, rq->errors); | ||
275 | h->senselen = rq->sense_len; | ||
276 | err = SCSI_DH_IO; | ||
277 | } | ||
278 | blk_put_request(rq); | ||
279 | done: | ||
280 | return err; | 332 | return err; |
281 | } | 333 | } |
282 | 334 | ||
@@ -477,50 +529,6 @@ static int alua_check_sense(struct scsi_device *sdev, | |||
477 | } | 529 | } |
478 | 530 | ||
479 | /* | 531 | /* |
480 | * alua_stpg - Evaluate SET TARGET GROUP STATES | ||
481 | * @sdev: the device to be evaluated | ||
482 | * @state: the new target group state | ||
483 | * | ||
484 | * Send a SET TARGET GROUP STATES command to the device. | ||
485 | * We only have to test here if we should resubmit the command; | ||
486 | * any other error is assumed as a failure. | ||
487 | */ | ||
488 | static int alua_stpg(struct scsi_device *sdev, int state, | ||
489 | struct alua_dh_data *h) | ||
490 | { | ||
491 | struct scsi_sense_hdr sense_hdr; | ||
492 | unsigned err; | ||
493 | int retry = ALUA_FAILOVER_RETRIES; | ||
494 | |||
495 | retry: | ||
496 | err = submit_stpg(sdev, h); | ||
497 | if (err == SCSI_DH_IO && h->senselen > 0) { | ||
498 | err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, | ||
499 | &sense_hdr); | ||
500 | if (!err) | ||
501 | return SCSI_DH_IO; | ||
502 | err = alua_check_sense(sdev, &sense_hdr); | ||
503 | if (retry > 0 && err == ADD_TO_MLQUEUE) { | ||
504 | retry--; | ||
505 | goto retry; | ||
506 | } | ||
507 | sdev_printk(KERN_INFO, sdev, | ||
508 | "%s: stpg sense code: %02x/%02x/%02x\n", | ||
509 | ALUA_DH_NAME, sense_hdr.sense_key, | ||
510 | sense_hdr.asc, sense_hdr.ascq); | ||
511 | err = SCSI_DH_IO; | ||
512 | } | ||
513 | if (err == SCSI_DH_OK) { | ||
514 | h->state = state; | ||
515 | sdev_printk(KERN_INFO, sdev, | ||
516 | "%s: port group %02x switched to state %c\n", | ||
517 | ALUA_DH_NAME, h->group_id, | ||
518 | print_alua_state(h->state) ); | ||
519 | } | ||
520 | return err; | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * alua_rtpg - Evaluate REPORT TARGET GROUP STATES | 532 | * alua_rtpg - Evaluate REPORT TARGET GROUP STATES |
525 | * @sdev: the device to be evaluated. | 533 | * @sdev: the device to be evaluated. |
526 | * | 534 | * |
@@ -652,7 +660,8 @@ out: | |||
652 | * based on a certain policy. But until we actually encounter them it | 660 | * based on a certain policy. But until we actually encounter them it |
653 | * should be okay. | 661 | * should be okay. |
654 | */ | 662 | */ |
655 | static int alua_activate(struct scsi_device *sdev) | 663 | static int alua_activate(struct scsi_device *sdev, |
664 | activate_complete fn, void *data) | ||
656 | { | 665 | { |
657 | struct alua_dh_data *h = get_alua_data(sdev); | 666 | struct alua_dh_data *h = get_alua_data(sdev); |
658 | int err = SCSI_DH_OK; | 667 | int err = SCSI_DH_OK; |
@@ -663,11 +672,19 @@ static int alua_activate(struct scsi_device *sdev) | |||
663 | goto out; | 672 | goto out; |
664 | } | 673 | } |
665 | 674 | ||
666 | if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) | 675 | if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) { |
667 | err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h); | 676 | h->callback_fn = fn; |
677 | h->callback_data = data; | ||
678 | err = submit_stpg(h); | ||
679 | if (err == SCSI_DH_OK) | ||
680 | return 0; | ||
681 | h->callback_fn = h->callback_data = NULL; | ||
682 | } | ||
668 | 683 | ||
669 | out: | 684 | out: |
670 | return err; | 685 | if (fn) |
686 | fn(data, err); | ||
687 | return 0; | ||
671 | } | 688 | } |
672 | 689 | ||
673 | /* | 690 | /* |
@@ -701,6 +718,8 @@ static const struct scsi_dh_devlist alua_dev_list[] = { | |||
701 | {"IBM", "2145" }, | 718 | {"IBM", "2145" }, |
702 | {"Pillar", "Axiom" }, | 719 | {"Pillar", "Axiom" }, |
703 | {"Intel", "Multi-Flex"}, | 720 | {"Intel", "Multi-Flex"}, |
721 | {"NETAPP", "LUN"}, | ||
722 | {"AIX", "NVDISK"}, | ||
704 | {NULL, NULL} | 723 | {NULL, NULL} |
705 | }; | 724 | }; |
706 | 725 | ||
@@ -745,6 +764,7 @@ static int alua_bus_attach(struct scsi_device *sdev) | |||
745 | h->rel_port = -1; | 764 | h->rel_port = -1; |
746 | h->buff = h->inq; | 765 | h->buff = h->inq; |
747 | h->bufflen = ALUA_INQUIRY_SIZE; | 766 | h->bufflen = ALUA_INQUIRY_SIZE; |
767 | h->sdev = sdev; | ||
748 | 768 | ||
749 | err = alua_initialize(sdev, h); | 769 | err = alua_initialize(sdev, h); |
750 | if (err != SCSI_DH_OK) | 770 | if (err != SCSI_DH_OK) |
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 0cffe84976fe..e8a0bc3efd49 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c | |||
@@ -20,6 +20,7 @@ | |||
20 | * along with this program; see the file COPYING. If not, write to | 20 | * along with this program; see the file COPYING. If not, write to |
21 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | */ | 22 | */ |
23 | #include <linux/slab.h> | ||
23 | #include <scsi/scsi.h> | 24 | #include <scsi/scsi.h> |
24 | #include <scsi/scsi_eh.h> | 25 | #include <scsi/scsi_eh.h> |
25 | #include <scsi/scsi_dh.h> | 26 | #include <scsi/scsi_dh.h> |
@@ -272,7 +273,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, | |||
272 | int len = 0; | 273 | int len = 0; |
273 | 274 | ||
274 | rq = blk_get_request(sdev->request_queue, | 275 | rq = blk_get_request(sdev->request_queue, |
275 | (cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO); | 276 | (cmd != INQUIRY) ? WRITE : READ, GFP_NOIO); |
276 | if (!rq) { | 277 | if (!rq) { |
277 | sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); | 278 | sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); |
278 | return NULL; | 279 | return NULL; |
@@ -286,14 +287,17 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, | |||
286 | len = sizeof(short_trespass); | 287 | len = sizeof(short_trespass); |
287 | rq->cmd_flags |= REQ_RW; | 288 | rq->cmd_flags |= REQ_RW; |
288 | rq->cmd[1] = 0x10; | 289 | rq->cmd[1] = 0x10; |
290 | rq->cmd[4] = len; | ||
289 | break; | 291 | break; |
290 | case MODE_SELECT_10: | 292 | case MODE_SELECT_10: |
291 | len = sizeof(long_trespass); | 293 | len = sizeof(long_trespass); |
292 | rq->cmd_flags |= REQ_RW; | 294 | rq->cmd_flags |= REQ_RW; |
293 | rq->cmd[1] = 0x10; | 295 | rq->cmd[1] = 0x10; |
296 | rq->cmd[8] = len; | ||
294 | break; | 297 | break; |
295 | case INQUIRY: | 298 | case INQUIRY: |
296 | len = CLARIION_BUFFER_SIZE; | 299 | len = CLARIION_BUFFER_SIZE; |
300 | rq->cmd[4] = len; | ||
297 | memset(buffer, 0, len); | 301 | memset(buffer, 0, len); |
298 | break; | 302 | break; |
299 | default: | 303 | default: |
@@ -301,7 +305,6 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, | |||
301 | break; | 305 | break; |
302 | } | 306 | } |
303 | 307 | ||
304 | rq->cmd[4] = len; | ||
305 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | 308 | rq->cmd_type = REQ_TYPE_BLOCK_PC; |
306 | rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | | 309 | rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | |
307 | REQ_FAILFAST_DRIVER; | 310 | REQ_FAILFAST_DRIVER; |
@@ -528,7 +531,8 @@ retry: | |||
528 | return err; | 531 | return err; |
529 | } | 532 | } |
530 | 533 | ||
531 | static int clariion_activate(struct scsi_device *sdev) | 534 | static int clariion_activate(struct scsi_device *sdev, |
535 | activate_complete fn, void *data) | ||
532 | { | 536 | { |
533 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | 537 | struct clariion_dh_data *csdev = get_clariion_data(sdev); |
534 | int result; | 538 | int result; |
@@ -559,7 +563,9 @@ done: | |||
559 | csdev->port, lun_state[csdev->lun_state], | 563 | csdev->port, lun_state[csdev->lun_state], |
560 | csdev->default_sp + 'A'); | 564 | csdev->default_sp + 'A'); |
561 | 565 | ||
562 | return result; | 566 | if (fn) |
567 | fn(data, result); | ||
568 | return 0; | ||
563 | } | 569 | } |
564 | /* | 570 | /* |
565 | * params - parameters in the following format | 571 | * params - parameters in the following format |
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index f7da7530875e..e3916641e627 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c | |||
@@ -21,6 +21,7 @@ | |||
21 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/slab.h> | ||
24 | #include <scsi/scsi.h> | 25 | #include <scsi/scsi.h> |
25 | #include <scsi/scsi_dbg.h> | 26 | #include <scsi/scsi_dbg.h> |
26 | #include <scsi/scsi_eh.h> | 27 | #include <scsi/scsi_eh.h> |
@@ -39,8 +40,14 @@ struct hp_sw_dh_data { | |||
39 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | 40 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; |
40 | int path_state; | 41 | int path_state; |
41 | int retries; | 42 | int retries; |
43 | int retry_cnt; | ||
44 | struct scsi_device *sdev; | ||
45 | activate_complete callback_fn; | ||
46 | void *callback_data; | ||
42 | }; | 47 | }; |
43 | 48 | ||
49 | static int hp_sw_start_stop(struct hp_sw_dh_data *); | ||
50 | |||
44 | static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev) | 51 | static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev) |
45 | { | 52 | { |
46 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | 53 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; |
@@ -191,19 +198,53 @@ static int start_done(struct scsi_device *sdev, unsigned char *sense) | |||
191 | return rc; | 198 | return rc; |
192 | } | 199 | } |
193 | 200 | ||
201 | static void start_stop_endio(struct request *req, int error) | ||
202 | { | ||
203 | struct hp_sw_dh_data *h = req->end_io_data; | ||
204 | unsigned err = SCSI_DH_OK; | ||
205 | |||
206 | if (error || host_byte(req->errors) != DID_OK || | ||
207 | msg_byte(req->errors) != COMMAND_COMPLETE) { | ||
208 | sdev_printk(KERN_WARNING, h->sdev, | ||
209 | "%s: sending start_stop_unit failed with %x\n", | ||
210 | HP_SW_NAME, req->errors); | ||
211 | err = SCSI_DH_IO; | ||
212 | goto done; | ||
213 | } | ||
214 | |||
215 | if (req->sense_len > 0) { | ||
216 | err = start_done(h->sdev, h->sense); | ||
217 | if (err == SCSI_DH_RETRY) { | ||
218 | err = SCSI_DH_IO; | ||
219 | if (--h->retry_cnt) { | ||
220 | blk_put_request(req); | ||
221 | err = hp_sw_start_stop(h); | ||
222 | if (err == SCSI_DH_OK) | ||
223 | return; | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | done: | ||
228 | blk_put_request(req); | ||
229 | if (h->callback_fn) { | ||
230 | h->callback_fn(h->callback_data, err); | ||
231 | h->callback_fn = h->callback_data = NULL; | ||
232 | } | ||
233 | return; | ||
234 | |||
235 | } | ||
236 | |||
194 | /* | 237 | /* |
195 | * hp_sw_start_stop - Send START STOP UNIT command | 238 | * hp_sw_start_stop - Send START STOP UNIT command |
196 | * @sdev: sdev command should be sent to | 239 | * @sdev: sdev command should be sent to |
197 | * | 240 | * |
198 | * Sending START STOP UNIT activates the SP. | 241 | * Sending START STOP UNIT activates the SP. |
199 | */ | 242 | */ |
200 | static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h) | 243 | static int hp_sw_start_stop(struct hp_sw_dh_data *h) |
201 | { | 244 | { |
202 | struct request *req; | 245 | struct request *req; |
203 | int ret, retry; | ||
204 | 246 | ||
205 | retry: | 247 | req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC); |
206 | req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); | ||
207 | if (!req) | 248 | if (!req) |
208 | return SCSI_DH_RES_TEMP_UNAVAIL; | 249 | return SCSI_DH_RES_TEMP_UNAVAIL; |
209 | 250 | ||
@@ -217,32 +258,10 @@ retry: | |||
217 | req->sense = h->sense; | 258 | req->sense = h->sense; |
218 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); | 259 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); |
219 | req->sense_len = 0; | 260 | req->sense_len = 0; |
220 | retry = h->retries; | 261 | req->end_io_data = h; |
221 | |||
222 | ret = blk_execute_rq(req->q, NULL, req, 1); | ||
223 | if (ret == -EIO) { | ||
224 | if (req->sense_len > 0) { | ||
225 | ret = start_done(sdev, h->sense); | ||
226 | } else { | ||
227 | sdev_printk(KERN_WARNING, sdev, | ||
228 | "%s: sending start_stop_unit failed with %x\n", | ||
229 | HP_SW_NAME, req->errors); | ||
230 | ret = SCSI_DH_IO; | ||
231 | } | ||
232 | } else | ||
233 | ret = SCSI_DH_OK; | ||
234 | 262 | ||
235 | if (ret == SCSI_DH_RETRY) { | 263 | blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio); |
236 | if (--retry) { | 264 | return SCSI_DH_OK; |
237 | blk_put_request(req); | ||
238 | goto retry; | ||
239 | } | ||
240 | ret = SCSI_DH_IO; | ||
241 | } | ||
242 | |||
243 | blk_put_request(req); | ||
244 | |||
245 | return ret; | ||
246 | } | 265 | } |
247 | 266 | ||
248 | static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) | 267 | static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) |
@@ -268,7 +287,8 @@ static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) | |||
268 | * activate the passive path (and deactivate the | 287 | * activate the passive path (and deactivate the |
269 | * previously active one). | 288 | * previously active one). |
270 | */ | 289 | */ |
271 | static int hp_sw_activate(struct scsi_device *sdev) | 290 | static int hp_sw_activate(struct scsi_device *sdev, |
291 | activate_complete fn, void *data) | ||
272 | { | 292 | { |
273 | int ret = SCSI_DH_OK; | 293 | int ret = SCSI_DH_OK; |
274 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); | 294 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); |
@@ -276,14 +296,18 @@ static int hp_sw_activate(struct scsi_device *sdev) | |||
276 | ret = hp_sw_tur(sdev, h); | 296 | ret = hp_sw_tur(sdev, h); |
277 | 297 | ||
278 | if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) { | 298 | if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) { |
279 | ret = hp_sw_start_stop(sdev, h); | 299 | h->retry_cnt = h->retries; |
300 | h->callback_fn = fn; | ||
301 | h->callback_data = data; | ||
302 | ret = hp_sw_start_stop(h); | ||
280 | if (ret == SCSI_DH_OK) | 303 | if (ret == SCSI_DH_OK) |
281 | sdev_printk(KERN_INFO, sdev, | 304 | return 0; |
282 | "%s: activated path\n", | 305 | h->callback_fn = h->callback_data = NULL; |
283 | HP_SW_NAME); | ||
284 | } | 306 | } |
285 | 307 | ||
286 | return ret; | 308 | if (fn) |
309 | fn(data, ret); | ||
310 | return 0; | ||
287 | } | 311 | } |
288 | 312 | ||
289 | static const struct scsi_dh_devlist hp_sw_dh_data_list[] = { | 313 | static const struct scsi_dh_devlist hp_sw_dh_data_list[] = { |
@@ -326,6 +350,7 @@ static int hp_sw_bus_attach(struct scsi_device *sdev) | |||
326 | h = (struct hp_sw_dh_data *) scsi_dh_data->buf; | 350 | h = (struct hp_sw_dh_data *) scsi_dh_data->buf; |
327 | h->path_state = HP_SW_PATH_UNINITIALIZED; | 351 | h->path_state = HP_SW_PATH_UNINITIALIZED; |
328 | h->retries = HP_SW_RETRIES; | 352 | h->retries = HP_SW_RETRIES; |
353 | h->sdev = sdev; | ||
329 | 354 | ||
330 | ret = hp_sw_tur(sdev, h); | 355 | ret = hp_sw_tur(sdev, h); |
331 | if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED) | 356 | if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED) |
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 268189d31d9c..5b683e429542 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <scsi/scsi.h> | 22 | #include <scsi/scsi.h> |
23 | #include <scsi/scsi_eh.h> | 23 | #include <scsi/scsi_eh.h> |
24 | #include <scsi/scsi_dh.h> | 24 | #include <scsi/scsi_dh.h> |
25 | #include <linux/workqueue.h> | ||
26 | #include <linux/slab.h> | ||
25 | 27 | ||
26 | #define RDAC_NAME "rdac" | 28 | #define RDAC_NAME "rdac" |
27 | #define RDAC_RETRY_COUNT 5 | 29 | #define RDAC_RETRY_COUNT 5 |
@@ -138,7 +140,13 @@ struct rdac_controller { | |||
138 | } mode_select; | 140 | } mode_select; |
139 | u8 index; | 141 | u8 index; |
140 | u8 array_name[ARRAY_LABEL_LEN]; | 142 | u8 array_name[ARRAY_LABEL_LEN]; |
143 | spinlock_t ms_lock; | ||
144 | int ms_queued; | ||
145 | struct work_struct ms_work; | ||
146 | struct scsi_device *ms_sdev; | ||
147 | struct list_head ms_head; | ||
141 | }; | 148 | }; |
149 | |||
142 | struct c8_inquiry { | 150 | struct c8_inquiry { |
143 | u8 peripheral_info; | 151 | u8 peripheral_info; |
144 | u8 page_code; /* 0xC8 */ | 152 | u8 page_code; /* 0xC8 */ |
@@ -198,8 +206,17 @@ static const char *lun_state[] = | |||
198 | "owned (AVT mode)", | 206 | "owned (AVT mode)", |
199 | }; | 207 | }; |
200 | 208 | ||
209 | struct rdac_queue_data { | ||
210 | struct list_head entry; | ||
211 | struct rdac_dh_data *h; | ||
212 | activate_complete callback_fn; | ||
213 | void *callback_data; | ||
214 | }; | ||
215 | |||
201 | static LIST_HEAD(ctlr_list); | 216 | static LIST_HEAD(ctlr_list); |
202 | static DEFINE_SPINLOCK(list_lock); | 217 | static DEFINE_SPINLOCK(list_lock); |
218 | static struct workqueue_struct *kmpath_rdacd; | ||
219 | static void send_mode_select(struct work_struct *work); | ||
203 | 220 | ||
204 | /* | 221 | /* |
205 | * module parameter to enable rdac debug logging. | 222 | * module parameter to enable rdac debug logging. |
@@ -281,7 +298,6 @@ static struct request *rdac_failover_get(struct scsi_device *sdev, | |||
281 | rdac_pg->subpage_code = 0x1; | 298 | rdac_pg->subpage_code = 0x1; |
282 | rdac_pg->page_len[0] = 0x01; | 299 | rdac_pg->page_len[0] = 0x01; |
283 | rdac_pg->page_len[1] = 0x28; | 300 | rdac_pg->page_len[1] = 0x28; |
284 | rdac_pg->lun_table[h->lun] = 0x81; | ||
285 | } else { | 301 | } else { |
286 | struct rdac_pg_legacy *rdac_pg; | 302 | struct rdac_pg_legacy *rdac_pg; |
287 | 303 | ||
@@ -291,7 +307,6 @@ static struct request *rdac_failover_get(struct scsi_device *sdev, | |||
291 | common = &rdac_pg->common; | 307 | common = &rdac_pg->common; |
292 | rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER; | 308 | rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER; |
293 | rdac_pg->page_len = 0x68; | 309 | rdac_pg->page_len = 0x68; |
294 | rdac_pg->lun_table[h->lun] = 0x81; | ||
295 | } | 310 | } |
296 | common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS; | 311 | common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS; |
297 | common->quiescence_timeout = RDAC_QUIESCENCE_TIME; | 312 | common->quiescence_timeout = RDAC_QUIESCENCE_TIME; |
@@ -325,6 +340,7 @@ static void release_controller(struct kref *kref) | |||
325 | struct rdac_controller *ctlr; | 340 | struct rdac_controller *ctlr; |
326 | ctlr = container_of(kref, struct rdac_controller, kref); | 341 | ctlr = container_of(kref, struct rdac_controller, kref); |
327 | 342 | ||
343 | flush_workqueue(kmpath_rdacd); | ||
328 | spin_lock(&list_lock); | 344 | spin_lock(&list_lock); |
329 | list_del(&ctlr->node); | 345 | list_del(&ctlr->node); |
330 | spin_unlock(&list_lock); | 346 | spin_unlock(&list_lock); |
@@ -363,6 +379,11 @@ static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id, | |||
363 | 379 | ||
364 | kref_init(&ctlr->kref); | 380 | kref_init(&ctlr->kref); |
365 | ctlr->use_ms10 = -1; | 381 | ctlr->use_ms10 = -1; |
382 | ctlr->ms_queued = 0; | ||
383 | ctlr->ms_sdev = NULL; | ||
384 | spin_lock_init(&ctlr->ms_lock); | ||
385 | INIT_WORK(&ctlr->ms_work, send_mode_select); | ||
386 | INIT_LIST_HEAD(&ctlr->ms_head); | ||
366 | list_add(&ctlr->node, &ctlr_list); | 387 | list_add(&ctlr->node, &ctlr_list); |
367 | done: | 388 | done: |
368 | spin_unlock(&list_lock); | 389 | spin_unlock(&list_lock); |
@@ -490,7 +511,7 @@ static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) | |||
490 | } | 511 | } |
491 | 512 | ||
492 | static int mode_select_handle_sense(struct scsi_device *sdev, | 513 | static int mode_select_handle_sense(struct scsi_device *sdev, |
493 | unsigned char *sensebuf) | 514 | unsigned char *sensebuf) |
494 | { | 515 | { |
495 | struct scsi_sense_hdr sense_hdr; | 516 | struct scsi_sense_hdr sense_hdr; |
496 | int err = SCSI_DH_IO, ret; | 517 | int err = SCSI_DH_IO, ret; |
@@ -533,11 +554,29 @@ done: | |||
533 | return err; | 554 | return err; |
534 | } | 555 | } |
535 | 556 | ||
536 | static int send_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) | 557 | static void send_mode_select(struct work_struct *work) |
537 | { | 558 | { |
559 | struct rdac_controller *ctlr = | ||
560 | container_of(work, struct rdac_controller, ms_work); | ||
538 | struct request *rq; | 561 | struct request *rq; |
562 | struct scsi_device *sdev = ctlr->ms_sdev; | ||
563 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
539 | struct request_queue *q = sdev->request_queue; | 564 | struct request_queue *q = sdev->request_queue; |
540 | int err, retry_cnt = RDAC_RETRY_COUNT; | 565 | int err, retry_cnt = RDAC_RETRY_COUNT; |
566 | struct rdac_queue_data *tmp, *qdata; | ||
567 | LIST_HEAD(list); | ||
568 | u8 *lun_table; | ||
569 | |||
570 | spin_lock(&ctlr->ms_lock); | ||
571 | list_splice_init(&ctlr->ms_head, &list); | ||
572 | ctlr->ms_queued = 0; | ||
573 | ctlr->ms_sdev = NULL; | ||
574 | spin_unlock(&ctlr->ms_lock); | ||
575 | |||
576 | if (ctlr->use_ms10) | ||
577 | lun_table = ctlr->mode_select.expanded.lun_table; | ||
578 | else | ||
579 | lun_table = ctlr->mode_select.legacy.lun_table; | ||
541 | 580 | ||
542 | retry: | 581 | retry: |
543 | err = SCSI_DH_RES_TEMP_UNAVAIL; | 582 | err = SCSI_DH_RES_TEMP_UNAVAIL; |
@@ -545,6 +584,10 @@ retry: | |||
545 | if (!rq) | 584 | if (!rq) |
546 | goto done; | 585 | goto done; |
547 | 586 | ||
587 | list_for_each_entry(qdata, &list, entry) { | ||
588 | lun_table[qdata->h->lun] = 0x81; | ||
589 | } | ||
590 | |||
548 | RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " | 591 | RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " |
549 | "%s MODE_SELECT command", | 592 | "%s MODE_SELECT command", |
550 | (char *) h->ctlr->array_name, h->ctlr->index, | 593 | (char *) h->ctlr->array_name, h->ctlr->index, |
@@ -565,10 +608,45 @@ retry: | |||
565 | } | 608 | } |
566 | 609 | ||
567 | done: | 610 | done: |
568 | return err; | 611 | list_for_each_entry_safe(qdata, tmp, &list, entry) { |
612 | list_del(&qdata->entry); | ||
613 | if (err == SCSI_DH_OK) | ||
614 | qdata->h->state = RDAC_STATE_ACTIVE; | ||
615 | if (qdata->callback_fn) | ||
616 | qdata->callback_fn(qdata->callback_data, err); | ||
617 | kfree(qdata); | ||
618 | } | ||
619 | return; | ||
620 | } | ||
621 | |||
622 | static int queue_mode_select(struct scsi_device *sdev, | ||
623 | activate_complete fn, void *data) | ||
624 | { | ||
625 | struct rdac_queue_data *qdata; | ||
626 | struct rdac_controller *ctlr; | ||
627 | |||
628 | qdata = kzalloc(sizeof(*qdata), GFP_KERNEL); | ||
629 | if (!qdata) | ||
630 | return SCSI_DH_RETRY; | ||
631 | |||
632 | qdata->h = get_rdac_data(sdev); | ||
633 | qdata->callback_fn = fn; | ||
634 | qdata->callback_data = data; | ||
635 | |||
636 | ctlr = qdata->h->ctlr; | ||
637 | spin_lock(&ctlr->ms_lock); | ||
638 | list_add_tail(&qdata->entry, &ctlr->ms_head); | ||
639 | if (!ctlr->ms_queued) { | ||
640 | ctlr->ms_queued = 1; | ||
641 | ctlr->ms_sdev = sdev; | ||
642 | queue_work(kmpath_rdacd, &ctlr->ms_work); | ||
643 | } | ||
644 | spin_unlock(&ctlr->ms_lock); | ||
645 | return SCSI_DH_OK; | ||
569 | } | 646 | } |
570 | 647 | ||
571 | static int rdac_activate(struct scsi_device *sdev) | 648 | static int rdac_activate(struct scsi_device *sdev, |
649 | activate_complete fn, void *data) | ||
572 | { | 650 | { |
573 | struct rdac_dh_data *h = get_rdac_data(sdev); | 651 | struct rdac_dh_data *h = get_rdac_data(sdev); |
574 | int err = SCSI_DH_OK; | 652 | int err = SCSI_DH_OK; |
@@ -577,10 +655,15 @@ static int rdac_activate(struct scsi_device *sdev) | |||
577 | if (err != SCSI_DH_OK) | 655 | if (err != SCSI_DH_OK) |
578 | goto done; | 656 | goto done; |
579 | 657 | ||
580 | if (h->lun_state == RDAC_LUN_UNOWNED) | 658 | if (h->lun_state == RDAC_LUN_UNOWNED) { |
581 | err = send_mode_select(sdev, h); | 659 | err = queue_mode_select(sdev, fn, data); |
660 | if (err == SCSI_DH_OK) | ||
661 | return 0; | ||
662 | } | ||
582 | done: | 663 | done: |
583 | return err; | 664 | if (fn) |
665 | fn(data, err); | ||
666 | return 0; | ||
584 | } | 667 | } |
585 | 668 | ||
586 | static int rdac_prep_fn(struct scsi_device *sdev, struct request *req) | 669 | static int rdac_prep_fn(struct scsi_device *sdev, struct request *req) |
@@ -666,6 +749,8 @@ static const struct scsi_dh_devlist rdac_dev_list[] = { | |||
666 | {"IBM", "1724"}, | 749 | {"IBM", "1724"}, |
667 | {"IBM", "1726"}, | 750 | {"IBM", "1726"}, |
668 | {"IBM", "1742"}, | 751 | {"IBM", "1742"}, |
752 | {"IBM", "1745"}, | ||
753 | {"IBM", "1746"}, | ||
669 | {"IBM", "1814"}, | 754 | {"IBM", "1814"}, |
670 | {"IBM", "1815"}, | 755 | {"IBM", "1815"}, |
671 | {"IBM", "1818"}, | 756 | {"IBM", "1818"}, |
@@ -790,13 +875,26 @@ static int __init rdac_init(void) | |||
790 | int r; | 875 | int r; |
791 | 876 | ||
792 | r = scsi_register_device_handler(&rdac_dh); | 877 | r = scsi_register_device_handler(&rdac_dh); |
793 | if (r != 0) | 878 | if (r != 0) { |
794 | printk(KERN_ERR "Failed to register scsi device handler."); | 879 | printk(KERN_ERR "Failed to register scsi device handler."); |
880 | goto done; | ||
881 | } | ||
882 | |||
883 | /* | ||
884 | * Create workqueue to handle mode selects for rdac | ||
885 | */ | ||
886 | kmpath_rdacd = create_singlethread_workqueue("kmpath_rdacd"); | ||
887 | if (!kmpath_rdacd) { | ||
888 | scsi_unregister_device_handler(&rdac_dh); | ||
889 | printk(KERN_ERR "kmpath_rdacd creation failed.\n"); | ||
890 | } | ||
891 | done: | ||
795 | return r; | 892 | return r; |
796 | } | 893 | } |
797 | 894 | ||
798 | static void __exit rdac_exit(void) | 895 | static void __exit rdac_exit(void) |
799 | { | 896 | { |
897 | destroy_workqueue(kmpath_rdacd); | ||
800 | scsi_unregister_device_handler(&rdac_dh); | 898 | scsi_unregister_device_handler(&rdac_dh); |
801 | } | 899 | } |
802 | 900 | ||