All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Retry the full device init on fatal link loss
@ 2026-10-29  1:48 ` Shawn Lin
  0 siblings, 0 replies; 8+ messages in thread
From: Shawn Lin @ 2026-10-29  1:48 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen
  Cc: Bart Van Assche, Bean Huo, Heiko Stuebner, Stanley Jhu,
	Alim Akhtar, linux-rockchip, linux-scsi, Shawn Lin


On an RK3572 board the UFS device is sometimes reported dead during the
initialization at boot: DEVICE_FATAL_ERROR | UIC_LINK_LOST is latched and
the following UIC query fails with -EIO, leaving the device unusable.

  [    2.784068][    C0] ufshcd-rockchip 2a2d0000.ufs: ufshcd_check_errors: saved_err 0x880 saved_uic_err 0x0
  [    2.784112][    C0] host_regs: 00000000: 0187011f 00000000 00000200 00000000
  [    2.784125][    C0] host_regs: 00000010: 00000000 000005e6 00000000 00000000
  [    2.784137][    C0] host_regs: 00000020: 00000000 00031ef5 00000000 00000000
  [    2.784148][    C0] host_regs: 00000030: 00000008 00000001 00000000 00000000
  [    2.784159][    C0] host_regs: 00000040: 00000000 00000000 00000000 00000000
  [    2.784170][    C0] host_regs: 00000050: 02dd3000 00000001 00000000 00000000
  [    2.784182][    C0] host_regs: 00000060: 00000000 00000000 00000000 00000000
  [    2.784193][    C0] host_regs: 00000070: 02dd4000 00000001 00000000 00000000
  [    2.784204][    C0] host_regs: 00000080: 00000000 00000000 00000000 00000000
  [    2.784215][    C0] host_regs: 00000090: 00000016 00000000 00000000 00000000
  [    2.784266][   T13] ufshcd-rockchip 2a2d0000.ufs: ufshcd_err_handler started; HBA state eh_fatal; powered 1; shutting down 0; saved_err = 2176; saved_uic_err = 0; force_reset = 0
  [    2.784334][  T168] ufshcd-rockchip 2a2d0000.ufs: ufshcd_query_flag: Sending flag query for idn 1 failed, err = 5

Recover by resetting the device and the controller and redoing the whole
initialization sequence, up to three times with a 100 ms settle delay in
between. Patch 1/2 moves the initialization sequence into a new function
so that it can be retried as a unit, and patch 2/2 adds the retry loop
around its call site in ufshcd_init().


Changes in v2:
- Move the initialization sequence into a new function and retry by
  looping over its call site instead of adding more gotos to
  ufshcd_init()(Bart)
- Stop a pending error handler and clear the error state latched by the
  failed attempt, so that the retry starts from a clean state(sashiko)
- Reconfigure and re-enable MCQ after the controller re-enable, since
  the HCE toggle clears the MCQ mode setting(sashiko)

Shawn Lin (2):
  scsi: ufs: core: Move the device initialization sequence into a new
    function
  scsi: ufs: core: Retry the full device init on fatal link loss

 drivers/ufs/core/ufshcd.c | 114 +++++++++++++++++++++++++++++---------
 1 file changed, 87 insertions(+), 27 deletions(-)

-- 
2.25.1


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 0/2] Retry the full device init on fatal link loss
@ 2026-10-29  1:48 ` Shawn Lin
  0 siblings, 0 replies; 8+ messages in thread
From: Shawn Lin @ 2026-10-29  1:48 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen
  Cc: Bart Van Assche, Bean Huo, Heiko Stuebner, Stanley Jhu,
	Alim Akhtar, linux-rockchip, linux-scsi, Shawn Lin


On an RK3572 board the UFS device is sometimes reported dead during the
initialization at boot: DEVICE_FATAL_ERROR | UIC_LINK_LOST is latched and
the following UIC query fails with -EIO, leaving the device unusable.

  [    2.784068][    C0] ufshcd-rockchip 2a2d0000.ufs: ufshcd_check_errors: saved_err 0x880 saved_uic_err 0x0
  [    2.784112][    C0] host_regs: 00000000: 0187011f 00000000 00000200 00000000
  [    2.784125][    C0] host_regs: 00000010: 00000000 000005e6 00000000 00000000
  [    2.784137][    C0] host_regs: 00000020: 00000000 00031ef5 00000000 00000000
  [    2.784148][    C0] host_regs: 00000030: 00000008 00000001 00000000 00000000
  [    2.784159][    C0] host_regs: 00000040: 00000000 00000000 00000000 00000000
  [    2.784170][    C0] host_regs: 00000050: 02dd3000 00000001 00000000 00000000
  [    2.784182][    C0] host_regs: 00000060: 00000000 00000000 00000000 00000000
  [    2.784193][    C0] host_regs: 00000070: 02dd4000 00000001 00000000 00000000
  [    2.784204][    C0] host_regs: 00000080: 00000000 00000000 00000000 00000000
  [    2.784215][    C0] host_regs: 00000090: 00000016 00000000 00000000 00000000
  [    2.784266][   T13] ufshcd-rockchip 2a2d0000.ufs: ufshcd_err_handler started; HBA state eh_fatal; powered 1; shutting down 0; saved_err = 2176; saved_uic_err = 0; force_reset = 0
  [    2.784334][  T168] ufshcd-rockchip 2a2d0000.ufs: ufshcd_query_flag: Sending flag query for idn 1 failed, err = 5

Recover by resetting the device and the controller and redoing the whole
initialization sequence, up to three times with a 100 ms settle delay in
between. Patch 1/2 moves the initialization sequence into a new function
so that it can be retried as a unit, and patch 2/2 adds the retry loop
around its call site in ufshcd_init().


Changes in v2:
- Move the initialization sequence into a new function and retry by
  looping over its call site instead of adding more gotos to
  ufshcd_init()(Bart)
- Stop a pending error handler and clear the error state latched by the
  failed attempt, so that the retry starts from a clean state(sashiko)
- Reconfigure and re-enable MCQ after the controller re-enable, since
  the HCE toggle clears the MCQ mode setting(sashiko)

Shawn Lin (2):
  scsi: ufs: core: Move the device initialization sequence into a new
    function
  scsi: ufs: core: Retry the full device init on fatal link loss

 drivers/ufs/core/ufshcd.c | 114 +++++++++++++++++++++++++++++---------
 1 file changed, 87 insertions(+), 27 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/2] scsi: ufs: core: Move the device initialization sequence into a new function
  2026-10-29  1:48 ` Shawn Lin
@ 2026-10-29  1:48   ` Shawn Lin
  -1 siblings, 0 replies; 8+ messages in thread
From: Shawn Lin @ 2026-10-29  1:48 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen
  Cc: Bart Van Assche, Bean Huo, Heiko Stuebner, Stanley Jhu,
	Alim Akhtar, linux-rockchip, linux-scsi, Shawn Lin

Move the link startup and device initialization steps from ufshcd_init()
into a new function ufshcd_full_device_init(), so that the sequence can
be retried as a unit. No functional change intended.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---

(no changes since v1)

 drivers/ufs/core/ufshcd.c | 84 +++++++++++++++++++++++----------------
 1 file changed, 50 insertions(+), 34 deletions(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index ee643830a57a..f1e54d719537 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -11207,6 +11207,55 @@ static int ufshcd_add_scsi_host(struct ufs_hba *hba)
 	return err;
 }
 
+/**
+ * ufshcd_full_device_init - Link startup and full device initialization
+ * @hba: per-adapter instance
+ *
+ * Execute the whole device initialization sequence used during driver
+ * probe: link startup, MCQ configuration, device verification, device
+ * initialization completion and device parameter setup.
+ *
+ * Return: 0 upon success; < 0 upon failure.
+ */
+static int ufshcd_full_device_init(struct ufs_hba *hba)
+{
+	int err;
+
+	hba->ufshcd_state = UFSHCD_STATE_RESET;
+
+	err = ufshcd_link_startup(hba);
+	if (err)
+		return err;
+
+	if (hba->mcq_enabled)
+		ufshcd_config_mcq(hba);
+
+	if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION)
+		return 0;
+
+	/* Debug counters initialization */
+	ufshcd_clear_dbg_ufs_stats(hba);
+
+	/* UniPro link is active now */
+	ufshcd_set_link_active(hba);
+
+	/* Verify device initialization by sending NOP OUT UPIU */
+	err = ufshcd_verify_dev_init(hba);
+	if (err)
+		return err;
+
+	/* Initiate UFS initialization, and waiting until completion */
+	err = ufshcd_complete_dev_init(hba);
+	if (err)
+		return err;
+
+	err = ufshcd_device_params_init(hba);
+	if (err)
+		return err;
+
+	return ufshcd_post_device_init(hba);
+}
+
 /**
  * ufshcd_init - Driver initialization routine
  * @hba: per-adapter instance
@@ -11420,41 +11469,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 	/* Initialize hba, detect and initialize UFS device */
 	ktime_t probe_start = ktime_get();
 
-	hba->ufshcd_state = UFSHCD_STATE_RESET;
-
-	err = ufshcd_link_startup(hba);
-	if (err)
-		goto out_release;
-
-	if (hba->mcq_enabled)
-		ufshcd_config_mcq(hba);
-
-	if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION)
-		goto initialized;
-
-	/* Debug counters initialization */
-	ufshcd_clear_dbg_ufs_stats(hba);
-
-	/* UniPro link is active now */
-	ufshcd_set_link_active(hba);
-
-	/* Verify device initialization by sending NOP OUT UPIU */
-	err = ufshcd_verify_dev_init(hba);
-	if (err)
-		goto out_release;
-
-	/* Initiate UFS initialization, and waiting until completion */
-	err = ufshcd_complete_dev_init(hba);
-	if (err)
-		goto out_release;
-
-	err = ufshcd_device_params_init(hba);
-	if (err)
-		goto out_release;
-
-	err = ufshcd_post_device_init(hba);
+	err = ufshcd_full_device_init(hba);
 
-initialized:
 	ufshcd_process_probe_result(hba, probe_start, err);
 	if (err)
 		goto out_release;
-- 
2.25.1


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 1/2] scsi: ufs: core: Move the device initialization sequence into a new function
@ 2026-10-29  1:48   ` Shawn Lin
  0 siblings, 0 replies; 8+ messages in thread
From: Shawn Lin @ 2026-10-29  1:48 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen
  Cc: Bart Van Assche, Bean Huo, Heiko Stuebner, Stanley Jhu,
	Alim Akhtar, linux-rockchip, linux-scsi, Shawn Lin

Move the link startup and device initialization steps from ufshcd_init()
into a new function ufshcd_full_device_init(), so that the sequence can
be retried as a unit. No functional change intended.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---

(no changes since v1)

 drivers/ufs/core/ufshcd.c | 84 +++++++++++++++++++++++----------------
 1 file changed, 50 insertions(+), 34 deletions(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index ee643830a57a..f1e54d719537 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -11207,6 +11207,55 @@ static int ufshcd_add_scsi_host(struct ufs_hba *hba)
 	return err;
 }
 
+/**
+ * ufshcd_full_device_init - Link startup and full device initialization
+ * @hba: per-adapter instance
+ *
+ * Execute the whole device initialization sequence used during driver
+ * probe: link startup, MCQ configuration, device verification, device
+ * initialization completion and device parameter setup.
+ *
+ * Return: 0 upon success; < 0 upon failure.
+ */
+static int ufshcd_full_device_init(struct ufs_hba *hba)
+{
+	int err;
+
+	hba->ufshcd_state = UFSHCD_STATE_RESET;
+
+	err = ufshcd_link_startup(hba);
+	if (err)
+		return err;
+
+	if (hba->mcq_enabled)
+		ufshcd_config_mcq(hba);
+
+	if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION)
+		return 0;
+
+	/* Debug counters initialization */
+	ufshcd_clear_dbg_ufs_stats(hba);
+
+	/* UniPro link is active now */
+	ufshcd_set_link_active(hba);
+
+	/* Verify device initialization by sending NOP OUT UPIU */
+	err = ufshcd_verify_dev_init(hba);
+	if (err)
+		return err;
+
+	/* Initiate UFS initialization, and waiting until completion */
+	err = ufshcd_complete_dev_init(hba);
+	if (err)
+		return err;
+
+	err = ufshcd_device_params_init(hba);
+	if (err)
+		return err;
+
+	return ufshcd_post_device_init(hba);
+}
+
 /**
  * ufshcd_init - Driver initialization routine
  * @hba: per-adapter instance
@@ -11420,41 +11469,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 	/* Initialize hba, detect and initialize UFS device */
 	ktime_t probe_start = ktime_get();
 
-	hba->ufshcd_state = UFSHCD_STATE_RESET;
-
-	err = ufshcd_link_startup(hba);
-	if (err)
-		goto out_release;
-
-	if (hba->mcq_enabled)
-		ufshcd_config_mcq(hba);
-
-	if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION)
-		goto initialized;
-
-	/* Debug counters initialization */
-	ufshcd_clear_dbg_ufs_stats(hba);
-
-	/* UniPro link is active now */
-	ufshcd_set_link_active(hba);
-
-	/* Verify device initialization by sending NOP OUT UPIU */
-	err = ufshcd_verify_dev_init(hba);
-	if (err)
-		goto out_release;
-
-	/* Initiate UFS initialization, and waiting until completion */
-	err = ufshcd_complete_dev_init(hba);
-	if (err)
-		goto out_release;
-
-	err = ufshcd_device_params_init(hba);
-	if (err)
-		goto out_release;
-
-	err = ufshcd_post_device_init(hba);
+	err = ufshcd_full_device_init(hba);
 
-initialized:
 	ufshcd_process_probe_result(hba, probe_start, err);
 	if (err)
 		goto out_release;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/2] scsi: ufs: core: Retry the full device init on fatal link loss
  2026-10-29  1:48 ` Shawn Lin
@ 2026-10-29  1:48   ` Shawn Lin
  -1 siblings, 0 replies; 8+ messages in thread
From: Shawn Lin @ 2026-10-29  1:48 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen
  Cc: Bart Van Assche, Bean Huo, Heiko Stuebner, Stanley Jhu,
	Alim Akhtar, linux-rockchip, linux-scsi, Shawn Lin

On an RK3572 board the UFS device is sometimes reported dead during the
initialization at boot: DEVICE_FATAL_ERROR | UIC_LINK_LOST is latched and
the following UIC query fails with -EIO, leaving the device unusable.

Recover by resetting the device and the controller and redoing the whole
initialization sequence, up to three times with a 100 ms settle delay in
between. Doing this in ufshcd_init() rather than in the platform driver's
probe keeps the interrupt, clock and regulator resources acquired only
once, and the UFS device is already reachable through hba->priv at that
point.

Each retry stops a pending error handler and clears the error state
latched by the failed attempt, reconfigures and re-enables MCQ if the
controller reset cleared it, and restores the reset ufshcd_state, so
that no stale error context survives into the retried initialization.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>

---

Changes in v2:
- Move the initialization sequence into a new function and retry by
  looping over its call site instead of adding more gotos to
  ufshcd_init()(Bart)
- Stop a pending error handler and clear the error state latched by the
  failed attempt, so that the retry starts from a clean state(sashiko)
- Reconfigure and re-enable MCQ after the controller re-enable, since
  the HCE toggle clears the MCQ mode setting(sashiko)

 drivers/ufs/core/ufshcd.c | 46 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index f1e54d719537..bd82d6755739 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -11468,8 +11468,52 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 
 	/* Initialize hba, detect and initialize UFS device */
 	ktime_t probe_start = ktime_get();
+	int retries = 3;
 
-	err = ufshcd_full_device_init(hba);
+	while (retries--) {
+		unsigned long flags;
+
+		err = ufshcd_full_device_init(hba);
+		if (!err)
+			break;
+
+		if (!retries)
+			break;
+
+		dev_warn(hba->dev, "UFS init failed %d, full retry (%d left)\n",
+			 err, retries);
+
+		/*
+		 * The failed attempt may have latched fatal errors and
+		 * scheduled the error handler. Stop it and start the retry
+		 * from a clean state, mirroring ufshcd_reset_and_restore().
+		 */
+		cancel_work_sync(&hba->eh_work);
+		spin_lock_irqsave(hba->host->host_lock, flags);
+		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);
+
+		ufshcd_device_reset(hba);
+		ufs_put_device_desc(hba);
+		ufshcd_hba_stop(hba);
+		if (ufshcd_hba_enable(hba)) {
+			dev_err(hba->dev, "Host controller enable failed\n");
+			ufshcd_print_evt_hist(hba);
+			ufshcd_print_host_state(hba);
+			goto out_release;
+		}
+
+		/* Reconfigure MCQ upon controller re-enable */
+		if (hba->mcq_enabled) {
+			ufshcd_config_mcq(hba);
+			ufshcd_mcq_enable(hba);
+		}
+
+		msleep(100);
+	}
 
 	ufshcd_process_probe_result(hba, probe_start, err);
 	if (err)
-- 
2.25.1


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/2] scsi: ufs: core: Retry the full device init on fatal link loss
@ 2026-10-29  1:48   ` Shawn Lin
  0 siblings, 0 replies; 8+ messages in thread
From: Shawn Lin @ 2026-10-29  1:48 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen
  Cc: Bart Van Assche, Bean Huo, Heiko Stuebner, Stanley Jhu,
	Alim Akhtar, linux-rockchip, linux-scsi, Shawn Lin

On an RK3572 board the UFS device is sometimes reported dead during the
initialization at boot: DEVICE_FATAL_ERROR | UIC_LINK_LOST is latched and
the following UIC query fails with -EIO, leaving the device unusable.

Recover by resetting the device and the controller and redoing the whole
initialization sequence, up to three times with a 100 ms settle delay in
between. Doing this in ufshcd_init() rather than in the platform driver's
probe keeps the interrupt, clock and regulator resources acquired only
once, and the UFS device is already reachable through hba->priv at that
point.

Each retry stops a pending error handler and clears the error state
latched by the failed attempt, reconfigures and re-enables MCQ if the
controller reset cleared it, and restores the reset ufshcd_state, so
that no stale error context survives into the retried initialization.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>

---

Changes in v2:
- Move the initialization sequence into a new function and retry by
  looping over its call site instead of adding more gotos to
  ufshcd_init()(Bart)
- Stop a pending error handler and clear the error state latched by the
  failed attempt, so that the retry starts from a clean state(sashiko)
- Reconfigure and re-enable MCQ after the controller re-enable, since
  the HCE toggle clears the MCQ mode setting(sashiko)

 drivers/ufs/core/ufshcd.c | 46 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index f1e54d719537..bd82d6755739 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -11468,8 +11468,52 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 
 	/* Initialize hba, detect and initialize UFS device */
 	ktime_t probe_start = ktime_get();
+	int retries = 3;
 
-	err = ufshcd_full_device_init(hba);
+	while (retries--) {
+		unsigned long flags;
+
+		err = ufshcd_full_device_init(hba);
+		if (!err)
+			break;
+
+		if (!retries)
+			break;
+
+		dev_warn(hba->dev, "UFS init failed %d, full retry (%d left)\n",
+			 err, retries);
+
+		/*
+		 * The failed attempt may have latched fatal errors and
+		 * scheduled the error handler. Stop it and start the retry
+		 * from a clean state, mirroring ufshcd_reset_and_restore().
+		 */
+		cancel_work_sync(&hba->eh_work);
+		spin_lock_irqsave(hba->host->host_lock, flags);
+		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);
+
+		ufshcd_device_reset(hba);
+		ufs_put_device_desc(hba);
+		ufshcd_hba_stop(hba);
+		if (ufshcd_hba_enable(hba)) {
+			dev_err(hba->dev, "Host controller enable failed\n");
+			ufshcd_print_evt_hist(hba);
+			ufshcd_print_host_state(hba);
+			goto out_release;
+		}
+
+		/* Reconfigure MCQ upon controller re-enable */
+		if (hba->mcq_enabled) {
+			ufshcd_config_mcq(hba);
+			ufshcd_mcq_enable(hba);
+		}
+
+		msleep(100);
+	}
 
 	ufshcd_process_probe_result(hba, probe_start, err);
 	if (err)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] scsi: ufs: core: Retry the full device init on fatal link loss
  2026-10-29  1:48   ` Shawn Lin
  (?)
@ 2026-10-29  2:06   ` sashiko-bot
  2026-10-29  2:17     ` Shawn Lin
  -1 siblings, 1 reply; 8+ messages in thread
From: sashiko-bot @ 2026-10-29  2:06 UTC (permalink / raw)
  To: Shawn Lin; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] scsi: ufs: core: broken MCQ reconfiguration order in ufshcd_init() retry
- [High] scsi: ufs: error state cleared before ufshcd_hba_stop() in ufshcd_init()
- [High] scsi: ufs: core: missing ufs_hwmon_remove() and EE mask reset on init retry
- [Low] scsi: ufs: core: pass host_lock pointer to spin_lock_irqsave()
--

commit 23f03ec7ec12e66a1c4114bfb0fbd0cd5e4ff5c9
Author: Shawn Lin <shawn.lin@rock-chips.com>

scsi: ufs: core: Retry the full device init on fatal link loss

This commit retries ufshcd_full_device_init() up to three times in
ufshcd_init() when device initialization fails, resetting the device and
host controller and clearing latched error state between attempts.

> diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
> index f1e54d7195370..bd82d6755739c 100644
> --- a/drivers/ufs/core/ufshcd.c
> +++ b/drivers/ufs/core/ufshcd.c
> @@ -11468,8 +11468,52 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
>  
>  	/* Initialize hba, detect and initialize UFS device */
>  	ktime_t probe_start = ktime_get();
> +	int retries = 3;
>  
> -	err = ufshcd_full_device_init(hba);
> +	while (retries--) {
> +		unsigned long flags;
> +
> +		err = ufshcd_full_device_init(hba);
> +		if (!err)
> +			break;
> +
> +		if (!retries)
> +			break;
> +
> +		dev_warn(hba->dev, "UFS init failed %d, full retry (%d left)\n",
> +			 err, retries);
> +
> +		/*
> +		 * The failed attempt may have latched fatal errors and
> +		 * scheduled the error handler. Stop it and start the retry
> +		 * from a clean state, mirroring ufshcd_reset_and_restore().
> +		 */
> +		cancel_work_sync(&hba->eh_work);
> +		spin_lock_irqsave(hba->host->host_lock, flags);
> +		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);

[Severity: Low]
In include/scsi/scsi_host.h, host_lock in struct Scsi_Host is defined by
value rather than as a pointer:

	spinlock_t		host_lock;

Should spin_lock_irqsave() and spin_unlock_irqrestore() in ufshcd_init()
take &hba->host->host_lock instead of hba->host->host_lock so that
drivers/ufs/core/ufshcd.c compiles?

> +
> +		ufshcd_device_reset(hba);
> +		ufs_put_device_desc(hba);
> +		ufshcd_hba_stop(hba);

[Severity: High]
What happens if an error or link-loss interrupt fires while the host
controller is still active during ufshcd_device_reset(), before
ufshcd_hba_stop() disables the controller?

Because cancel_work_sync(&hba->eh_work) and the clearing of hba->saved_err,
hba->saved_uic_err, and hba->ufshcd_state happen before ufshcd_hba_stop(),
resetting the attached device while controller interrupts are enabled can
trigger ufshcd_intr() -> ufshcd_check_errors():

	hba->saved_err |= hba->errors;
	hba->saved_uic_err |= hba->uic_error;
	...
	ufshcd_schedule_eh_work(hba);

Since hba->ufs_device_wlun is not set yet and hba->host_sem is not held
during ufshcd_init(), ufshcd_err_handler() can then run concurrently on
hba->eh_wq:

	down(&hba->host_sem);
	spin_lock_irqsave(&hba->host->host_lock, flags);
	if (ufshcd_err_handling_should_stop(hba)) {
		if (hba->ufshcd_state != UFSHCD_STATE_ERROR)
			hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
		spin_unlock_irqrestore(&hba->host->host_lock, flags);
		up(&hba->host_sem);
		return;
	}

Could this overwrite hba->ufshcd_state and leave hba->saved_err and
hba->saved_uic_err latched during the retry? Should ufshcd_hba_stop(hba) be
called before cancelling hba->eh_work, clearing the error state, and
resetting the device?

[Severity: High]
Can this retry path also leak the hwmon device and struct ufs_hwmon_data if
ufshcd_full_device_init() fails in ufshcd_post_device_init() after
ufshcd_device_params_init() has already succeeded?

During ufshcd_full_device_init(), the call chain is:

	ufshcd_device_params_init()
	  ufs_get_device_desc()
	    ufshcd_temp_notif_probe()
	      ufshcd_enable_ee(hba, mask);
	      ufs_hwmon_probe(hba, mask);
	ufshcd_post_device_init()
	  ufshcd_config_pwr_mode()

If ufshcd_post_device_init() fails, ufs_put_device_desc() only frees
dev_info->model and dev_info->device_id. On the next iteration,
ufs_hwmon_probe() in drivers/ufs/core/ufs-hwmon.c allocates a new
struct ufs_hwmon_data, registers a second hwmon device, and overwrites
hba->hwmon_device:

	data = kzalloc_obj(*data);
	if (!data)
		return;
	...
	hwmon = hwmon_device_register_with_info(dev, "ufs", data, &ufs_hwmon_hba_info, NULL);
	...
	hba->hwmon_device = hwmon;

In addition, hba->ee_ctrl_mask and hba->ee_drv_mask retain the bits set by
ufshcd_enable_ee() before ufshcd_device_reset() reset the device, which
causes ufshcd_update_ee_control() on the next attempt to see an unchanged
mask and skip writing the exception event control attribute to the device.
Should the retry cleanup call ufs_hwmon_remove(hba) and clear the exception
event masks?

> +		if (ufshcd_hba_enable(hba)) {
> +			dev_err(hba->dev, "Host controller enable failed\n");
> +			ufshcd_print_evt_hist(hba);
> +			ufshcd_print_host_state(hba);
> +			goto out_release;
> +		}
> +
> +		/* Reconfigure MCQ upon controller re-enable */
> +		if (hba->mcq_enabled) {
> +			ufshcd_config_mcq(hba);
> +			ufshcd_mcq_enable(hba);
> +		}

[Severity: High]
Is the ordering of ufshcd_config_mcq(hba) and ufshcd_mcq_enable(hba) here
intended?

On the initial probe path, ufshcd_add_scsi_host() calls ufshcd_mcq_enable()
first, and ufshcd_full_device_init() calls ufshcd_config_mcq() only after
ufshcd_link_startup() completes:

	err = ufshcd_link_startup(hba);
	if (err)
		return err;

	if (hba->mcq_enabled)
		ufshcd_config_mcq(hba);

In the retry path of ufshcd_init(), calling ufshcd_config_mcq(hba) before
ufshcd_mcq_enable(hba) configures the queues and enables them in
ufshcd_mcq_make_queues_operational() before ufshcd_mcq_enable() selects
multi-circular queue mode in REG_UFS_MEM_CFG and before the next attempt's
ufshcd_link_startup(hba). Then, when ufshcd_full_device_init() runs on the
next iteration, it calls ufshcd_config_mcq(hba) a second time while the
hardware queues are already enabled.

Furthermore, if ufshcd_link_startup() encounters an error on its own retry
and calls ufshcd_hba_enable(hba), the controller reset will clear
REG_UFS_MEM_CFG again without ufshcd_mcq_enable(hba) being re-applied before
ufshcd_config_mcq(hba). Should the retry path only call
ufshcd_mcq_enable(hba) (or should ufshcd_mcq_enable(hba) be called right
before ufshcd_config_mcq(hba) inside ufshcd_full_device_init())?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261029014839.3390579-1-shawn.lin@rock-chips.com?part=2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] scsi: ufs: core: Retry the full device init on fatal link loss
  2026-10-29  2:06   ` sashiko-bot
