From: Stanley Jhu <stanleyjhu@google.com>
To: "Martin K . Petersen" <mkp@kernel.org>,
"James E . J . Bottomley"
<James.Bottomley@HansenPartnership.com>,
linux-scsi@vger.kernel.org
Cc: Bart Van Assche <bvanassche@acm.org>,
Seunghwan Baek <sh8267.baek@samsung.com>,
Alim Akhtar <alim.akhtar@samsung.com>,
Avri Altman <avri.altman@sandisk.com>,
Peter Wang <peter.wang@mediatek.com>,
Can Guo <can.guo@oss.qualcomm.com>,
Bean Huo <beanhuo@micron.com>,
linux-kernel@vger.kernel.org, stable@vger.kernel.org,
Stanley Jhu <stanleyjhu@google.com>
Subject: [PATCH] scsi: ufs: core: Prevent MMIO access and drain in-flight commands during shutdown
Date: Thu, 3 Sep 2026 11:13:44 +0800 [thread overview]
Message-ID: <20260903031344.3740524-1-stanleyjhu@google.com> (raw)
Commit 19a198b67767 ("scsi: ufs: core: Put the normal LU into
SDEV_OFFLINE when ufs device wl-lun suspend") transitioned normal
logical units into SDEV_OFFLINE during ufshcd_wl_shutdown() to prevent
requeue deadlocks. However, setting SDEV_OFFLINE does not wait for
in-flight or currently dispatching requests to drain.
If an I/O request races past scsi_queue_rq() right as or before
SDEV_OFFLINE is set, or if an asynchronous command execution suffers
scheduling delays, it can arrive in ufshcd_queuecommand() or issue MMIO
writes after ufshcd_wl_shutdown() has powered off the UFS controller
(is_powered = false, regulators disabled, clocks gated). Writing to MMIO
registers of a power-gated or clock-gated controller triggers fatal
hardware bus errors, system hangs, or kernel panics.
Fix this with a dual-layer defense:
1. In ufshcd_queuecommand(), check if hba->shutting_down is set. Reject
any non-WLUN / non-PM requests immediately with DID_NO_CONNECT before
any MMIO register access.
Note that checking !hba->is_powered is unnecessary here because
hba->shutting_down is asserted prior to disabling clocks and
regulators in ufshcd_wl_shutdown(), and module removal drains and
destroys all request queues via scsi_remove_host() before is_powered
is cleared.
2. In ufshcd_wl_shutdown(), invoke ufshcd_wait_for_pending_cmds() after
taking regular LUNs offline to drain all existing hardware transfer
and task management requests before putting the device into powerdown
mode and powering down the host controller. Warn if draining times
out after 1 second.
Fixes: 19a198b67767 ("scsi: ufs: core: Put the normal LU into SDEV_OFFLINE when ufs device wl-lun suspend")
Cc: stable@vger.kernel.org
Signed-off-by: Stanley Jhu <stanleyjhu@google.com>
---
drivers/ufs/core/ufshcd.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 2ba244cf40ac..6d78e34a19b2 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -3105,6 +3105,25 @@ static enum scsi_qc_status ufshcd_queuecommand(struct Scsi_Host *host,
int err = 0;
struct ufs_hw_queue *hwq = NULL;
+ /*
+ * During host shutdown, fail any incoming regular I/O commands
+ * immediately. This prevents stray requests that bypassed SCSI queue
+ * offline checks from writing to MMIO doorbells after the controller
+ * is power-gated (causing fatal bus errors / panics).
+ *
+ * Note: Checking !hba->is_powered is not needed here because:
+ * 1. During shutdown, hba->shutting_down is set prior to cutting
+ * controller power, so shutting_down alone fully covers the
+ * unpowered window.
+ * 2. During module removal, scsi_remove_host() freezes and destroys
+ * all request queues before hba->is_powered is set to false in
+ * ufshcd_hba_exit().
+ */
+ if (unlikely(READ_ONCE(hba->shutting_down))) {
+ if (!is_device_wlun(cmd->device) ||
+ !(scsi_cmd_to_rq(cmd)->rq_flags & RQF_PM)) {
+ set_host_byte(cmd, DID_NO_CONNECT);
+ scsi_done(cmd);
+ return 0;
+ }
+ }
+
switch (hba->ufshcd_state) {
case UFSHCD_STATE_OPERATIONAL:
break;
@@ -10931,6 +10950,14 @@ static void ufshcd_wl_shutdown(struct scsi_device *sdev)
scsi_device_set_state(sdev, SDEV_OFFLINE);
mutex_unlock(&sdev->state_mutex);
}
+
+ /*
+ * Drain all in-flight transfer and task management requests before
+ * putting the device into low power and turning off controller power.
+ */
+ if (ufshcd_wait_for_pending_cmds(hba, USEC_PER_SEC))
+ dev_warn(hba->dev,
+ "timed out waiting for in-flight commands during shutdown\n");
+
__ufshcd_wl_suspend(hba, UFS_SHUTDOWN_PM);
/*
--
2.43.0
reply other threads:[~2026-09-03 3:13 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260903031344.3740524-1-stanleyjhu@google.com \
--to=stanleyjhu@google.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=alim.akhtar@samsung.com \
--cc=avri.altman@sandisk.com \
--cc=beanhuo@micron.com \
--cc=bvanassche@acm.org \
--cc=can.guo@oss.qualcomm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=mkp@kernel.org \
--cc=peter.wang@mediatek.com \
--cc=sh8267.baek@samsung.com \
--cc=stable@vger.kernel.org \
/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