* [PATCH v10 1/4] scsi: ufs: core: Clear saved errors in ufshcd_link_recovery()
[not found] ` <CGME20261111082304epcas2p4887d72756d51a72b94729439d25dd3e8@epcas2p4.samsung.com>
@ 2026-11-11 8:18 ` HOYOUNG SEO
0 siblings, 0 replies; 6+ messages in thread
From: HOYOUNG SEO @ 2026-11-11 8:18 UTC (permalink / raw)
To: linux-scsi, linux-kernel, bvanassche, mkp, martin.petersen,
stanleyjhu, peter.wang, alim.akhtar, kwangwon.min, kwmad.kim,
cpgsproxy1, h10.kim
Cc: HOYOUNG SEO, Bean Huo
ufshcd_link_recovery() resets both the device and the host and then
re-establishes the link. Unlike ufshcd_reset_and_restore(), however, it
does not clear hba->saved_err, hba->saved_uic_err and hba->force_reset,
so the errors latched before the recovery remain pending after the link
has already been recovered.
When ufshcd_err_handler() runs afterwards,
ufshcd_err_handling_should_stop() sees these stale errors. The error
handler then quiesces all queues and, depending on the latched errors
(e.g. a fatal error or UFSHCD_UIC_DL_PA_INIT_ERROR), performs another
full ufshcd_reset_and_restore() on a link that is already operational.
Cache and clear the saved errors before the reset, as
ufshcd_reset_and_restore() does, so that only errors raised during or
after the recovery are left to the error handler. Put them back if the
recovery fails.
Fixes: 35dabf4503b9 ("scsi: ufs: core: Use link recovery when h8 exit fails during runtime resume")
Signed-off-by: HOYOUNG SEO <hy50.seo@samsung.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Reviewed-by: Bean Huo <beanhuo@micron.com>
---
drivers/ufs/core/ufshcd.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index fd52deb72d21..3b5580ac390c 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -4695,10 +4695,20 @@ EXPORT_SYMBOL_GPL(ufshcd_uic_change_pwr_mode);
int ufshcd_link_recovery(struct ufs_hba *hba)
{
+ u32 saved_err, saved_uic_err;
int ret;
unsigned long flags;
spin_lock_irqsave(&hba->host->host_lock, flags);
+ /*
+ * The errors saved so far are handled by this full reset, so cache and
+ * clear them first, in case new errors are generated during recovery.
+ */
+ 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;
ufshcd_set_eh_in_progress(hba);
spin_unlock_irqrestore(&hba->host->host_lock, flags);
@@ -4709,8 +4719,11 @@ int ufshcd_link_recovery(struct ufs_hba *hba)
ret = ufshcd_host_reset_and_restore(hba);
spin_lock_irqsave(&hba->host->host_lock, flags);
- if (ret)
+ if (ret) {
hba->ufshcd_state = UFSHCD_STATE_ERROR;
+ hba->saved_err |= saved_err;
+ hba->saved_uic_err |= saved_uic_err;
+ }
ufshcd_clear_eh_in_progress(hba);
spin_unlock_irqrestore(&hba->host->host_lock, flags);
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v10 2/4] scsi: ufs: core: Add a helper for the system suspend callbacks
[not found] ` <CGME20261111082305epcas2p28dd4b104523c10c82457a29e7e89c56c@epcas2p2.samsung.com>
@ 2026-11-11 8:18 ` HOYOUNG SEO
2026-11-11 12:50 ` Peter Wang
0 siblings, 1 reply; 6+ messages in thread
From: HOYOUNG SEO @ 2026-11-11 8:18 UTC (permalink / raw)
To: linux-scsi, linux-kernel, bvanassche, mkp, martin.petersen,
stanleyjhu, peter.wang, alim.akhtar, kwangwon.min, kwmad.kim,
cpgsproxy1, h10.kim
Cc: HOYOUNG SEO
Move the body of ufshcd_wl_suspend() into ufshcd_wl_system_suspend(),
which takes the PM operation as a parameter, so that it can be shared
with ufshcd_wl_poweroff() in the next patch. ufshcd_wl_suspend() calls it
with UFS_SYSTEM_PM.
No functional change, except that the error message printed when the
suspend fails now contains the name of the new function.
Suggested-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: HOYOUNG SEO <hy50.seo@samsung.com>
---
drivers/ufs/core/ufshcd.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 3b5580ac390c..4825349e87fd 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -10712,7 +10712,7 @@ static int ufshcd_wl_runtime_resume(struct device *dev)
#endif
#ifdef CONFIG_PM_SLEEP
-static int ufshcd_wl_suspend(struct device *dev)
+static int ufshcd_wl_system_suspend(struct device *dev, enum ufs_pm_op pm_op)
{
struct scsi_device *sdev = to_scsi_device(dev);
struct ufs_hba *hba;
@@ -10725,7 +10725,7 @@ static int ufshcd_wl_suspend(struct device *dev)
if (pm_runtime_suspended(dev))
goto out;
- ret = __ufshcd_wl_suspend(hba, UFS_SYSTEM_PM);
+ ret = __ufshcd_wl_suspend(hba, pm_op);
if (ret) {
dev_err(&sdev->sdev_gendev, "%s failed: %d\n", __func__, ret);
up(&hba->host_sem);
@@ -10741,6 +10741,11 @@ static int ufshcd_wl_suspend(struct device *dev)
return ret;
}
+static int ufshcd_wl_suspend(struct device *dev)
+{
+ return ufshcd_wl_system_suspend(dev, UFS_SYSTEM_PM);
+}
+
static int ufshcd_wl_resume(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v10 3/4] scsi: ufs: core: Make ufshcd_wl_poweroff() behave like ufshcd_wl_suspend()
[not found] ` <CGME20261111082306epcas2p21456a0a7d81ed5328ec01f022b87ee32@epcas2p2.samsung.com>
@ 2026-11-11 8:18 ` HOYOUNG SEO
2026-11-11 12:50 ` Peter Wang
0 siblings, 1 reply; 6+ messages in thread
From: HOYOUNG SEO @ 2026-11-11 8:18 UTC (permalink / raw)
To: linux-scsi, linux-kernel, bvanassche, mkp, martin.petersen,
stanleyjhu, peter.wang, alim.akhtar, kwangwon.min, kwmad.kim,
cpgsproxy1, h10.kim
Cc: HOYOUNG SEO
ufshcd_wl_poweroff(), the hibernation poweroff callback, calls
__ufshcd_wl_suspend(hba, UFS_SHUTDOWN_PM) directly and ignores the
result. Unlike ufshcd_wl_suspend() it:
- does not take hba->host_sem. An error handler that runs in the
meantime can reset the link concurrently with __ufshcd_wl_suspend().
It also leaves host_sem unbalanced: if hibernation is aborted after
ufshcd_wl_poweroff() has been called, ufshcd_wl_resume() is called as
the .restore callback and releases host_sem, which was not acquired;
- does not check pm_runtime_suspended(dev). __ufshcd_suspend_prepare()
leaves the WLUN runtime suspended if ufshcd_rpm_ok_for_spm() is true,
which is the case if rpm_lvl and spm_lvl are equal. Then
__ufshcd_wl_suspend() triggers error recovery and returns -EBUSY;
- does not set hba->is_sys_suspended, so ufshcd_err_handling_prepare()
does not restore the clocks and regulators if the .restore callback
fails;
- ignores errors.
Call ufshcd_wl_system_suspend() with UFS_SHUTDOWN_PM from
ufshcd_wl_poweroff() to fix all of these, as suggested by Bart Van
Assche. host_sem is held until ufshcd_wl_resume() releases it if
hibernation is aborted, and released if the suspend fails. For
UFS_SHUTDOWN_PM, __ufshcd_wl_suspend() does not convert failures into
-EBUSY, so a positive SCSI or UIC status can be returned. A dev_pm_ops
callback has to return a negative error code, so convert it.
This changes the behavior of ufshcd_wl_poweroff(): an error is now
returned from the .poweroff callback, which aborts hibernation, instead
of being ignored, and a runtime suspended WLUN is left as it is like in
ufshcd_wl_suspend().
Do not use hba->shutting_down to stop the error handler: it makes
ufs_mtk_system_suspend(), which is also the .poweroff callback of the
MediaTek host controller, fail with -EBUSY, and nothing clears it when
hibernation is aborted.
Fixes: b294ff3e3449 ("scsi: ufs: core: Enable power management for wlun")
Suggested-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: HOYOUNG SEO <hy50.seo@samsung.com>
---
drivers/ufs/core/ufshcd.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 4825349e87fd..8aea99f5c364 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -10729,6 +10729,9 @@ static int ufshcd_wl_system_suspend(struct device *dev, enum ufs_pm_op pm_op)
if (ret) {
dev_err(&sdev->sdev_gendev, "%s failed: %d\n", __func__, ret);
up(&hba->host_sem);
+ /* __ufshcd_wl_suspend() can return a positive status for UFS_SHUTDOWN_PM. */
+ if (ret > 0)
+ ret = -EBUSY;
}
out:
@@ -11576,11 +11579,7 @@ EXPORT_SYMBOL_GPL(ufshcd_suspend_prepare);
#ifdef CONFIG_PM_SLEEP
static int ufshcd_wl_poweroff(struct device *dev)
{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct ufs_hba *hba = shost_priv(sdev->host);
-
- __ufshcd_wl_suspend(hba, UFS_SHUTDOWN_PM);
- return 0;
+ return ufshcd_wl_system_suspend(dev, UFS_SHUTDOWN_PM);
}
#endif
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v10 4/4] scsi: ufs: core: Limit early link recovery in the error handler to runtime PM
[not found] ` <CGME20261111082307epcas2p3b1376d94048de0aa228515860e892641@epcas2p3.samsung.com>
@ 2026-11-11 8:18 ` HOYOUNG SEO
0 siblings, 0 replies; 6+ messages in thread
From: HOYOUNG SEO @ 2026-11-11 8:18 UTC (permalink / raw)
To: linux-scsi, linux-kernel, bvanassche, mkp, martin.petersen,
stanleyjhu, peter.wang, alim.akhtar, kwangwon.min, kwmad.kim,
cpgsproxy1, h10.kim
Cc: HOYOUNG SEO
ufshcd_err_handler() recovers the link without taking hba->host_sem
whenever hba->pm_op_in_progress is set. That early path was added by
commit f966e02ae521 ("scsi: ufs: core: Fix runtime suspend error
deadlock") because the regular error handling would wait for a runtime
PM operation that cannot complete while the error handler is waiting.
pm_op_in_progress is also set during system suspend, system resume,
shutdown and poweroff, where the early path is not needed and runs
concurrently with the PM path itself. For example, if a LINERESET is
reported and the hibern8 exit fails in __ufshcd_wl_resume() during
system resume, both ufshcd_err_handler() and __ufshcd_wl_resume() call
ufshcd_link_recovery(), and the host and the device may be reset at the
same time.
Only take the early path while pm_op_in_progress is set and a runtime
suspend or resume of the WLUN is in progress. The runtime PM core sets
the runtime status of the WLUN to RPM_SUSPENDING or RPM_RESUMING while
ufshcd_wl_runtime_suspend() or ufshcd_wl_runtime_resume() runs, and it
is RPM_ACTIVE or RPM_SUSPENDED during system PM. The runtime status
alone is not enough: it also covers the block layer steps before and
after the driver callbacks, where the early link recovery must not run.
pm_op_in_progress is only set while __ufshcd_wl_suspend() or
__ufshcd_wl_resume() run, which is inside that window.
Both checks are done in the new function ufshcd_in_wl_rpm_callback().
The runtime status is only available with CONFIG_PM, so the function
returns false without it. Both values are read without locking, so use
READ_ONCE() for them and WRITE_ONCE() when pm_op_in_progress is
updated. As the window of pm_op_in_progress is contained in the runtime
PM window, a stale value of either one can only make the error handler
take the regular path, like an error handler that starts just before or
after the PM operation.
For the other PM operations the regular error handling is safe:
- the system PM callbacks hold host_sem from ufshcd_wl_suspend() until
ufshcd_wl_resume() returns, and ufshcd_wl_poweroff() holds it as
well, so the error handler waits for them;
- during shutdown, hba->shutting_down makes the error handler stop.
This changes the behavior during shutdown: errors that occur while the
final START STOP UNIT command is being processed are no longer handled
by the error handler. Recovery then only happens through
ufshcd_eh_timed_out().
Fixes: e23ef4f22db3 ("scsi: ufs: core: Fix error handler host_sem issue")
Signed-off-by: HOYOUNG SEO <hy50.seo@samsung.com>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
---
drivers/ufs/core/ufshcd.c | 32 +++++++++++++++++++++++++++-----
1 file changed, 27 insertions(+), 5 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 8aea99f5c364..09c8095141e2 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -7062,6 +7062,23 @@ static bool ufshcd_abort_all(struct ufs_hba *hba)
return ret != 0;
}
+/*
+ * Whether a runtime PM callback of the WLUN runs __ufshcd_wl_suspend() or
+ * __ufshcd_wl_resume().
+ */
+static bool ufshcd_in_wl_rpm_callback(struct ufs_hba *hba)
+{
+#ifdef CONFIG_PM
+ enum rpm_status status =
+ READ_ONCE(hba->ufs_device_wlun->sdev_gendev.power.runtime_status);
+
+ return READ_ONCE(hba->pm_op_in_progress) &&
+ (status == RPM_SUSPENDING || status == RPM_RESUMING);
+#else
+ return false;
+#endif
+}
+
/**
* ufshcd_err_handler - handle UFS errors that require s/w attention
* @work: pointer to work structure
@@ -7091,9 +7108,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.
+ *
+ * Do this only while the PM callbacks run for a runtime PM
+ * operation. The system PM and poweroff callbacks hold
+ * host_sem, and shutting_down makes the regular path below
+ * stop, so it does not reset the link concurrently with them.
*/
ufshcd_rpm_get_noresume(hba);
- if (hba->pm_op_in_progress) {
+ if (ufshcd_in_wl_rpm_callback(hba)) {
ufshcd_link_recovery(hba);
ufshcd_rpm_put(hba);
return;
@@ -10392,7 +10414,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
enum ufs_dev_pwr_mode req_dev_pwr_mode;
enum uic_link_state req_link_state;
- hba->pm_op_in_progress = true;
+ WRITE_ONCE(hba->pm_op_in_progress, true);
if (pm_op != UFS_SHUTDOWN_PM) {
pm_lvl = pm_op == UFS_RUNTIME_PM ?
hba->rpm_lvl : hba->spm_lvl;
@@ -10565,7 +10587,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
hba->clk_gating.is_suspended = false;
ufshcd_release(hba);
}
- hba->pm_op_in_progress = false;
+ WRITE_ONCE(hba->pm_op_in_progress, false);
return ret;
}
@@ -10575,7 +10597,7 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
int ret;
enum uic_link_state old_link_state = hba->uic_link_state;
- hba->pm_op_in_progress = true;
+ WRITE_ONCE(hba->pm_op_in_progress, true);
/*
* Call vendor specific resume callback. As these callbacks may access
@@ -10666,7 +10688,7 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
ufshcd_update_evt_hist(hba, UFS_EVT_WL_RES_ERR, (u32)ret);
hba->clk_gating.is_suspended = false;
ufshcd_release(hba);
- hba->pm_op_in_progress = false;
+ WRITE_ONCE(hba->pm_op_in_progress, false);
return ret;
}
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v10 2/4] scsi: ufs: core: Add a helper for the system suspend callbacks
2026-11-11 8:18 ` [PATCH v10 2/4] scsi: ufs: core: Add a helper for the system suspend callbacks HOYOUNG SEO
@ 2026-11-11 12:50 ` Peter Wang
0 siblings, 0 replies; 6+ messages in thread
From: Peter Wang @ 2026-11-11 12:50 UTC (permalink / raw)
To: HOYOUNG SEO, linux-scsi, linux-kernel, bvanassche, mkp,
martin.petersen, stanleyjhu, alim.akhtar, kwangwon.min,
kwmad.kim, cpgsproxy1, h10.kim
On Wed, 2026-11-11 at 17:18 +0900, HOYOUNG SEO wrote:
> Move the body of ufshcd_wl_suspend() into ufshcd_wl_system_suspend(),
> which takes the PM operation as a parameter, so that it can be shared
> with ufshcd_wl_poweroff() in the next patch. ufshcd_wl_suspend()
> calls it
> with UFS_SYSTEM_PM.
>
> No functional change, except that the error message printed when the
> suspend fails now contains the name of the new function.
>
> Suggested-by: Bart Van Assche <bvanassche@acm.org>
> Signed-off-by: HOYOUNG SEO <hy50.seo@samsung.com>
> ---
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v10 3/4] scsi: ufs: core: Make ufshcd_wl_poweroff() behave like ufshcd_wl_suspend()
2026-11-11 8:18 ` [PATCH v10 3/4] scsi: ufs: core: Make ufshcd_wl_poweroff() behave like ufshcd_wl_suspend() HOYOUNG SEO
@ 2026-11-11 12:50 ` Peter Wang
0 siblings, 0 replies; 6+ messages in thread
From: Peter Wang @ 2026-11-11 12:50 UTC (permalink / raw)
To: HOYOUNG SEO, linux-scsi, linux-kernel, bvanassche, mkp,
martin.petersen, stanleyjhu, alim.akhtar, kwangwon.min,
kwmad.kim, cpgsproxy1, h10.kim
On Wed, 2026-11-11 at 17:18 +0900, HOYOUNG SEO wrote:
> ufshcd_wl_poweroff(), the hibernation poweroff callback, calls
> __ufshcd_wl_suspend(hba, UFS_SHUTDOWN_PM) directly and ignores the
> result. Unlike ufshcd_wl_suspend() it:
>
> - does not take hba->host_sem. An error handler that runs in the
> meantime can reset the link concurrently with
> __ufshcd_wl_suspend().
> It also leaves host_sem unbalanced: if hibernation is aborted
> after
> ufshcd_wl_poweroff() has been called, ufshcd_wl_resume() is called
> as
> the .restore callback and releases host_sem, which was not
> acquired;
> - does not check pm_runtime_suspended(dev).
> __ufshcd_suspend_prepare()
> leaves the WLUN runtime suspended if ufshcd_rpm_ok_for_spm() is
> true,
> which is the case if rpm_lvl and spm_lvl are equal. Then
> __ufshcd_wl_suspend() triggers error recovery and returns -EBUSY;
> - does not set hba->is_sys_suspended, so
> ufshcd_err_handling_prepare()
> does not restore the clocks and regulators if the .restore
> callback
> fails;
> - ignores errors.
>
> Call ufshcd_wl_system_suspend() with UFS_SHUTDOWN_PM from
> ufshcd_wl_poweroff() to fix all of these, as suggested by Bart Van
> Assche. host_sem is held until ufshcd_wl_resume() releases it if
> hibernation is aborted, and released if the suspend fails. For
> UFS_SHUTDOWN_PM, __ufshcd_wl_suspend() does not convert failures into
> -EBUSY, so a positive SCSI or UIC status can be returned. A
> dev_pm_ops
> callback has to return a negative error code, so convert it.
>
> This changes the behavior of ufshcd_wl_poweroff(): an error is now
> returned from the .poweroff callback, which aborts hibernation,
> instead
> of being ignored, and a runtime suspended WLUN is left as it is like
> in
> ufshcd_wl_suspend().
>
> Do not use hba->shutting_down to stop the error handler: it makes
> ufs_mtk_system_suspend(), which is also the .poweroff callback of the
> MediaTek host controller, fail with -EBUSY, and nothing clears it
> when
> hibernation is aborted.
>
> Fixes: b294ff3e3449 ("scsi: ufs: core: Enable power management for
> wlun")
> Suggested-by: Bart Van Assche <bvanassche@acm.org>
> Signed-off-by: HOYOUNG SEO <hy50.seo@samsung.com>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-11 12:50 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <cover.1794384665.git.hy50.seo@samsung.com>
[not found] ` <CGME20261111082304epcas2p4887d72756d51a72b94729439d25dd3e8@epcas2p4.samsung.com>
2026-11-11 8:18 ` [PATCH v10 1/4] scsi: ufs: core: Clear saved errors in ufshcd_link_recovery() HOYOUNG SEO
[not found] ` <CGME20261111082305epcas2p28dd4b104523c10c82457a29e7e89c56c@epcas2p2.samsung.com>
2026-11-11 8:18 ` [PATCH v10 2/4] scsi: ufs: core: Add a helper for the system suspend callbacks HOYOUNG SEO
2026-11-11 12:50 ` Peter Wang
[not found] ` <CGME20261111082306epcas2p21456a0a7d81ed5328ec01f022b87ee32@epcas2p2.samsung.com>
2026-11-11 8:18 ` [PATCH v10 3/4] scsi: ufs: core: Make ufshcd_wl_poweroff() behave like ufshcd_wl_suspend() HOYOUNG SEO
2026-11-11 12:50 ` Peter Wang
[not found] ` <CGME20261111082307epcas2p3b1376d94048de0aa228515860e892641@epcas2p3.samsung.com>
2026-11-11 8:18 ` [PATCH v10 4/4] scsi: ufs: core: Limit early link recovery in the error handler to runtime PM HOYOUNG SEO
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®