Linux SCSI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Stanley Jhu" <stanleyjhu@google.com>
Cc: linux-scsi@vger.kernel.org
Subject: Re: [PATCH 2/2] scsi: ufs: core: Wake consumer queues on suspended W-LUN recovery
Date: Thu, 05 Nov 2026 07:43:05 +0000	[thread overview]
Message-ID: <sashiko-outbox-198693@kernel.org> (raw)
In-Reply-To: <20261105071518.1458428-3-stanleyjhu@google.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] scsi: ufs: core: premature HBA runtime suspend in ufshcd_recover_pm_error()
- [High] scsi: ufs: core: missed queue wake in ufshcd_recover_pm_error() after prepare
--

commit ea7f240ee0c25a5e5c4a46de9b52655deaa5da4e
Author: Stanley Jhu <stanleyjhu@google.com>

scsi: ufs: core: Wake consumer queues on suspended W-LUN recovery

This commit updates ufshcd_recover_pm_error() to set resume_sdev_queues
when ufs_device_wlun is runtime-suspended, so consumer queues blocked in
__bio_queue_enter() after a failed W-LUN runtime resume are woken via
pm_request_resume().

> diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
> index fd52deb72d21c..0701ec408736d 100644
> --- a/drivers/ufs/core/ufshcd.c
> +++ b/drivers/ufs/core/ufshcd.c
> @@ -6953,7 +6953,9 @@ static void ufshcd_recover_pm_error(struct ufs_hba *hba)
>  		resume_sdev_queues = true;
>  	}
>  
> -	if (hba->ufs_device_wlun->sdev_gendev.power.runtime_error) {
> +	if (pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev)) {
> +		resume_sdev_queues = true;

[Severity: High]
Can leaving ufs_device_wlun in RPM_SUSPENDED here cause hba->dev to
prematurely runtime-suspend before the asynchronous consumer resume work runs?

When W-LUN runtime resume fails, rpm_resume() leaves ufs_device_wlun in
RPM_SUSPENDED with power.runtime_error == 0 and drops the reference on its
parent starget->dev, allowing starget->dev and shost->shost_gendev to remain
RPM_SUSPENDED with hba->dev->power.child_count == 0.

In ufshcd_err_handler(), ufshcd_err_handling_prepare() takes
pm_runtime_get_sync(hba->dev), powers on regulators/clocks/IRQs, and calls
ufshcd_vops_resume(), and then ufshcd_reset_and_restore() resets the host and
restores hba->curr_dev_pwr_mode = UFS_ACTIVE_PWR_MODE and
hba->uic_link_state = UIC_LINK_ACTIVE_STATE.

Unlike the power.runtime_error branch below:

drivers/ufs/core/ufshcd.c:ufshcd_recover_pm_error() {
	...
	} else if (hba->ufs_device_wlun->sdev_gendev.power.runtime_error) {
		pm_runtime_get_sync(&starget->dev);
		pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev);
		pm_runtime_put_sync(&starget->dev);
		resume_sdev_queues = true;
	}
}

which synchronously resumes starget->dev and sets ufs_device_wlun active (so
starget->dev, shost->shost_gendev, and hba->dev all have power.child_count ==
1), this new branch only sets resume_sdev_queues = true and queues
asynchronous pm_request_resume(q->dev) work on pm_wq (or queues nothing if no
consumer LUN has q->rpm_status in RPM_SUSPENDED or RPM_SUSPENDING).

Immediately after ufshcd_recover_pm_error() returns,
ufshcd_err_handling_unprepare() runs:

drivers/ufs/core/ufshcd.c:ufshcd_err_handling_unprepare() {
	...
	if (ufshcd_is_clkscaling_supported(hba))
		ufshcd_clk_scaling_suspend(hba, false);
	ufshcd_rpm_put(hba);
	pm_runtime_put(hba->dev);
}

Because ufs_device_wlun, starget->dev, and shost->shost_gendev are still
RPM_SUSPENDED, pm_runtime_put(hba->dev) drops hba->dev->power.usage_count to 0
while hba->dev->power.child_count is 0. Wouldn't that allow
ufshcd_runtime_suspend() -> ufshcd_suspend() to disable host IRQs, gate clocks
to CLKS_OFF, and put vreg and vdd_hba into LPM while the UFS device and UniPro
link are still in UFS_ACTIVE_PWR_MODE and UIC_LINK_ACTIVE_STATE (without
__ufshcd_wl_suspend() or ufshcd_vops_suspend() having run), and then cause a
subsequent __ufshcd_wl_resume() to skip controller/link reinitialization
because both ufshcd_is_link_hibern8(hba) and ufshcd_is_link_off(hba) are
false?

> +	} else if (hba->ufs_device_wlun->sdev_gendev.power.runtime_error) {

[Severity: High]
What happens if ufshcd_rpm_get_sync(hba) in ufshcd_err_handling_prepare()
already transitioned ufs_device_wlun to RPM_ACTIVE before
ufshcd_recover_pm_error() is reached?

When a consumer-initiated runtime resume of ufs_device_wlun fails, commit
eef1d74bf88f leaves ufs_device_wlun in RPM_SUSPENDED with
power.runtime_error == 0, while the consumer queue remains blocked in
__bio_queue_enter() with q->pm_only set and q->rpm_status == RPM_SUSPENDED.

When ufshcd_err_handler() subsequently runs, it calls
ufshcd_err_handling_prepare() before ufshcd_set_eh_in_progress():

drivers/ufs/core/ufshcd.c:ufshcd_err_handling_prepare() {
	pm_runtime_get_sync(hba->dev);
	ufshcd_rpm_get_sync(hba);
	if (pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev) ||
	...
}

Because power.runtime_error is 0, ufshcd_rpm_get_sync(hba) invokes
__ufshcd_wl_resume() a second time instead of failing immediately with
-EINVAL. That second __ufshcd_wl_resume() call can succeed and transition
ufs_device_wlun to RPM_ACTIVE: for example, when hba->ufshcd_state is
UFSHCD_STATE_EH_SCHEDULED_NON_FATAL (which ufshcd_queuecommand() allows before
ufshcd_set_eh_in_progress() and which later triggers needs_reset = true in
ufshcd_err_handler()), or when __ufshcd_wl_resume() recovers the link via
ufshcd_link_recovery() or ufshcd_reset_and_restore():

drivers/ufs/core/ufshcd.c:__ufshcd_wl_resume() {
	...
			ret = ufshcd_link_recovery(hba);
			if (ret)
				goto vendor_suspend;
		}
	} else if (ufshcd_is_link_off(hba)) {
		ret = ufshcd_reset_and_restore(hba);
	...
}

Once ufshcd_rpm_get_sync(hba) in ufshcd_err_handling_prepare() sets
ufs_device_wlun to RPM_ACTIVE, both
pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev) and
hba->ufs_device_wlun->sdev_gendev.power.runtime_error will be false in
ufshcd_recover_pm_error() (or ufshcd_err_handling_should_stop() will skip the
do_reset path altogether if __ufshcd_wl_resume() already ran
ufshcd_reset_and_restore()). Wouldn't that leave resume_sdev_queues false and
leave the consumer queue stuck in __bio_queue_enter()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261105071518.1458428-1-stanleyjhu@google.com?part=2

  reply	other threads:[~2026-11-05  7:43 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05  7:15 [PATCH 0/2] scsi: ufs: core: Fix post-reset runtime PM recovery after eef1d74bf88f Stanley Jhu
2026-11-05  7:15 ` [PATCH 1/2] scsi: ufs: core: Skip redundant variant resume after error recovery power-up Stanley Jhu
2026-11-05  7:42   ` sashiko-bot
2026-11-05 14:43     ` Stanley Jhu
2026-11-05  7:15 ` [PATCH 2/2] scsi: ufs: core: Wake consumer queues on suspended W-LUN recovery Stanley Jhu
2026-11-05  7:43   ` sashiko-bot [this message]
2026-11-05 14:43     ` Stanley Jhu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-198693@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=stanleyjhu@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox