* [PATCH] scsi: core: Set BLK_FEAT_SKIP_TAGSET_QUIESCE on pseudo SCSI devices
@ 2026-09-01 12:23 Stanley Jhu
2026-09-01 17:38 ` Bart Van Assche
0 siblings, 1 reply; 3+ messages in thread
From: Stanley Jhu @ 2026-09-01 12:23 UTC (permalink / raw)
To: James E . J . Bottomley, Martin K . Petersen
Cc: Bart Van Assche, hare, john.g.garry, hch, linux-scsi,
linux-kernel, stable
Commit d630fbf6fc8c ("scsi: core: Support allocating a pseudo SCSI
device") introduced pseudo SCSI devices to allocate and dispatch
internal SCSI commands (such as device management commands) via
scsi_get_internal_cmd(). Subsequently, commit 08b12cda6c44 ("scsi: ufs:
core: Switch to scsi_get_internal_cmd()") switched UFS internal commands
to use this mechanism.
However, pseudo SCSI devices share the host tagset (&shost->tag_set)
with regular LUNs. During error recovery or host reset, drivers
typically quiesce the host tagset via
blk_mq_quiesce_tagset(&shost->tag_set) to freeze user block I/O.
Because pseudo_sdev->request_queue belongs to shost->tag_set,
blk_mq_quiesce_tagset() marks it QUEUE_FLAG_QUIESCED as well.
When error handling then attempts to issue internal commands to recover
or verify the device (e.g. ufshcd_verify_dev_init() issuing a NOP OUT
UPIU), blk_execute_rq() inserts the request into the request_queue of
pseudo_sdev. Because the queue is quiesced, blk_mq_run_hw_queue() skips
running the queue, and blk_execute_rq() blocks indefinitely waiting for
completion. Since blk_mq_unquiesce_tagset() is only invoked after error
recovery finishes, this results in an unrecoverable circular wait
deadlock.
Resolve this by setting BLK_FEAT_SKIP_TAGSET_QUIESCE in struct
queue_limits when allocating a pseudo SCSI device in scsi_alloc_sdev().
Passing this feature directly into blk_mq_alloc_queue() conforms to the
Block Layer's atomic queue limits initialization model and mirrors
NVMe's canonical pattern for its internal connect_q in
drivers/nvme/host/core.c. This ensures that blk_mq_quiesce_tagset()
ignores the pseudo device's request queue, allowing internal commands to
be dispatched while user I/O remains quiesced.
Fixes: d630fbf6fc8c ("scsi: core: Support allocating a pseudo SCSI device")
Fixes: 08b12cda6c44 ("scsi: ufs: core: Switch to scsi_get_internal_cmd()")
Cc: stable@vger.kernel.org
Signed-off-by: Stanley Jhu <stanleyjhu@google.com>
---
drivers/scsi/scsi_scan.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 3b82e80e807a..eb48866ed0dc 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -336,6 +336,8 @@ static struct scsi_device *scsi_alloc_sdev(struct
scsi_target *starget,
sdev->sg_reserved_size = INT_MAX;
scsi_init_limits(shost, &lim);
+ if (scsi_device_is_pseudo_dev(sdev))
+ lim.features |= BLK_FEAT_SKIP_TAGSET_QUIESCE;
q = blk_mq_alloc_queue(&sdev->host->tag_set, &lim, sdev);
if (IS_ERR(q)) {
/* release fn is set up in scsi_sysfs_device_initialise, so
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] scsi: core: Set BLK_FEAT_SKIP_TAGSET_QUIESCE on pseudo SCSI devices
2026-09-01 12:23 [PATCH] scsi: core: Set BLK_FEAT_SKIP_TAGSET_QUIESCE on pseudo SCSI devices Stanley Jhu
@ 2026-09-01 17:38 ` Bart Van Assche
2026-09-02 2:00 ` Stanley Jhu
0 siblings, 1 reply; 3+ messages in thread
From: Bart Van Assche @ 2026-09-01 17:38 UTC (permalink / raw)
To: Stanley Jhu, James E . J . Bottomley, Martin K . Petersen
Cc: hare, john.g.garry, hch, linux-scsi, linux-kernel, stable
On 9/1/26 5:23 AM, Stanley Jhu wrote:
> diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
> index 3b82e80e807a..eb48866ed0dc 100644
> --- a/drivers/scsi/scsi_scan.c
> +++ b/drivers/scsi/scsi_scan.c
> @@ -336,6 +336,8 @@ static struct scsi_device *scsi_alloc_sdev(struct
> scsi_target *starget,
> sdev->sg_reserved_size = INT_MAX;
>
> scsi_init_limits(shost, &lim);
> + if (scsi_device_is_pseudo_dev(sdev))
> + lim.features |= BLK_FEAT_SKIP_TAGSET_QUIESCE;
> q = blk_mq_alloc_queue(&sdev->host->tag_set, &lim, sdev);
> if (IS_ERR(q)) {
> /* release fn is set up in scsi_sysfs_device_initialise, so
The above change will break frequency scaling because
ufshcd_pause_command_processing() also calls blk_mq_quiesce_tagset(),
isn't it? Has it been considered to remove the blk_mq_unquiesce_tagset()
call from ufshcd_err_handling_unprepare() and to change the
blk_mq_quiesce_tagset() call in ufshcd_err_handling_prepare() into
blk_mq_wait_quiesce_done()? The following comment can be kept:
/* Wait for ongoing ufshcd_queuecommand() calls to finish. */
Thanks,
Bart.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] scsi: core: Set BLK_FEAT_SKIP_TAGSET_QUIESCE on pseudo SCSI devices
2026-09-01 17:38 ` Bart Van Assche
@ 2026-09-02 2:00 ` Stanley Jhu
0 siblings, 0 replies; 3+ messages in thread
From: Stanley Jhu @ 2026-09-02 2:00 UTC (permalink / raw)
To: Bart Van Assche, Stanley Jhu, James E . J . Bottomley,
Martin K . Petersen
Cc: hare, john.g.garry, hch, linux-scsi, linux-kernel, stable
On Tue, 1 Sep 2026, Bart Van Assche wrote:
> Does setting BLK_FEAT_SKIP_TAGSET_QUIESCE on pseudo_sdev break frequency
> scaling? ufshcd_pause_command_processing() also calls blk_mq_quiesce_tagset().
>
> Why not replace blk_mq_quiesce_tagset() in ufshcd_err_handling_prepare()
> with blk_mq_wait_quiesce_done() and drop blk_mq_unquiesce_tagset() in
> ufshcd_err_handling_unprepare()?
Hi Bart,
Looking at the three call sites of blk_mq_quiesce_tagset() in ufshcd.c, they
have distinct requirements regarding pseudo_sdev:
1. Clock scaling (ufshcd_clock_scaling_prepare):
Requires freezing all queues (including pseudo_sdev) while clock
frequencies change.
2. Command pause (ufshcd_pause_command_processing):
Requires freezing all queues while TX equalization retraining runs.
3. Error handling (ufshcd_err_handling_prepare):
Requires quiescing attached logical units to avoid HOST_BUSY retry
storms during host reset, but must keep pseudo_sdev open so internal
recovery commands (e.g. NOP OUT in ufshcd_verify_dev_init) can proceed.
Setting BLK_FEAT_SKIP_TAGSET_QUIESCE on pseudo_sdev in SCSI core breaks (1)
and (2). Conversely, replacing blk_mq_quiesce_tagset() with
blk_mq_wait_quiesce_done() in (3) leaves logical units unquiesced, causing
incoming I/O to storm the recovering controller with HOST_BUSY retries.
Would it be cleaner to keep blk_mq_quiesce_tagset() for (1) and (2), and
handle (3) locally in UFS error handling by quiescing only logical units?
static void ufshcd_quiesce_all_sdevs(struct ufs_hba *hba)
{
struct scsi_device *sdev;
shost_for_each_device(sdev, hba->host)
blk_mq_quiesce_queue_nowait(sdev->request_queue);
blk_mq_wait_quiesce_done(&hba->host->tag_set);
}
static void ufshcd_unquiesce_all_sdevs(struct ufs_hba *hba)
{
struct scsi_device *sdev;
shost_for_each_device(sdev, hba->host)
blk_mq_unquiesce_queue(sdev->request_queue);
}
Because shost_for_each_device() explicitly skips pseudo SCSI devices
(via scsi_device_is_pseudo_dev() in __scsi_iterate_devices()), logical units
are quiesced while pseudo_sdev remains unquiesced for recovery commands.
What do you think about this approach? If this looks reasonable to you,
I will withdraw the SCSI core patch and submit the UFS-local fix.
Thanks,
Stanley Jhu
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-02 2:01 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 12:23 [PATCH] scsi: core: Set BLK_FEAT_SKIP_TAGSET_QUIESCE on pseudo SCSI devices Stanley Jhu
2026-09-01 17:38 ` Bart Van Assche
2026-09-02 2:00 ` Stanley Jhu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox