summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ufs
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2021-10-02 18:45:49 +0300
committerMartin K. Petersen <martin.petersen@oracle.com>2021-10-04 22:20:38 -0400
commit54a4045342a8bffabde1827bfd6d86b63163111d (patch)
tree8836fa69593da49e64e2e0862b9ba4cc69c70250 /drivers/scsi/ufs
parentedc0596cc04bf0ac3a69c66e994d3ff8b650ff71 (diff)
downloadlinux-stable-54a4045342a8bffabde1827bfd6d86b63163111d.tar.gz
linux-stable-54a4045342a8bffabde1827bfd6d86b63163111d.tar.bz2
linux-stable-54a4045342a8bffabde1827bfd6d86b63163111d.zip
scsi: ufs: core: Do not exit ufshcd_reset_and_restore() unless operational or dead
Callers of ufshcd_reset_and_restore() expect it to return in an operational state. However, the code only checks direct errors and so the ufshcd_state may not be UFSHCD_STATE_OPERATIONAL due to error interrupts. Fix by also checking ufshcd_state, still allowing non-fatal errors which are left for the error handler to deal with. Link: https://lore.kernel.org/r/20211002154550.128511-2-adrian.hunter@intel.com Reviewed-by: Avri altman <avri.altman@wdc.com> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/ufs')
-rw-r--r--drivers/scsi/ufs/ufshcd.c36
1 files changed, 23 insertions, 13 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 47236ee93a0e..9f53a154cde5 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7151,31 +7151,41 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
*/
static int ufshcd_reset_and_restore(struct ufs_hba *hba)
{
- u32 saved_err;
- u32 saved_uic_err;
+ u32 saved_err = 0;
+ u32 saved_uic_err = 0;
int err = 0;
unsigned long flags;
int retries = MAX_HOST_RESET_RETRIES;
- /*
- * This is a fresh start, cache and clear saved error first,
- * in case new error generated during reset and restore.
- */
spin_lock_irqsave(hba->host->host_lock, flags);
- saved_err = hba->saved_err;
- saved_uic_err = hba->saved_uic_err;
- hba->saved_err = 0;
- hba->saved_uic_err = 0;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
-
do {
+ /*
+ * This is a fresh start, cache and clear saved error first,
+ * in case new error generated during reset and restore.
+ */
+ saved_err |= hba->saved_err;
+ saved_uic_err |= hba->saved_uic_err;
+ hba->saved_err = 0;
+ hba->saved_uic_err = 0;
+ hba->force_reset = false;
+ hba->ufshcd_state = UFSHCD_STATE_RESET;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
/* Reset the attached device */
ufshcd_device_reset(hba);
err = ufshcd_host_reset_and_restore(hba);
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (err)
+ continue;
+ /* Do not exit unless operational or dead */
+ if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL &&
+ hba->ufshcd_state != UFSHCD_STATE_ERROR &&
+ hba->ufshcd_state != UFSHCD_STATE_EH_SCHEDULED_NON_FATAL)
+ err = -EAGAIN;
} while (err && --retries);
- spin_lock_irqsave(hba->host->host_lock, flags);
/*
* Inform scsi mid-layer that we did reset and allow to handle
* Unit Attention properly.