From 54a4045342a8bffabde1827bfd6d86b63163111d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sat, 2 Oct 2021 18:45:49 +0300 Subject: [PATCH] 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 Signed-off-by: Adrian Hunter Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 47236ee..9f53a15 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. -- 2.7.4