scsi: core: Move scsi_host_busy() out of host lock if it is for per-command
[platform/kernel/linux-starfive.git] / drivers / scsi / scsi_error.c
index 3ec8bfd..43eff11 100644 (file)
@@ -61,11 +61,11 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
 static enum scsi_disposition scsi_try_to_abort_cmd(const struct scsi_host_template *,
                                                   struct scsi_cmnd *);
 
-void scsi_eh_wakeup(struct Scsi_Host *shost)
+void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy)
 {
        lockdep_assert_held(shost->host_lock);
 
-       if (scsi_host_busy(shost) == shost->host_failed) {
+       if (busy == shost->host_failed) {
                trace_scsi_eh_wakeup(shost);
                wake_up_process(shost->ehandler);
                SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost,
@@ -88,7 +88,7 @@ void scsi_schedule_eh(struct Scsi_Host *shost)
        if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 ||
            scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) {
                shost->host_eh_scheduled++;
-               scsi_eh_wakeup(shost);
+               scsi_eh_wakeup(shost, scsi_host_busy(shost));
        }
 
        spin_unlock_irqrestore(shost->host_lock, flags);
@@ -282,11 +282,12 @@ static void scsi_eh_inc_host_failed(struct rcu_head *head)
 {
        struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu);
        struct Scsi_Host *shost = scmd->device->host;
+       unsigned int busy = scsi_host_busy(shost);
        unsigned long flags;
 
        spin_lock_irqsave(shost->host_lock, flags);
        shost->host_failed++;
-       scsi_eh_wakeup(shost);
+       scsi_eh_wakeup(shost, busy);
        spin_unlock_irqrestore(shost->host_lock, flags);
 }
 
@@ -536,6 +537,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 +597,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 +709,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 +811,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;
@@ -1119,6 +1153,7 @@ retry:
 
        scsi_log_send(scmd);
        scmd->submitter = SUBMITTED_BY_SCSI_ERROR_HANDLER;
+       scmd->flags |= SCMD_LAST;
 
        /*
         * Lock sdev->state_mutex to avoid that scsi_device_quiesce() can
@@ -1807,6 +1842,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 +2005,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;
@@ -2150,22 +2197,26 @@ void scsi_eh_flush_done_q(struct list_head *done_q)
        struct scsi_cmnd *scmd, *next;
 
        list_for_each_entry_safe(scmd, next, done_q, eh_entry) {
+               struct scsi_device *sdev = scmd->device;
+
                list_del_init(&scmd->eh_entry);
-               if (scsi_device_online(scmd->device) &&
-                   !scsi_noretry_cmd(scmd) && scsi_cmd_retry_allowed(scmd) &&
-                       scsi_eh_should_retry_cmd(scmd)) {
+               if (scsi_device_online(sdev) && !scsi_noretry_cmd(scmd) &&
+                   scsi_cmd_retry_allowed(scmd) &&
+                   scsi_eh_should_retry_cmd(scmd)) {
                        SCSI_LOG_ERROR_RECOVERY(3,
                                scmd_printk(KERN_INFO, scmd,
                                             "%s: flush retry cmd\n",
                                             current->comm));
                                scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
+                               blk_mq_kick_requeue_list(sdev->request_queue);
                } else {
                        /*
                         * If just we got sense for the device (called
                         * scsi_eh_get_sense), scmd->result is already
                         * set, do not set DID_TIME_OUT.
                         */
-                       if (!scmd->result)
+                       if (!scmd->result &&
+                           !(scmd->flags & SCMD_FORCE_EH_SUCCESS))
                                scmd->result |= (DID_TIME_OUT << 16);
                        SCSI_LOG_ERROR_RECOVERY(3,
                                scmd_printk(KERN_INFO, scmd,
@@ -2413,6 +2464,7 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
        scsi_init_command(dev, scmd);
 
        scmd->submitter = SUBMITTED_BY_SCSI_RESET_IOCTL;
+       scmd->flags |= SCMD_LAST;
        memset(&scmd->sdb, 0, sizeof(scmd->sdb));
 
        scmd->cmd_len                   = 0;