[PATCH v2 2/2] scsi: ufs: core: Retry the full device init on fatal link loss
Shawn Lin
shawn.lin at rock-chips.com
Wed Oct 28 18:48:39 PDT 2026
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 at 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
More information about the Linux-rockchip
mailing list