diff options
| -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) |
