Commit b2460756 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Martin K. Petersen

scsi_dh_alua: Make stpg synchronous

The 'activate_complete' function needs to be executed after
stpg has finished, so we can as well execute stpg synchronously
and call the function directly.
Reviewed-by: default avatarBart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent f2ecf13a
...@@ -169,81 +169,28 @@ static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff, ...@@ -169,81 +169,28 @@ static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
} }
/* /*
* stpg_endio - Evaluate SET TARGET GROUP STATES * submit_stpg - Issue a SET TARGET PORT GROUP command
* @sdev: the device to be evaluated
* @state: the new target group state
*
* Evaluate a SET TARGET GROUP STATES command response.
*/
static void stpg_endio(struct request *req, int error)
{
struct alua_dh_data *h = req->end_io_data;
struct scsi_sense_hdr sense_hdr;
unsigned err = SCSI_DH_OK;
if (host_byte(req->errors) != DID_OK ||
msg_byte(req->errors) != COMMAND_COMPLETE) {
err = SCSI_DH_IO;
goto done;
}
if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
&sense_hdr)) {
if (sense_hdr.sense_key == NOT_READY &&
sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) {
/* ALUA state transition already in progress */
err = SCSI_DH_OK;
goto done;
}
if (sense_hdr.sense_key == UNIT_ATTENTION) {
err = SCSI_DH_RETRY;
goto done;
}
sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr);
err = SCSI_DH_IO;
} else if (error)
err = SCSI_DH_IO;
if (err == SCSI_DH_OK) {
h->state = TPGS_STATE_OPTIMIZED;
sdev_printk(KERN_INFO, h->sdev,
"%s: port group %02x switched to state %c\n",
ALUA_DH_NAME, h->group_id,
print_alua_state(h->state));
}
done:
req->end_io_data = NULL;
__blk_put_request(req->q, req);
if (h->callback_fn) {
h->callback_fn(h->callback_data, err);
h->callback_fn = h->callback_data = NULL;
}
return;
}
/*
* submit_stpg - Issue a SET TARGET GROUP STATES command
* *
* Currently we're only setting the current target port group state * Currently we're only setting the current target port group state
* to 'active/optimized' and let the array firmware figure out * to 'active/optimized' and let the array firmware figure out
* the states of the remaining groups. * the states of the remaining groups.
*/ */
static unsigned submit_stpg(struct alua_dh_data *h) static unsigned submit_stpg(struct scsi_device *sdev, int group_id,
unsigned char *sense)
{ {
struct request *rq; struct request *rq;
unsigned char stpg_data[8];
int stpg_len = 8; int stpg_len = 8;
struct scsi_device *sdev = h->sdev; int err = 0;
/* Prepare the data buffer */ /* Prepare the data buffer */
memset(h->buff, 0, stpg_len); memset(stpg_data, 0, stpg_len);
h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f; stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
put_unaligned_be16(h->group_id, &h->buff[6]); put_unaligned_be16(group_id, &stpg_data[6]);
rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); rq = get_alua_req(sdev, stpg_data, stpg_len, WRITE);
if (!rq) if (!rq)
return SCSI_DH_RES_TEMP_UNAVAIL; return DRIVER_BUSY << 24;
/* Prepare the command. */ /* Prepare the command. */
rq->cmd[0] = MAINTENANCE_OUT; rq->cmd[0] = MAINTENANCE_OUT;
...@@ -251,13 +198,17 @@ static unsigned submit_stpg(struct alua_dh_data *h) ...@@ -251,13 +198,17 @@ static unsigned submit_stpg(struct alua_dh_data *h)
put_unaligned_be32(stpg_len, &rq->cmd[6]); put_unaligned_be32(stpg_len, &rq->cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT); rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
rq->sense = h->sense; rq->sense = sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0; rq->sense_len = 0;
rq->end_io_data = h;
blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio); blk_execute_rq(rq->q, NULL, rq, 1);
return SCSI_DH_OK; if (rq->errors)
err = rq->errors;
blk_put_request(rq);
return err;
} }
/* /*
...@@ -582,59 +533,59 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ ...@@ -582,59 +533,59 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* alua_stpg - Issue a SET TARGET PORT GROUP command * alua_stpg - Issue a SET TARGET PORT GROUP command
* *
* Issue a SET TARGET PORT GROUP command and evaluate the * Issue a SET TARGET PORT GROUP command and evaluate the
* response. Returns SCSI_DH_RETRY if the target port group * response. Returns SCSI_DH_RETRY per default to trigger
* state is found to be in 'transitioning'. * a re-evaluation of the target group state or SCSI_DH_OK
* If SCSI_DH_OK is returned the passed-in 'fn' function * if no further action needs to be taken.
* this function will take care of executing 'fn'.
* Otherwise 'fn' should be executed by the caller with the
* returned error code.
*/ */
static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h, static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
activate_complete fn, void *data)
{ {
int err = SCSI_DH_OK; int retval;
int stpg = 0; struct scsi_sense_hdr sense_hdr;
if (!(h->tpgs & TPGS_MODE_EXPLICIT))
/* Only implicit ALUA supported */
goto out;
if (!(h->tpgs & TPGS_MODE_EXPLICIT)) {
/* Only implicit ALUA supported, retry */
return SCSI_DH_RETRY;
}
switch (h->state) { switch (h->state) {
case TPGS_STATE_OPTIMIZED:
return SCSI_DH_OK;
case TPGS_STATE_NONOPTIMIZED: case TPGS_STATE_NONOPTIMIZED:
stpg = 1;
if ((h->flags & ALUA_OPTIMIZE_STPG) && if ((h->flags & ALUA_OPTIMIZE_STPG) &&
!h->pref && !h->pref &&
(h->tpgs & TPGS_MODE_IMPLICIT)) (h->tpgs & TPGS_MODE_IMPLICIT))
stpg = 0; return SCSI_DH_OK;
break; break;
case TPGS_STATE_STANDBY: case TPGS_STATE_STANDBY:
case TPGS_STATE_UNAVAILABLE: case TPGS_STATE_UNAVAILABLE:
stpg = 1;
break; break;
case TPGS_STATE_OFFLINE: case TPGS_STATE_OFFLINE:
err = SCSI_DH_IO; return SCSI_DH_IO;
break;
case TPGS_STATE_TRANSITIONING: case TPGS_STATE_TRANSITIONING:
err = SCSI_DH_RETRY;
break; break;
default: default:
break; sdev_printk(KERN_INFO, sdev,
"%s: stpg failed, unhandled TPGS state %d",
ALUA_DH_NAME, h->state);
return SCSI_DH_NOSYS;
} }
retval = submit_stpg(sdev, h->group_id, h->sense);
if (stpg) { if (retval) {
h->callback_fn = fn; if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
h->callback_data = data; &sense_hdr)) {
err = submit_stpg(h); sdev_printk(KERN_INFO, sdev,
if (err != SCSI_DH_OK) "%s: stpg failed, result %d",
h->callback_fn = h->callback_data = NULL; ALUA_DH_NAME, retval);
else if (driver_byte(retval) == DRIVER_BUSY)
fn = NULL; return SCSI_DH_DEV_TEMP_BUSY;
} else {
sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
} }
out: }
if (fn) /* Retry RTPG */
fn(data, err); return SCSI_DH_RETRY;
return err;
} }
/* /*
...@@ -722,10 +673,9 @@ static int alua_activate(struct scsi_device *sdev, ...@@ -722,10 +673,9 @@ static int alua_activate(struct scsi_device *sdev,
if (optimize_stpg) if (optimize_stpg)
h->flags |= ALUA_OPTIMIZE_STPG; h->flags |= ALUA_OPTIMIZE_STPG;
err = alua_stpg(sdev, h, fn, data); err = alua_stpg(sdev, h);
out: out:
if (err != SCSI_DH_OK && fn) if (fn)
fn(data, err); fn(data, err);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment