aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/device_handler
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/device_handler')
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c132
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
71static char print_alua_state(int);
72static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
73
68static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev) 74static 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 */
248static 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 }
283done:
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 */
241static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) 299static 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);
279done:
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 */
488static 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
670out: 683out:
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)