Commit 54a40453 authored by Adrian Hunter's avatar Adrian Hunter Committed by Martin K. Petersen

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.comReviewed-by: default avatarAvri altman <avri.altman@wdc.com>
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent edc0596c
...@@ -7151,31 +7151,41 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) ...@@ -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) static int ufshcd_reset_and_restore(struct ufs_hba *hba)
{ {
u32 saved_err; u32 saved_err = 0;
u32 saved_uic_err; u32 saved_uic_err = 0;
int err = 0; int err = 0;
unsigned long flags; unsigned long flags;
int retries = MAX_HOST_RESET_RETRIES; 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); 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 { 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 */ /* Reset the attached device */
ufshcd_device_reset(hba); ufshcd_device_reset(hba);
err = ufshcd_host_reset_and_restore(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); } while (err && --retries);
spin_lock_irqsave(hba->host->host_lock, flags);
/* /*
* Inform scsi mid-layer that we did reset and allow to handle * Inform scsi mid-layer that we did reset and allow to handle
* Unit Attention properly. * Unit Attention properly.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment