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>
This commit is contained in:
Adrian Hunter 2021-10-02 18:45:49 +03:00 committed by Martin K. Petersen
parent edc0596cc0
commit 54a4045342

View File

@ -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.