@@ -536,6 +536,7 @@ static inline void set_scsi_ml_byte(struct scsi_cmnd *cmd, u8 status)
*/
enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
{
+ struct request *req = scsi_cmd_to_rq(scmd);
struct scsi_device *sdev = scmd->device;
struct scsi_sense_hdr sshdr;
@@ -595,6 +596,22 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
if (sshdr.asc == 0x10) /* DIF */
return SUCCESS;
+ /*
+ * Check aborts due to command duration limit policy:
+ * ABORTED COMMAND additional sense code with the
+ * COMMAND TIMEOUT BEFORE PROCESSING or
+ * COMMAND TIMEOUT DURING PROCESSING or
+ * COMMAND TIMEOUT DURING PROCESSING DUE TO ERROR RECOVERY
+ * additional sense code qualifiers.
+ */
+ if (sshdr.asc == 0x2e &&
+ sshdr.ascq >= 0x01 && sshdr.ascq <= 0x03) {
+ set_scsi_ml_byte(scmd, SCSIML_STAT_DL_TIMEOUT);
+ req->cmd_flags |= REQ_FAILFAST_DEV;
+ req->rq_flags |= RQF_QUIET;
+ return SUCCESS;
+ }
+
if (sshdr.asc == 0x44 && sdev->sdev_bflags & BLIST_RETRY_ITF)
return ADD_TO_MLQUEUE;
if (sshdr.asc == 0xc1 && sshdr.ascq == 0x01 &&
@@ -691,6 +708,14 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
}
return SUCCESS;
+ case COMPLETED:
+ if (sshdr.asc == 0x55 && sshdr.ascq == 0x0a) {
+ set_scsi_ml_byte(scmd, SCSIML_STAT_DL_TIMEOUT);
+ req->cmd_flags |= REQ_FAILFAST_DEV;
+ req->rq_flags |= RQF_QUIET;
+ }
+ return SUCCESS;
+
default:
return SUCCESS;
}
@@ -785,6 +810,14 @@ static enum scsi_disposition scsi_eh_completed_normally(struct scsi_cmnd *scmd)
switch (get_status_byte(scmd)) {
case SAM_STAT_GOOD:
scsi_handle_queue_ramp_up(scmd->device);
+ if (scmd->sense_buffer && SCSI_SENSE_VALID(scmd))
+ /*
+ * If we have sense data, call scsi_check_sense() in
+ * order to set the correct SCSI ML byte (if any).
+ * No point in checking the return value, since the
+ * command has already completed successfully.
+ */
+ scsi_check_sense(scmd);
fallthrough;
case SAM_STAT_COMMAND_TERMINATED:
return SUCCESS;
@@ -1807,6 +1840,10 @@ bool scsi_noretry_cmd(struct scsi_cmnd *scmd)
return !!(req->cmd_flags & REQ_FAILFAST_DRIVER);
}
+ /* Never retry commands aborted due to a duration limit timeout */
+ if (scsi_ml_byte(scmd->result) == SCSIML_STAT_DL_TIMEOUT)
+ return true;
+
if (!scsi_status_is_check_condition(scmd->result))
return false;
@@ -1966,6 +2003,14 @@ enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *scmd)
if (scmd->cmnd[0] == REPORT_LUNS)
scmd->device->sdev_target->expecting_lun_change = 0;
scsi_handle_queue_ramp_up(scmd->device);
+ if (scmd->sense_buffer && SCSI_SENSE_VALID(scmd))
+ /*
+ * If we have sense data, call scsi_check_sense() in
+ * order to set the correct SCSI ML byte (if any).
+ * No point in checking the return value, since the
+ * command has already completed successfully.
+ */
+ scsi_check_sense(scmd);
fallthrough;
case SAM_STAT_COMMAND_TERMINATED:
return SUCCESS;
@@ -601,6 +601,8 @@ static blk_status_t scsi_result_to_blk_status(int result)
return BLK_STS_MEDIUM;
case SCSIML_STAT_TGT_FAILURE:
return BLK_STS_TARGET;
+ case SCSIML_STAT_DL_TIMEOUT:
+ return BLK_STS_DURATION_LIMIT;
}
switch (host_byte(result)) {
@@ -798,6 +800,8 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
blk_stat = BLK_STS_ZONE_OPEN_RESOURCE;
}
break;
+ case COMPLETED:
+ fallthrough;
default:
action = ACTION_FAIL;
break;
@@ -27,6 +27,7 @@ enum scsi_ml_status {
SCSIML_STAT_NOSPC = 0x02, /* Space allocation on the dev failed */
SCSIML_STAT_MED_ERROR = 0x03, /* Medium error */
SCSIML_STAT_TGT_FAILURE = 0x04, /* Permanent target failure */
+ SCSIML_STAT_DL_TIMEOUT = 0x05, /* Command Duration Limit timeout */
};
static inline u8 scsi_ml_byte(int result)