@ 2026-10-29  2:17     ` Shawn Lin
  0 siblings, 0 replies; 8+ messages in thread
From: Shawn Lin @ 2026-10-29  2:17 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: shawn.lin, linux-scsi

在 2026/10/29 星期四 10:06, sashiko-bot@kernel.org 写道:
> Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
> - [High] scsi: ufs: core: broken MCQ reconfiguration order in ufshcd_init() retry
> - [High] scsi: ufs: error state cleared before ufshcd_hba_stop() in ufshcd_init()
> - [High] scsi: ufs: core: missing ufs_hwmon_remove() and EE mask reset on init retry
> - [Low] scsi: ufs: core: pass host_lock pointer to spin_lock_irqsave()
> --

...

> 
> [Severity: High]
> What happens if an error or link-loss interrupt fires while the host
> controller is still active during ufshcd_device_reset(), before
> ufshcd_hba_stop() disables the controller?
> 
> Because cancel_work_sync(&hba->eh_work) and the clearing of hba->saved_err,
> hba->saved_uic_err, and hba->ufshcd_state happen before ufshcd_hba_stop(),
> resetting the attached device while controller interrupts are enabled can
> trigger ufshcd_intr() -> ufshcd_check_errors():
> 
> 	hba->saved_err |= hba->errors;
> 	hba->saved_uic_err |= hba->uic_error;
> 	...
> 	ufshcd_schedule_eh_work(hba);
> 
> Since hba->ufs_device_wlun is not set yet and hba->host_sem is not held
> during ufshcd_init(), ufshcd_err_handler() can then run concurrently on
> hba->eh_wq:
> 
> 	down(&hba->host_sem);
> 	spin_lock_irqsave(&hba->host->host_lock, flags);
> 	if (ufshcd_err_handling_should_stop(hba)) {
> 		if (hba->ufshcd_state != UFSHCD_STATE_ERROR)
> 			hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
> 		spin_unlock_irqrestore(&hba->host->host_lock, flags);
> 		up(&hba->host_sem);
> 		return;
> 	}
> 
> Could this overwrite hba->ufshcd_state and leave hba->saved_err and
> hba->saved_uic_err latched during the retry? Should ufshcd_hba_stop(hba) be
> called before cancelling hba->eh_work, clearing the error state, and
> resetting the device?

It's a valid concern, will fix it in v3.

> 
> [Severity: High]
> Can this retry path also leak the hwmon device and struct ufs_hwmon_data if
> ufshcd_full_device_init() fails in ufshcd_post_device_init() after
> ufshcd_device_params_init() has already succeeded?
> 
> During ufshcd_full_device_init(), the call chain is:
> 
> 	ufshcd_device_params_init()
> 	  ufs_get_device_desc()
> 	    ufshcd_temp_notif_probe()
> 	      ufshcd_enable_ee(hba, mask);
> 	      ufs_hwmon_probe(hba, mask);
> 	ufshcd_post_device_init()
> 	  ufshcd_config_pwr_mode()
> 
> If ufshcd_post_device_init() fails, ufs_put_device_desc() only frees
> dev_info->model and dev_info->device_id. On the next iteration,
> ufs_hwmon_probe() in drivers/ufs/core/ufs-hwmon.c allocates a new
> struct ufs_hwmon_data, registers a second hwmon device, and overwrites
> hba->hwmon_device:
> 
> 	data = kzalloc_obj(*data);
> 	if (!data)
> 		return;
> 	...
> 	hwmon = hwmon_device_register_with_info(dev, "ufs", data, &ufs_hwmon_hba_info, NULL);
> 	...
> 	hba->hwmon_device = hwmon;
> 
> In addition, hba->ee_ctrl_mask and hba->ee_drv_mask retain the bits set by
> ufshcd_enable_ee() before ufshcd_device_reset() reset the device, which
> causes ufshcd_update_ee_control() on the next attempt to see an unchanged
> mask and skip writing the exception event control attribute to the device.
> Should the retry cleanup call ufs_hwmon_remove(hba) and clear the exception
> event masks?

Ack.

> 
>> +		if (ufshcd_hba_enable(hba)) {
>> +			dev_err(hba->dev, "Host controller enable failed\n");
>> +			ufshcd_print_evt_hist(hba);
>> +			ufshcd_print_host_state(hba);
>> +			goto out_release;
>> +		}
>> +
>> +		/* Reconfigure MCQ upon controller re-enable */
>> +		if (hba->mcq_enabled) {
>> +			ufshcd_config_mcq(hba);
>> +			ufshcd_mcq_enable(hba);
>> +		}
> 
> [Severity: High]
> Is the ordering of ufshcd_config_mcq(hba) and ufshcd_mcq_enable(hba) here
> intended?
> 
> On the initial probe path, ufshcd_add_scsi_host() calls ufshcd_mcq_enable()
> first, and ufshcd_full_device_init() calls ufshcd_config_mcq() only after
> ufshcd_link_startup() completes:
> 
> 	err = ufshcd_link_startup(hba);
> 	if (err)
> 		return err;
> 
> 	if (hba->mcq_enabled)
> 		ufshcd_config_mcq(hba);
> 
> In the retry path of ufshcd_init(), calling ufshcd_config_mcq(hba) before
> ufshcd_mcq_enable(hba) configures the queues and enables them in
> ufshcd_mcq_make_queues_operational() before ufshcd_mcq_enable() selects
> multi-circular queue mode in REG_UFS_MEM_CFG and before the next attempt's
> ufshcd_link_startup(hba). Then, when ufshcd_full_device_init() runs on the
> next iteration, it calls ufshcd_config_mcq(hba) a second time while the
> hardware queues are already enabled.
> 
> Furthermore, if ufshcd_link_startup() encounters an error on its own retry
> and calls ufshcd_hba_enable(hba), the controller reset will clear
> REG_UFS_MEM_CFG again without ufshcd_mcq_enable(hba) being re-applied before
> ufshcd_config_mcq(hba). Should the retry path only call
> ufshcd_mcq_enable(hba) (or should ufshcd_mcq_enable(hba) be called right
> before ufshcd_config_mcq(hba) inside ufshcd_full_device_init())?

My platform doesn't support MCQ, so actually I cannot test
this path. Will look into it.

> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-10-29  2:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-29  1:48 [PATCH v2 0/2] Retry the full device init on fatal link loss Shawn Lin
2026-10-29  1:48 ` Shawn Lin
2026-10-29  1:48 ` [PATCH v2 1/2] scsi: ufs: core: Move the device initialization sequence into a new function Shawn Lin
2026-10-29  1:48   ` Shawn Lin
2026-10-29  1:48 ` [PATCH v2 2/2] scsi: ufs: core: Retry the full device init on fatal link loss Shawn Lin
2026-10-29  1:48   ` Shawn Lin
2026-10-29  2:06   ` sashiko-bot
2026-10-29  2:17     ` Shawn Lin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.