diff options
author | Chandra Seetharaman <sekharan@us.ibm.com> | 2009-10-21 12:23:04 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-04 13:00:48 -0500 |
commit | 96e6586556dfa80112f42895be93c561582d9930 (patch) | |
tree | 6f63a10bfa801ef28b355541cf617d2e2fffcebc /drivers/scsi | |
parent | 4e2ef86cd5ce057b60acea33bb71c06676e71888 (diff) |
[SCSI] scsi_dh: Make alua hardware handler's activate() async
Make the activate function asynchronous by using blk_execute_rq_nowait()
Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_alua.c | 132 |
1 files changed, 73 insertions, 59 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index e8a8928e58bc..4f0d0138f48b 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c | |||
@@ -60,11 +60,17 @@ struct alua_dh_data { | |||
60 | int bufflen; | 60 | int bufflen; |
61 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | 61 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; |
62 | int senselen; | 62 | int senselen; |
63 | struct scsi_device *sdev; | ||
64 | activate_complete callback_fn; | ||
65 | void *callback_data; | ||
63 | }; | 66 | }; |
64 | 67 | ||
65 | #define ALUA_POLICY_SWITCH_CURRENT 0 | 68 | #define ALUA_POLICY_SWITCH_CURRENT 0 |
66 | #define ALUA_POLICY_SWITCH_ALL 1 | 69 | #define ALUA_POLICY_SWITCH_ALL 1 |
67 | 70 | ||
71 | static char print_alua_state(int); | ||
72 | static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *); | ||
73 | |||
68 | static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev) | 74 | static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev) |
69 | { | 75 | { |
70 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | 76 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; |
@@ -231,18 +237,71 @@ done: | |||
231 | } | 237 | } |
232 | 238 | ||
233 | /* | 239 | /* |
240 | * alua_stpg - Evaluate SET TARGET GROUP STATES | ||
241 | * @sdev: the device to be evaluated | ||
242 | * @state: the new target group state | ||
243 | * | ||
244 | * Send a SET TARGET GROUP STATES command to the device. | ||
245 | * We only have to test here if we should resubmit the command; | ||
246 | * any other error is assumed as a failure. | ||
247 | */ | ||
248 | static void stpg_endio(struct request *req, int error) | ||
249 | { | ||
250 | struct alua_dh_data *h = req->end_io_data; | ||
251 | struct scsi_sense_hdr sense_hdr; | ||
252 | unsigned err = SCSI_DH_IO; | ||
253 | |||
254 | if (error || host_byte(req->errors) != DID_OK || | ||
255 | msg_byte(req->errors) != COMMAND_COMPLETE) | ||
256 | goto done; | ||
257 | |||
258 | if (err == SCSI_DH_IO && h->senselen > 0) { | ||
259 | err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, | ||
260 | &sense_hdr); | ||
261 | if (!err) { | ||
262 | err = SCSI_DH_IO; | ||
263 | goto done; | ||
264 | } | ||
265 | err = alua_check_sense(h->sdev, &sense_hdr); | ||
266 | if (err == ADD_TO_MLQUEUE) { | ||
267 | err = SCSI_DH_RETRY; | ||
268 | goto done; | ||
269 | } | ||
270 | sdev_printk(KERN_INFO, h->sdev, | ||
271 | "%s: stpg sense code: %02x/%02x/%02x\n", | ||
272 | ALUA_DH_NAME, sense_hdr.sense_key, | ||
273 | sense_hdr.asc, sense_hdr.ascq); | ||
274 | err = SCSI_DH_IO; | ||
275 | } | ||
276 | if (err == SCSI_DH_OK) { | ||
277 | h->state = TPGS_STATE_OPTIMIZED; | ||
278 | sdev_printk(KERN_INFO, h->sdev, | ||
279 | "%s: port group %02x switched to state %c\n", | ||
280 | ALUA_DH_NAME, h->group_id, | ||
281 | print_alua_state(h->state)); | ||
282 | } | ||
283 | done: | ||
284 | blk_put_request(req); | ||
285 | if (h->callback_fn) { | ||
286 | h->callback_fn(h->callback_data, err); | ||
287 | h->callback_fn = h->callback_data = NULL; | ||
288 | } | ||
289 | return; | ||
290 | } | ||
291 | |||
292 | /* | ||
234 | * submit_stpg - Issue a SET TARGET GROUP STATES command | 293 | * submit_stpg - Issue a SET TARGET GROUP STATES command |
235 | * @sdev: sdev the command should be sent to | ||
236 | * | 294 | * |
237 | * Currently we're only setting the current target port group state | 295 | * Currently we're only setting the current target port group state |
238 | * to 'active/optimized' and let the array firmware figure out | 296 | * to 'active/optimized' and let the array firmware figure out |
239 | * the states of the remaining groups. | 297 | * the states of the remaining groups. |
240 | */ | 298 | */ |
241 | static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) | 299 | static unsigned submit_stpg(struct alua_dh_data *h) |
242 | { | 300 | { |
243 | struct request *rq; | 301 | struct request *rq; |
244 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | 302 | int err = SCSI_DH_RES_TEMP_UNAVAIL; |
245 | int stpg_len = 8; | 303 | int stpg_len = 8; |
304 | struct scsi_device *sdev = h->sdev; | ||
246 | 305 | ||
247 | /* Prepare the data buffer */ | 306 | /* Prepare the data buffer */ |
248 | memset(h->buff, 0, stpg_len); | 307 | memset(h->buff, 0, stpg_len); |
@@ -252,7 +311,7 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) | |||
252 | 311 | ||
253 | rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); | 312 | rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); |
254 | if (!rq) | 313 | if (!rq) |
255 | goto done; | 314 | return SCSI_DH_RES_TEMP_UNAVAIL; |
256 | 315 | ||
257 | /* Prepare the command. */ | 316 | /* Prepare the command. */ |
258 | rq->cmd[0] = MAINTENANCE_OUT; | 317 | rq->cmd[0] = MAINTENANCE_OUT; |
@@ -266,17 +325,9 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) | |||
266 | rq->sense = h->sense; | 325 | rq->sense = h->sense; |
267 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | 326 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); |
268 | rq->sense_len = h->senselen = 0; | 327 | rq->sense_len = h->senselen = 0; |
328 | rq->end_io_data = h; | ||
269 | 329 | ||
270 | err = blk_execute_rq(rq->q, NULL, rq, 1); | 330 | 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; | 331 | return err; |
281 | } | 332 | } |
282 | 333 | ||
@@ -477,50 +528,6 @@ static int alua_check_sense(struct scsi_device *sdev, | |||
477 | } | 528 | } |
478 | 529 | ||
479 | /* | 530 | /* |
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 | 531 | * alua_rtpg - Evaluate REPORT TARGET GROUP STATES |
525 | * @sdev: the device to be evaluated. | 532 | * @sdev: the device to be evaluated. |
526 | * | 533 | * |
@@ -664,8 +671,14 @@ static int alua_activate(struct scsi_device *sdev, | |||
664 | goto out; | 671 | goto out; |
665 | } | 672 | } |
666 | 673 | ||
667 | if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) | 674 | if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) { |
668 | err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h); | 675 | h->callback_fn = fn; |
676 | h->callback_data = data; | ||
677 | err = submit_stpg(h); | ||
678 | if (err == SCSI_DH_OK) | ||
679 | return 0; | ||
680 | h->callback_fn = h->callback_data = NULL; | ||
681 | } | ||
669 | 682 | ||
670 | out: | 683 | out: |
671 | if (fn) | 684 | if (fn) |
@@ -748,6 +761,7 @@ static int alua_bus_attach(struct scsi_device *sdev) | |||
748 | h->rel_port = -1; | 761 | h->rel_port = -1; |
749 | h->buff = h->inq; | 762 | h->buff = h->inq; |
750 | h->bufflen = ALUA_INQUIRY_SIZE; | 763 | h->bufflen = ALUA_INQUIRY_SIZE; |
764 | h->sdev = sdev; | ||
751 | 765 | ||
752 | err = alua_initialize(sdev, h); | 766 | err = alua_initialize(sdev, h); |
753 | if (err != SCSI_DH_OK) | 767 | if (err != SCSI_DH_OK) |