[PATCH 1/1] scsi: core: Restart a stopped queue when sysfs sets a device running

From: Brian Bunker

Date: Fri Oct 30 2026 - 12:43:03 EST


A device that its transport blocks has its queue stopped. If the SCSI
error handler then gives up on the device, it moves it from SDEV_BLOCK
to SDEV_OFFLINE and leaves the queue stopped. When userspace later
writes "running" to the device's state attribute, store_state_field()
moves it to SDEV_RUNNING, still with the queue stopped, and rescans it.
The rescan takes the device lock and waits for I/O that can never be
dispatched.

Nothing restarts the queue after that. When the transport later
unblocks the device, scsi_internal_device_unblock_nowait() rejects a
device that is already in SDEV_RUNNING and returns before
scsi_start_queue(), so the device is left running with its queue
stopped for good. The task that wrote "running" hangs forever holding
the device lock, and anything else that takes it hangs behind it.

This shows up with iSCSI when a session drops again just after
recovering. iscsid onlines the session's devices after a relogin by
writing "running" to every device it finds offline:

1. The session is blocked, which blocks the device and stops its
queue.
2. The error handler cannot recover the device and moves it from
SDEV_BLOCK to SDEV_OFFLINE. The queue stays stopped.
3. iscsid writes "running": SDEV_OFFLINE -> SDEV_RUNNING with the
queue still stopped, then the rescan sends an INQUIRY that sits
unsent while holding the device lock.
4. The session recovery timeout calls scsi_target_unblock(). The
other devices go from SDEV_BLOCK to SDEV_TRANSPORT_OFFLINE and get
their queues restarted, but this one is skipped because it is
already running.

A vmcore from such a hang shows the device in SDEV_RUNNING with
queue_stopped set and the queue's quiesce_depth at 1, the rescan's
INQUIRY never started (MQ_RQ_IDLE, no start time or deadline), and
iscsid owning the device lock while other tasks wait for it.

Restart the queue in store_state_field() when it moves a device to
SDEV_RUNNING. scsi_start_queue() only unquiesces the queue when
queue_stopped is set, so this is a no-op for a device whose queue is
already running, and it keeps a later scsi_start_queue() from the
transport balanced. If the transport is still blocked, its own
readiness checks in queuecommand keep commands from reaching the wire,
as for any other running device.

Fixes: f0f82e2476f6 ("scsi: core: Fix capacity set to zero after offlinining device")
Signed-off-by: Brian Bunker <brian@xxxxxxxxxxxxxxx>
---
drivers/scsi/scsi_sysfs.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index fe54792ed69e..f5416a1548bd 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -811,8 +811,16 @@ store_state_field(struct device *dev, struct device_attribute *attr,
ret = 0;
} else {
ret = scsi_device_set_state(sdev, state);
- if (ret == 0 && state == SDEV_RUNNING)
+ if (ret == 0 && state == SDEV_RUNNING) {
+ /*
+ * The device may have been offlined while blocked by
+ * its transport, so its queue can still be stopped.
+ * The transport's unblock skips a running device and
+ * would never restart it, so restart it here.
+ */
+ scsi_start_queue(sdev);
rescan_dev = true;
+ }
}
mutex_unlock(&sdev->state_mutex);

--
2.56.0