@@ -1671,6 +1671,66 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
return;
}
+/**
+ * scsi_zbc_noretry_cmd - Determine if ZBC device command can be retried
+ * @scmd: Failed cmd to check
+ *
+ * Test the error condition of a failed ZBC device command to determine cases
+ * that are known to be not worth retrying.
+ * If the specified command is not intended for a ZBC device, do nothing.
+ */
+bool scsi_zbc_noretry_cmd(struct scsi_cmnd *scmd)
+{
+ struct request *rq = scmd->request;
+ struct scsi_sense_hdr sshdr;
+
+ /*
+ * The request queue zone model may not be set when this is called
+ * during device probe/revalidation. In that case, just fall back to
+ * default behavior and let the caller decide what to do with failures.
+ */
+ if (!blk_queue_is_zoned(rq->q))
+ return false;
+
+ if (!scsi_command_normalize_sense(scmd, &sshdr))
+ /* no valid sense data, don't know, so maybe retry */
+ return false;
+
+ if (sshdr.sense_key != ILLEGAL_REQUEST)
+ return false;
+
+ switch (req_op(rq)) {
+ case REQ_OP_ZONE_RESET:
+
+ if (sshdr.asc == 0x24) {
+ /*
+ * INVALID FIELD IN CDB error: reset of a conventional
+ * zone was attempted. Nothing to worry about, so be
+ * quiet about the error.
+ */
+ if (!blk_rq_is_passthrough(rq))
+ rq->rq_flags |= RQF_QUIET;
+ return true;
+ }
+ return false;
+
+ case REQ_OP_WRITE:
+ case REQ_OP_WRITE_ZEROES:
+ case REQ_OP_WRITE_SAME:
+
+ /*
+ * INVALID ADDRESS FOR WRITE error: It is unlikely that
+ * retrying write requests failed with any kind of
+ * alignement error will result in success. So don't.
+ */
+ return sshdr.asc == 0x21;
+
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_GPL(scsi_zbc_noretry_cmd);
+
/**
* scsi_noretry_cmd - determine if command should be failed fast
* @scmd: SCSI cmd to examine.
@@ -1699,6 +1759,12 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd)
return 0;
check_type:
+ /*
+ * For ZBC, do not retry conditions that will only fail again.
+ */
+ if (scmd->device->type == TYPE_ZBC &&
+ scsi_zbc_noretry_cmd(scmd))
+ return 1;
/*
* assume caller has checked sense and determined
* the check condition was retryable.
@@ -2041,7 +2041,7 @@ static int sd_done(struct scsi_cmnd *SCpnt)
out:
if (sd_is_zoned(sdkp))
- sd_zbc_complete(SCpnt, good_bytes, &sshdr);
+ sd_zbc_complete(SCpnt, good_bytes);
SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,
"sd_done: completed %d of %d bytes\n",
@@ -284,8 +284,7 @@ extern void sd_zbc_remove(struct scsi_disk *sdkp);
extern void sd_zbc_print_zones(struct scsi_disk *sdkp);
extern int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd);
extern int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd);
-extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
- struct scsi_sense_hdr *sshdr);
+extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes);
#else /* CONFIG_BLK_DEV_ZONED */
@@ -310,8 +309,9 @@ static inline int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd)
}
static inline void sd_zbc_complete(struct scsi_cmnd *cmd,
- unsigned int good_bytes,
- struct scsi_sense_hdr *sshdr) {}
+ unsigned int good_bytes)
+{
+}
#endif /* CONFIG_BLK_DEV_ZONED */
@@ -271,53 +271,16 @@ int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd)
* sd_zbc_complete - ZBC command post processing.
* @cmd: Completed command
* @good_bytes: Command reply bytes
- * @sshdr: command sense header
*
- * Called from sd_done(). Process report zones reply and handle reset zone
- * and write commands errors.
+ * Called from sd_done(). Process report zones reply.
*/
-void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
- struct scsi_sense_hdr *sshdr)
+void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes)
{
- int result = cmd->result;
struct request *rq = cmd->request;
- switch (req_op(rq)) {
- case REQ_OP_ZONE_RESET:
-
- if (result &&
- sshdr->sense_key == ILLEGAL_REQUEST &&
- sshdr->asc == 0x24)
- /*
- * INVALID FIELD IN CDB error: reset of a conventional
- * zone was attempted. Nothing to worry about, so be
- * quiet about the error.
- */
- rq->rq_flags |= RQF_QUIET;
- break;
-
- case REQ_OP_WRITE:
- case REQ_OP_WRITE_ZEROES:
- case REQ_OP_WRITE_SAME:
-
- if (result &&
- sshdr->sense_key == ILLEGAL_REQUEST &&
- sshdr->asc == 0x21)
- /*
- * INVALID ADDRESS FOR WRITE error: It is unlikely that
- * retrying write requests failed with any kind of
- * alignement error will result in success. So don't.
- */
- cmd->allowed = 0;
- break;
-
- case REQ_OP_ZONE_REPORT:
-
- if (!result)
- sd_zbc_report_zones_complete(cmd, good_bytes);
- break;
-
- }
+ if (req_op(rq) == REQ_OP_ZONE_REPORT &&
+ !cmd->result)
+ sd_zbc_report_zones_complete(cmd, good_bytes);
}
/**
@@ -18,6 +18,7 @@ extern int scsi_block_when_processing_errors(struct scsi_device *);
extern bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
struct scsi_sense_hdr *sshdr);
extern int scsi_check_sense(struct scsi_cmnd *);
+extern bool scsi_zbc_noretry_cmd(struct scsi_cmnd *);
static inline bool scsi_sense_is_deferred(const struct scsi_sense_hdr *sshdr)
{
For ZBC/ZAC devices, retrying a command with a condition known to lead to a failure is useless. One example is an unaligned write past the write pointer of a sequential zone. Retrying the same command will result in an error again. Currently, these iknown error condition cases are handled in sd_zbc.c using the sd_zbc_complete() function which is called from sd_done() when a command completes. However, these known error conditions are not handled in libata, nor is scsi_noretry_cmd() considering them. Fix this by introducing the function scsi_zbc_noretry_cmd() and use this function in scsi_noretry_cmd(). This allows simplifying sd_zbc_complete() which now only has to deal with report zones command reply. scsi_zbc_noretry_cmd() is also exported so that it can be used from libata. Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> --- drivers/scsi/scsi_error.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/sd.c | 2 +- drivers/scsi/sd.h | 8 +++--- drivers/scsi/sd_zbc.c | 47 ++++----------------------------- include/scsi/scsi_eh.h | 1 + 5 files changed, 77 insertions(+), 47 deletions(-)