Merge patch series "scsi: sshdr and retry fixes"
Mike Christie <michael.christie@oracle.com> says: The following patches were made over Linus tree (Martin's 6.7 branch was missing some changes to sd.c). They only contain the sshdr and rdac retry fixes from the "Allow scsi_execute users to control retries" patchset. The patches in this set are reviewed and tested but the changes to how we do retries will take a little longer and require more testing, so I broke up the series to make them easier to review. Link: https://lore.kernel.org/r/20231004210013.5601-1-michael.christie@oracle.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
@@ -82,7 +82,7 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
|
|||||||
{
|
{
|
||||||
unsigned char cmd[6] = { TEST_UNIT_READY };
|
unsigned char cmd[6] = { TEST_UNIT_READY };
|
||||||
struct scsi_sense_hdr sshdr;
|
struct scsi_sense_hdr sshdr;
|
||||||
int ret = SCSI_DH_OK, res;
|
int ret, res;
|
||||||
blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
|
blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
|
||||||
REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
|
REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
|
||||||
const struct scsi_exec_args exec_args = {
|
const struct scsi_exec_args exec_args = {
|
||||||
@@ -92,19 +92,18 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
|
|||||||
retry:
|
retry:
|
||||||
res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT,
|
res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT,
|
||||||
HP_SW_RETRIES, &exec_args);
|
HP_SW_RETRIES, &exec_args);
|
||||||
if (res) {
|
if (res > 0 && scsi_sense_valid(&sshdr)) {
|
||||||
if (scsi_sense_valid(&sshdr))
|
ret = tur_done(sdev, h, &sshdr);
|
||||||
ret = tur_done(sdev, h, &sshdr);
|
} else if (res == 0) {
|
||||||
else {
|
|
||||||
sdev_printk(KERN_WARNING, sdev,
|
|
||||||
"%s: sending tur failed with %x\n",
|
|
||||||
HP_SW_NAME, res);
|
|
||||||
ret = SCSI_DH_IO;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
h->path_state = HP_SW_PATH_ACTIVE;
|
h->path_state = HP_SW_PATH_ACTIVE;
|
||||||
ret = SCSI_DH_OK;
|
ret = SCSI_DH_OK;
|
||||||
|
} else {
|
||||||
|
sdev_printk(KERN_WARNING, sdev,
|
||||||
|
"%s: sending tur failed with %x\n",
|
||||||
|
HP_SW_NAME, res);
|
||||||
|
ret = SCSI_DH_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == SCSI_DH_IMM_RETRY)
|
if (ret == SCSI_DH_IMM_RETRY)
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
@@ -122,7 +121,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
|
|||||||
unsigned char cmd[6] = { START_STOP, 0, 0, 0, 1, 0 };
|
unsigned char cmd[6] = { START_STOP, 0, 0, 0, 1, 0 };
|
||||||
struct scsi_sense_hdr sshdr;
|
struct scsi_sense_hdr sshdr;
|
||||||
struct scsi_device *sdev = h->sdev;
|
struct scsi_device *sdev = h->sdev;
|
||||||
int res, rc = SCSI_DH_OK;
|
int res, rc;
|
||||||
int retry_cnt = HP_SW_RETRIES;
|
int retry_cnt = HP_SW_RETRIES;
|
||||||
blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
|
blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
|
||||||
REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
|
REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
|
||||||
@@ -133,35 +132,37 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
|
|||||||
retry:
|
retry:
|
||||||
res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT,
|
res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT,
|
||||||
HP_SW_RETRIES, &exec_args);
|
HP_SW_RETRIES, &exec_args);
|
||||||
if (res) {
|
if (!res) {
|
||||||
if (!scsi_sense_valid(&sshdr)) {
|
return SCSI_DH_OK;
|
||||||
sdev_printk(KERN_WARNING, sdev,
|
} else if (res < 0 || !scsi_sense_valid(&sshdr)) {
|
||||||
"%s: sending start_stop_unit failed, "
|
sdev_printk(KERN_WARNING, sdev,
|
||||||
"no sense available\n", HP_SW_NAME);
|
"%s: sending start_stop_unit failed, "
|
||||||
return SCSI_DH_IO;
|
"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;
|
|
||||||
}
|
|
||||||
fallthrough;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
fallthrough;
|
||||||
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -530,7 +530,7 @@ static void send_mode_select(struct work_struct *work)
|
|||||||
container_of(work, struct rdac_controller, ms_work);
|
container_of(work, struct rdac_controller, ms_work);
|
||||||
struct scsi_device *sdev = ctlr->ms_sdev;
|
struct scsi_device *sdev = ctlr->ms_sdev;
|
||||||
struct rdac_dh_data *h = sdev->handler_data;
|
struct rdac_dh_data *h = sdev->handler_data;
|
||||||
int err = SCSI_DH_OK, retry_cnt = RDAC_RETRY_COUNT;
|
int rc, err, retry_cnt = RDAC_RETRY_COUNT;
|
||||||
struct rdac_queue_data *tmp, *qdata;
|
struct rdac_queue_data *tmp, *qdata;
|
||||||
LIST_HEAD(list);
|
LIST_HEAD(list);
|
||||||
unsigned char cdb[MAX_COMMAND_SIZE];
|
unsigned char cdb[MAX_COMMAND_SIZE];
|
||||||
@@ -558,20 +558,23 @@ static void send_mode_select(struct work_struct *work)
|
|||||||
(char *) h->ctlr->array_name, h->ctlr->index,
|
(char *) h->ctlr->array_name, h->ctlr->index,
|
||||||
(retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying");
|
(retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying");
|
||||||
|
|
||||||
if (scsi_execute_cmd(sdev, cdb, opf, &h->ctlr->mode_select, data_size,
|
rc = scsi_execute_cmd(sdev, cdb, opf, &h->ctlr->mode_select, data_size,
|
||||||
RDAC_TIMEOUT * HZ, RDAC_RETRIES, &exec_args)) {
|
RDAC_TIMEOUT * HZ, RDAC_RETRIES, &exec_args);
|
||||||
|
if (!rc) {
|
||||||
|
h->state = RDAC_STATE_ACTIVE;
|
||||||
|
RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
|
||||||
|
"MODE_SELECT completed",
|
||||||
|
(char *) h->ctlr->array_name, h->ctlr->index);
|
||||||
|
err = SCSI_DH_OK;
|
||||||
|
} else if (rc < 0) {
|
||||||
|
err = SCSI_DH_IO;
|
||||||
|
} else {
|
||||||
err = mode_select_handle_sense(sdev, &sshdr);
|
err = mode_select_handle_sense(sdev, &sshdr);
|
||||||
if (err == SCSI_DH_RETRY && retry_cnt--)
|
if (err == SCSI_DH_RETRY && retry_cnt--)
|
||||||
goto retry;
|
goto retry;
|
||||||
if (err == SCSI_DH_IMM_RETRY)
|
if (err == SCSI_DH_IMM_RETRY)
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
if (err == SCSI_DH_OK) {
|
|
||||||
h->state = RDAC_STATE_ACTIVE;
|
|
||||||
RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
|
|
||||||
"MODE_SELECT completed",
|
|
||||||
(char *) h->ctlr->array_name, h->ctlr->index);
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry_safe(qdata, tmp, &list, entry) {
|
list_for_each_entry_safe(qdata, tmp, &list, entry) {
|
||||||
list_del(&qdata->entry);
|
list_del(&qdata->entry);
|
||||||
|
@@ -692,7 +692,7 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable)
|
|||||||
ret = scsi_mode_select(sdev, 1, 0, buf_data, len, 5 * HZ, 3,
|
ret = scsi_mode_select(sdev, 1, 0, buf_data, len, 5 * HZ, 3,
|
||||||
&data, &sshdr);
|
&data, &sshdr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (scsi_sense_valid(&sshdr))
|
if (ret > 0 && scsi_sense_valid(&sshdr))
|
||||||
scsi_print_sense_hdr(sdev,
|
scsi_print_sense_hdr(sdev,
|
||||||
dev_name(&sdev->sdev_gendev), &sshdr);
|
dev_name(&sdev->sdev_gendev), &sshdr);
|
||||||
return ret;
|
return ret;
|
||||||
|
@@ -2299,10 +2299,10 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
|
|||||||
do {
|
do {
|
||||||
result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, NULL, 0,
|
result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, NULL, 0,
|
||||||
timeout, 1, &exec_args);
|
timeout, 1, &exec_args);
|
||||||
if (sdev->removable && scsi_sense_valid(sshdr) &&
|
if (sdev->removable && result > 0 && scsi_sense_valid(sshdr) &&
|
||||||
sshdr->sense_key == UNIT_ATTENTION)
|
sshdr->sense_key == UNIT_ATTENTION)
|
||||||
sdev->changed = 1;
|
sdev->changed = 1;
|
||||||
} while (scsi_sense_valid(sshdr) &&
|
} while (result > 0 && scsi_sense_valid(sshdr) &&
|
||||||
sshdr->sense_key == UNIT_ATTENTION && --retries);
|
sshdr->sense_key == UNIT_ATTENTION && --retries);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@@ -676,10 +676,10 @@ spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer,
|
|||||||
for (r = 0; r < retries; r++) {
|
for (r = 0; r < retries; r++) {
|
||||||
result = spi_execute(sdev, spi_write_buffer, REQ_OP_DRV_OUT,
|
result = spi_execute(sdev, spi_write_buffer, REQ_OP_DRV_OUT,
|
||||||
buffer, len, &sshdr);
|
buffer, len, &sshdr);
|
||||||
if(result || !scsi_device_online(sdev)) {
|
if (result || !scsi_device_online(sdev)) {
|
||||||
|
|
||||||
scsi_device_set_state(sdev, SDEV_QUIESCE);
|
scsi_device_set_state(sdev, SDEV_QUIESCE);
|
||||||
if (scsi_sense_valid(&sshdr)
|
if (result > 0 && scsi_sense_valid(&sshdr)
|
||||||
&& sshdr.sense_key == ILLEGAL_REQUEST
|
&& sshdr.sense_key == ILLEGAL_REQUEST
|
||||||
/* INVALID FIELD IN CDB */
|
/* INVALID FIELD IN CDB */
|
||||||
&& sshdr.asc == 0x24 && sshdr.ascq == 0x00)
|
&& sshdr.asc == 0x24 && sshdr.ascq == 0x00)
|
||||||
|
@@ -143,7 +143,7 @@ cache_type_store(struct device *dev, struct device_attribute *attr,
|
|||||||
struct scsi_mode_data data;
|
struct scsi_mode_data data;
|
||||||
struct scsi_sense_hdr sshdr;
|
struct scsi_sense_hdr sshdr;
|
||||||
static const char temp[] = "temporary ";
|
static const char temp[] = "temporary ";
|
||||||
int len;
|
int len, ret;
|
||||||
|
|
||||||
if (sdp->type != TYPE_DISK && sdp->type != TYPE_ZBC)
|
if (sdp->type != TYPE_DISK && sdp->type != TYPE_ZBC)
|
||||||
/* no cache control on RBC devices; theoretically they
|
/* no cache control on RBC devices; theoretically they
|
||||||
@@ -190,9 +190,10 @@ cache_type_store(struct device *dev, struct device_attribute *attr,
|
|||||||
*/
|
*/
|
||||||
data.device_specific = 0;
|
data.device_specific = 0;
|
||||||
|
|
||||||
if (scsi_mode_select(sdp, 1, sp, buffer_data, len, SD_TIMEOUT,
|
ret = scsi_mode_select(sdp, 1, sp, buffer_data, len, SD_TIMEOUT,
|
||||||
sdkp->max_retries, &data, &sshdr)) {
|
sdkp->max_retries, &data, &sshdr);
|
||||||
if (scsi_sense_valid(&sshdr))
|
if (ret) {
|
||||||
|
if (ret > 0 && scsi_sense_valid(&sshdr))
|
||||||
sd_print_sense_hdr(sdkp, &sshdr);
|
sd_print_sense_hdr(sdkp, &sshdr);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -2180,19 +2181,21 @@ sd_spinup_disk(struct scsi_disk *sdkp)
|
|||||||
sdkp->max_retries,
|
sdkp->max_retries,
|
||||||
&exec_args);
|
&exec_args);
|
||||||
|
|
||||||
/*
|
if (the_result > 0) {
|
||||||
* If the drive has indicated to us that it
|
/*
|
||||||
* doesn't have any media in it, don't bother
|
* If the drive has indicated to us that it
|
||||||
* with any more polling.
|
* doesn't have any media in it, don't bother
|
||||||
*/
|
* with any more polling.
|
||||||
if (media_not_present(sdkp, &sshdr)) {
|
*/
|
||||||
if (media_was_present)
|
if (media_not_present(sdkp, &sshdr)) {
|
||||||
sd_printk(KERN_NOTICE, sdkp, "Media removed, stopped polling\n");
|
if (media_was_present)
|
||||||
return;
|
sd_printk(KERN_NOTICE, sdkp,
|
||||||
}
|
"Media removed, stopped polling\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (the_result)
|
|
||||||
sense_valid = scsi_sense_valid(&sshdr);
|
sense_valid = scsi_sense_valid(&sshdr);
|
||||||
|
}
|
||||||
retries++;
|
retries++;
|
||||||
} while (retries < 3 &&
|
} while (retries < 3 &&
|
||||||
(!scsi_status_is_good(the_result) ||
|
(!scsi_status_is_good(the_result) ||
|
||||||
@@ -2388,11 +2391,10 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
|
|||||||
the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN,
|
the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN,
|
||||||
buffer, RC16_LEN, SD_TIMEOUT,
|
buffer, RC16_LEN, SD_TIMEOUT,
|
||||||
sdkp->max_retries, &exec_args);
|
sdkp->max_retries, &exec_args);
|
||||||
|
|
||||||
if (media_not_present(sdkp, &sshdr))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (the_result > 0) {
|
if (the_result > 0) {
|
||||||
|
if (media_not_present(sdkp, &sshdr))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
sense_valid = scsi_sense_valid(&sshdr);
|
sense_valid = scsi_sense_valid(&sshdr);
|
||||||
if (sense_valid &&
|
if (sense_valid &&
|
||||||
sshdr.sense_key == ILLEGAL_REQUEST &&
|
sshdr.sense_key == ILLEGAL_REQUEST &&
|
||||||
@@ -2889,7 +2891,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bad_sense:
|
bad_sense:
|
||||||
if (scsi_sense_valid(&sshdr) &&
|
if (res == -EIO && scsi_sense_valid(&sshdr) &&
|
||||||
sshdr.sense_key == ILLEGAL_REQUEST &&
|
sshdr.sense_key == ILLEGAL_REQUEST &&
|
||||||
sshdr.asc == 0x24 && sshdr.ascq == 0x0)
|
sshdr.asc == 0x24 && sshdr.ascq == 0x0)
|
||||||
/* Invalid field in CDB */
|
/* Invalid field in CDB */
|
||||||
@@ -2937,7 +2939,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
|
|||||||
sd_first_printk(KERN_WARNING, sdkp,
|
sd_first_printk(KERN_WARNING, sdkp,
|
||||||
"getting Control mode page failed, assume no ATO\n");
|
"getting Control mode page failed, assume no ATO\n");
|
||||||
|
|
||||||
if (scsi_sense_valid(&sshdr))
|
if (res == -EIO && scsi_sense_valid(&sshdr))
|
||||||
sd_print_sense_hdr(sdkp, &sshdr);
|
sd_print_sense_hdr(sdkp, &sshdr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@@ -177,7 +177,8 @@ static unsigned int sr_get_events(struct scsi_device *sdev)
|
|||||||
|
|
||||||
result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buf, sizeof(buf),
|
result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buf, sizeof(buf),
|
||||||
SR_TIMEOUT, MAX_RETRIES, &exec_args);
|
SR_TIMEOUT, MAX_RETRIES, &exec_args);
|
||||||
if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION)
|
if (result > 0 && scsi_sense_valid(&sshdr) &&
|
||||||
|
sshdr.sense_key == UNIT_ATTENTION)
|
||||||
return DISK_EVENT_MEDIA_CHANGE;
|
return DISK_EVENT_MEDIA_CHANGE;
|
||||||
|
|
||||||
if (result || be16_to_cpu(eh->data_len) < sizeof(*med))
|
if (result || be16_to_cpu(eh->data_len) < sizeof(*med))
|
||||||
|
Reference in New Issue
Block a user