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: Hannes Reinecke <hare@suse.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
b78205c932
commit
80e1836cf9
|
@ -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 *);
|
||||||
*
|
*
|
||||||
* 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 @@ done:
|
||||||
*/
|
*/
|
||||||
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 @@ done:
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
|
struct scsi_device *sdev = h->sdev;
|
||||||
|
int res, rc = SCSI_DH_OK;
|
||||||
|
int retry_cnt = HP_SW_RETRIES;
|
||||||
|
u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
|
||||||
|
REQ_FAILFAST_DRIVER;
|
||||||
|
|
||||||
req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
|
retry:
|
||||||
if (IS_ERR(req))
|
res = scsi_execute_req_flags(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
|
||||||
return SCSI_DH_RES_TEMP_UNAVAIL;
|
HP_SW_TIMEOUT, HP_SW_RETRIES,
|
||||||
|
NULL, req_flags, 0);
|
||||||
blk_rq_set_block_pc(req);
|
if (res) {
|
||||||
req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
|
if (!scsi_sense_valid(&sshdr)) {
|
||||||
REQ_FAILFAST_DRIVER;
|
sdev_printk(KERN_WARNING, sdev,
|
||||||
req->cmd_len = COMMAND_SIZE(START_STOP);
|
"%s: sending start_stop_unit failed, "
|
||||||
req->cmd[0] = START_STOP;
|
"no sense available\n", HP_SW_NAME);
|
||||||
req->cmd[4] = 1; /* Start spin cycle */
|
return SCSI_DH_IO;
|
||||||
req->timeout = HP_SW_TIMEOUT;
|
}
|
||||||
req->sense = h->sense;
|
switch (sshdr.sense_key) {
|
||||||
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
case NOT_READY:
|
||||||
req->sense_len = 0;
|
if (sshdr.asc == 0x04 && sshdr.ascq == 3) {
|
||||||
req->end_io_data = h;
|
/*
|
||||||
|
* LUN not ready - manual intervention required
|
||||||
blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio);
|
*
|
||||||
return SCSI_DH_OK;
|
* 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,
|
||||||
|
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue