Commit 80e1836c authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Jens Axboe

scsi_dh_hp_sw: switch to scsi_execute_req_flags()

Switch to scsi_execute_req_flags() instead of using the block interface
directly.  This will set REQ_QUIET and REQ_PREEMPT, but this is okay as
we're evaluating the errors anyway and should be able to send the command
even if the device is quiesced.
Signed-off-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Acked-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent b78205c9
...@@ -38,13 +38,10 @@ ...@@ -38,13 +38,10 @@
#define HP_SW_PATH_PASSIVE 1 #define HP_SW_PATH_PASSIVE 1
struct hp_sw_dh_data { struct hp_sw_dh_data {
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
int path_state; int path_state;
int retries; int retries;
int retry_cnt; int retry_cnt;
struct scsi_device *sdev; struct scsi_device *sdev;
activate_complete callback_fn;
void *callback_data;
}; };
static int hp_sw_start_stop(struct hp_sw_dh_data *); static int hp_sw_start_stop(struct hp_sw_dh_data *);
...@@ -56,43 +53,34 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *); ...@@ -56,43 +53,34 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *);
* *
* Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
*/ */
static int tur_done(struct scsi_device *sdev, unsigned char *sense) static int tur_done(struct scsi_device *sdev, struct hp_sw_dh_data *h,
struct scsi_sense_hdr *sshdr)
{ {
struct scsi_sense_hdr sshdr; int ret = SCSI_DH_IO;
int ret;
ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); switch (sshdr->sense_key) {
if (!ret) {
sdev_printk(KERN_WARNING, sdev,
"%s: sending tur failed, no sense available\n",
HP_SW_NAME);
ret = SCSI_DH_IO;
goto done;
}
switch (sshdr.sense_key) {
case UNIT_ATTENTION: case UNIT_ATTENTION:
ret = SCSI_DH_IMM_RETRY; ret = SCSI_DH_IMM_RETRY;
break; break;
case NOT_READY: case NOT_READY:
if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) { if (sshdr->asc == 0x04 && sshdr->ascq == 2) {
/* /*
* LUN not ready - Initialization command required * LUN not ready - Initialization command required
* *
* This is the passive path * This is the passive path
*/ */
ret = SCSI_DH_DEV_OFFLINED; h->path_state = HP_SW_PATH_PASSIVE;
ret = SCSI_DH_OK;
break; break;
} }
/* Fallthrough */ /* Fallthrough */
default: default:
sdev_printk(KERN_WARNING, sdev, sdev_printk(KERN_WARNING, sdev,
"%s: sending tur failed, sense %x/%x/%x\n", "%s: sending tur failed, sense %x/%x/%x\n",
HP_SW_NAME, sshdr.sense_key, sshdr.asc, HP_SW_NAME, sshdr->sense_key, sshdr->asc,
sshdr.ascq); sshdr->ascq);
break; break;
} }
done:
return ret; return ret;
} }
...@@ -105,130 +93,35 @@ static int tur_done(struct scsi_device *sdev, unsigned char *sense) ...@@ -105,130 +93,35 @@ static int tur_done(struct scsi_device *sdev, unsigned char *sense)
*/ */
static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
{ {
struct request *req; unsigned char cmd[6] = { TEST_UNIT_READY };
int ret; struct scsi_sense_hdr sshdr;
int ret = SCSI_DH_OK, res;
u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
REQ_FAILFAST_DRIVER;
retry: retry:
req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); res = scsi_execute_req_flags(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
if (IS_ERR(req)) HP_SW_TIMEOUT, HP_SW_RETRIES,
return SCSI_DH_RES_TEMP_UNAVAIL; NULL, req_flags, 0);
if (res) {
blk_rq_set_block_pc(req); if (scsi_sense_valid(&sshdr))
req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | ret = tur_done(sdev, h, &sshdr);
REQ_FAILFAST_DRIVER; else {
req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
req->cmd[0] = TEST_UNIT_READY;
req->timeout = HP_SW_TIMEOUT;
req->sense = h->sense;
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
req->sense_len = 0;
ret = blk_execute_rq(req->q, NULL, req, 1);
if (ret == -EIO) {
if (req->sense_len > 0) {
ret = tur_done(sdev, h->sense);
} else {
sdev_printk(KERN_WARNING, sdev, sdev_printk(KERN_WARNING, sdev,
"%s: sending tur failed with %x\n", "%s: sending tur failed with %x\n",
HP_SW_NAME, req->errors); HP_SW_NAME, res);
ret = SCSI_DH_IO; ret = SCSI_DH_IO;
} }
} else { } else {
h->path_state = HP_SW_PATH_ACTIVE; h->path_state = HP_SW_PATH_ACTIVE;
ret = SCSI_DH_OK; ret = SCSI_DH_OK;
} }
if (ret == SCSI_DH_IMM_RETRY) { if (ret == SCSI_DH_IMM_RETRY)
blk_put_request(req);
goto retry; goto retry;
}
if (ret == SCSI_DH_DEV_OFFLINED) {
h->path_state = HP_SW_PATH_PASSIVE;
ret = SCSI_DH_OK;
}
blk_put_request(req);
return ret; return ret;
} }
/*
* start_done - Handle START STOP UNIT return status
* @sdev: sdev the command has been sent to
* @errors: blk error code
*/
static int start_done(struct scsi_device *sdev, unsigned char *sense)
{
struct scsi_sense_hdr sshdr;
int rc;
rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
if (!rc) {
sdev_printk(KERN_WARNING, sdev,
"%s: sending start_stop_unit failed, "
"no sense available\n",
HP_SW_NAME);
return SCSI_DH_IO;
}
switch (sshdr.sense_key) {
case NOT_READY:
if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
/*
* LUN not ready - manual intervention required
*
* Switch-over in progress, retry.
*/
rc = SCSI_DH_RETRY;
break;
}
/* fall through */
default:
sdev_printk(KERN_WARNING, sdev,
"%s: sending start_stop_unit failed, sense %x/%x/%x\n",
HP_SW_NAME, sshdr.sense_key, sshdr.asc,
sshdr.ascq);
rc = SCSI_DH_IO;
}
return rc;
}
static void start_stop_endio(struct request *req, int error)
{
struct hp_sw_dh_data *h = req->end_io_data;
unsigned err = SCSI_DH_OK;
if (error || host_byte(req->errors) != DID_OK ||
msg_byte(req->errors) != COMMAND_COMPLETE) {
sdev_printk(KERN_WARNING, h->sdev,
"%s: sending start_stop_unit failed with %x\n",
HP_SW_NAME, req->errors);
err = SCSI_DH_IO;
goto done;
}
if (req->sense_len > 0) {
err = start_done(h->sdev, h->sense);
if (err == SCSI_DH_RETRY) {
err = SCSI_DH_IO;
if (--h->retry_cnt) {
blk_put_request(req);
err = hp_sw_start_stop(h);
if (err == SCSI_DH_OK)
return;
}
}
}
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;
}
/* /*
* hp_sw_start_stop - Send START STOP UNIT command * hp_sw_start_stop - Send START STOP UNIT command
* @sdev: sdev command should be sent to * @sdev: sdev command should be sent to
...@@ -237,26 +130,48 @@ static void start_stop_endio(struct request *req, int error) ...@@ -237,26 +130,48 @@ static void start_stop_endio(struct request *req, int error)
*/ */
static int hp_sw_start_stop(struct hp_sw_dh_data *h) static int hp_sw_start_stop(struct hp_sw_dh_data *h)
{ {
struct request *req; unsigned char cmd[6] = { START_STOP, 0, 0, 0, 1, 0 };
struct scsi_sense_hdr sshdr;
req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC); struct scsi_device *sdev = h->sdev;
if (IS_ERR(req)) int res, rc = SCSI_DH_OK;
return SCSI_DH_RES_TEMP_UNAVAIL; int retry_cnt = HP_SW_RETRIES;
u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
blk_rq_set_block_pc(req); REQ_FAILFAST_DRIVER;
req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
REQ_FAILFAST_DRIVER;
req->cmd_len = COMMAND_SIZE(START_STOP);
req->cmd[0] = START_STOP;
req->cmd[4] = 1; /* Start spin cycle */
req->timeout = HP_SW_TIMEOUT;
req->sense = h->sense;
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
req->sense_len = 0;
req->end_io_data = h;
blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio); retry:
return SCSI_DH_OK; res = scsi_execute_req_flags(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
HP_SW_TIMEOUT, HP_SW_RETRIES,
NULL, req_flags, 0);
if (res) {
if (!scsi_sense_valid(&sshdr)) {
sdev_printk(KERN_WARNING, sdev,
"%s: sending start_stop_unit failed, "
"no sense available\n", HP_SW_NAME);
return SCSI_DH_IO;
}
switch (sshdr.sense_key) {
case NOT_READY:
if (sshdr.asc == 0x04 && sshdr.ascq == 3) {
/*
* LUN not ready - manual intervention required
*
* Switch-over in progress, retry.
*/
if (--retry_cnt)
goto retry;
rc = SCSI_DH_RETRY;
break;
}
/* fall through */
default:
sdev_printk(KERN_WARNING, sdev,
"%s: sending start_stop_unit failed, "
"sense %x/%x/%x\n", HP_SW_NAME,
sshdr.sense_key, sshdr.asc, sshdr.ascq);
rc = SCSI_DH_IO;
}
}
return rc;
} }
static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
...@@ -290,15 +205,8 @@ static int hp_sw_activate(struct scsi_device *sdev, ...@@ -290,15 +205,8 @@ static int hp_sw_activate(struct scsi_device *sdev,
ret = hp_sw_tur(sdev, h); ret = hp_sw_tur(sdev, h);
if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) { if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE)
h->retry_cnt = h->retries;
h->callback_fn = fn;
h->callback_data = data;
ret = hp_sw_start_stop(h); ret = hp_sw_start_stop(h);
if (ret == SCSI_DH_OK)
return 0;
h->callback_fn = h->callback_data = NULL;
}
if (fn) if (fn)
fn(data, ret); fn(data, ret);
......
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