diff mbox series

[1/2] scsi: ufs: Do not exit ufshcd_reset_and_restore() unless operational or dead

Message ID 20211002154550.128511-2-adrian.hunter@intel.com (mailing list archive)
State Accepted
Headers show
Series scsi: ufs: Do not exit reset of error functions unless operational | expand

Commit Message

Adrian Hunter Oct. 2, 2021, 3:45 p.m. UTC
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 checking also ufshcd_state, still allowing non-fatal errors which
are left for the error handler to deal with.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/scsi/ufs/ufshcd.c | 36 +++++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 13 deletions(-)

Comments

Avri Altman Oct. 3, 2021, 7:26 a.m. UTC | #1
> 
> 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 checking also ufshcd_state, still allowing non-fatal errors which are left
> for the error handler to deal with.
> 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Avri altman <avri.altman@wdc.com>


> ---
>  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
> 9faf02cbb9ad..16492779d3a6 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -7156,31 +7156,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.25.1
diff mbox series

Patch

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9faf02cbb9ad..16492779d3a6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7156,31 +7156,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.