[PATCH v3 2/2] scsi: ufs: core: add is_sys_suspended state before recovery
From: HOYOUNG SEO
Date: Mon Oct 26 2026 - 00:42:31 EST
If a LINERESET is reported and the hibern8 exit fails in
__ufshcd_wl_resume() during system resume, the link is recovered twice:
- the UIC error interrupt schedules eh_work, and ufshcd_err_handler()
calls ufshcd_link_recovery() because hba->pm_op_in_progress is set;
- __ufshcd_wl_resume() calls ufshcd_link_recovery() itself after the
hibern8 exit failure.
Since the early recovery path in ufshcd_err_handler() does not take
hba->host_sem, the two recoveries are not serialized and may reset the
host and the device concurrently.
During system resume, hba->host_sem is held from ufshcd_wl_suspend()
until ufshcd_wl_resume() returns, so the error handler can simply wait
for it. Skip the early link recovery when hba->is_sys_suspended is set.
Once host_sem is released, ufshcd_err_handler() decides as usual with
ufshcd_err_handling_should_stop(). With the previous patch, the errors
already recovered by the resume path are cleared, so it stops unless new
errors occurred. If the resume failed before any recovery was done, the
pending errors are still set and it runs the regular error handling. If
the recovery in the resume path failed, the HBA is in
UFSHCD_STATE_ERROR and the error handler does not retry.
The early link recovery added by commit f966e02ae521 ("scsi: ufs: core:
Fix runtime suspend error deadlock") is kept for runtime PM, where
host_sem is not held and the error handler cannot wait for the PM
operation to finish.
Signed-off-by: HOYOUNG SEO <hy50.seo@xxxxxxxxxxx>
---
drivers/ufs/core/ufshcd.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 74dfbb98129e..d085d394858f 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -7053,9 +7053,14 @@ static void ufshcd_err_handler(struct work_struct *work)
* runtime resume. This avoids potential deadlocks that could
* happen if we tried to resume the device while a PM operation
* is already in progress.
+ *
+ * During system resume, host_sem is held from
+ * ufshcd_wl_suspend() until ufshcd_wl_resume() returns, so wait
+ * for it below instead of recovering the link concurrently with
+ * the resume path.
*/
ufshcd_rpm_get_noresume(hba);
- if (hba->pm_op_in_progress) {
+ if (hba->pm_op_in_progress && !hba->is_sys_suspended) {
ufshcd_link_recovery(hba);
ufshcd_rpm_put(hba);
return;
--
2.34.1