All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] scsi: mpt3sas: Time out delayed not-responding device blocks
@ 2026-10-30 14:49 Jeff Layton
  2026-10-30 15:11 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Jeff Layton @ 2026-10-30 14:49 UTC (permalink / raw)
  To: Sathya Prakash, Sreekanth Reddy, Suganath Prabu Subramani,
	Ranjan Kumar, James E.J. Bottomley, Martin K. Petersen,
	Nagalakshmi Nandigama, James Bottomley
  Cc: Sreekanth Reddy, MPT-FusionLinux.pdl, linux-scsi, linux-kernel,
	Keith Busch, Jeff Layton

We have an agent that writes "- - -" to the sysfs scan attribute at
regular intervals. Several of these scans ended up deadlocked:

 1. A drive in reset failed its initial scan, so the worker started to
    remove the drive.
 2. A sysfs scan took sas_host->lock, allocated an sdev for the drive
    and sent an INQUIRY.
 3. A DELAY_NOT_RESPONDING event blocked the new sdev.
 4. The worker waited for sas_host->lock in sas_rphy_free():

      __mutex_lock
      sas_port_delete+0x75 [scsi_transport_sas]
      mpt3sas_transport_port_remove
      _scsih_add_device

After that, all further scan attempts got stuck waiting on the
sas_host->lock.

On DELAY_NOT_RESPONDING the event callback blocks every sdev on the
handle. The block is released only:
 - by the callback, if the firmware later reports TARG_NOT_RESPONDING
 - by the firmware event worker, when it processes a later event

Commit e4bc7f5c21a1 ("mpt3sas: Don't block the drive when drive addition
under the control of SML") was a partial fix for a similar issue.  Not
blocking sdevs that a scan is still probing is not enough: the scan also
sends REPORT LUNS to LUN 0 once it is visible, and LUN 0 may be blocked
before or during the scan.

Within the report device missing delay, the firmware either reports the
device as not responding, and the callback unblocks it, or the device
has come back. Past that delay the block has no further use. So:

Schedule delayed_work to the system_wq for the missing delay plus 30s.
When it runs, unblock any expired sdevs.

Cc: Keith Busch <kbusch@kernel.org>
Fixes: f92363d12359 ("[SCSI] mpt3sas: add new driver supporting 12GB SAS")
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 drivers/scsi/mpt3sas/mpt3sas_base.c  | 10 +++++
 drivers/scsi/mpt3sas/mpt3sas_base.h  |  7 +++
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 82 ++++++++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 1af25a22611a..1c4d10acc7ff 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -5405,6 +5405,7 @@ _base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc)
 /**
  * _base_assign_fw_reported_qd	- Get FW reported QD for SAS/SATA devices.
  *				- On failure set default QD values.
+ *				- Also get the PCIe device missing delay.
  * @ioc : per adapter object
  *
  * Returns 0 for success, non-zero for failure.
@@ -5416,6 +5417,7 @@ static int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc)
 	Mpi2SasIOUnitPage1_t sas_iounit_pg1;
 	Mpi26PCIeIOUnitPage1_t pcie_iounit_pg1;
 	u16 depth;
+	u8 dmd;
 	int rc = 0;
 
 	ioc->max_wideport_qd = MPT3SAS_SAS_QUEUE_DEPTH;
@@ -5453,6 +5455,14 @@ static int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc)
 	ioc->max_nvme_qd = (le16_to_cpu(pcie_iounit_pg1.NVMeMaxQueueDepth)) ?
 	    (le16_to_cpu(pcie_iounit_pg1.NVMeMaxQueueDepth)) :
 	    MPT3SAS_NVME_QUEUE_DEPTH;
+
+	dmd = pcie_iounit_pg1.DMDReportPCIe;
+	if (dmd & MPI26_PCIEIOUNIT1_DMDRPT_UNIT_16_SEC)
+		ioc->pcie_device_missing_delay =
+		    (dmd & MPI26_PCIEIOUNIT1_DMDRPT_DELAY_TIME_MASK) * 16;
+	else
+		ioc->pcie_device_missing_delay =
+		    dmd & MPI26_PCIEIOUNIT1_DMDRPT_DELAY_TIME_MASK;
 out:
 	dinitprintk(ioc, pr_err(
 	    "MaxWidePortQD: 0x%x MaxNarrowPortQD: 0x%x MaxSataQD: 0x%x MaxNvmeQD: 0x%x\n",
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 47255bf9cdda..4d12b1f6231c 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -469,6 +469,8 @@ struct MPT3SAS_TARGET {
  * @flags: MPT_DEVICE_XXX flags
  * @configured_lun: lun is configured
  * @block: device is in SDEV_BLOCK state
+ * @block_deadline: jiffies after which a delayed not-responding block is
+ *	released without waiting for the firmware event worker, 0 if none
  * @tlr_snoop_check: flag used in determining whether to disable TLR
  * @eedp_enable: eedp support enable bit
  * @eedp_type: 0(type_1), 1(type_2), 2(type_3)
@@ -486,6 +488,7 @@ struct MPT3SAS_DEVICE {
 	u8	ignore_delay_remove;
 	/* Iopriority Command Handling */
 	u8	ncq_prio_enable;
+	unsigned long	block_deadline;
 	/*
 	 * Bug workaround for SATL handling: the mpt2/3sas firmware
 	 * doesn't return BUSY or TASK_SET_FULL for subsequent
@@ -1165,6 +1168,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
  *			pci resource handling
  * @fault_reset_work_q: fw fault workqueue
  * @fault_reset_work: fw fault work
+ * @dnr_unblock_work: releases expired delayed not-responding blocks
  * @firmware_event_thread: fw event work queue
  * @fw_event_lock:
  * @fw_event_list: list of fw events
@@ -1251,6 +1255,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
  * @pcie_device_lock:
  * @io_missing_delay: time for IO completed by fw when PDR enabled
  * @device_missing_delay: time for device missing by fw when PDR enabled
+ * @pcie_device_missing_delay: time for PCIe device missing by fw
  * @sas_id : used for setting volume target IDs
  * @pcie_target_id: used for setting pcie target IDs
  * @blocking_handles: bitmask used to identify which devices need blocking
@@ -1350,6 +1355,7 @@ struct MPT3SAS_ADAPTER {
 	/* fw fault handler */
 	struct workqueue_struct *fault_reset_work_q;
 	struct delayed_work fault_reset_work;
+	struct delayed_work dnr_unblock_work;
 
 	/* fw event handler */
 	struct workqueue_struct	*firmware_event_thread;
@@ -1487,6 +1493,7 @@ struct MPT3SAS_ADAPTER {
 	spinlock_t	raid_device_lock;
 	u8		io_missing_delay;
 	u16		device_missing_delay;
+	u16		pcie_device_missing_delay;
 	int		sas_id;
 	int		pcie_target_id;
 
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 085d4672db85..dda5a429a917 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -3878,6 +3878,7 @@ _scsih_internal_device_block(struct scsi_device *sdev,
 	sdev_printk(KERN_INFO, sdev, "device_block, handle(0x%04x)\n",
 	    sas_device_priv_data->sas_target->handle);
 	sas_device_priv_data->block = 1;
+	sas_device_priv_data->block_deadline = 0;
 
 	r = scsi_internal_device_block_nowait(sdev);
 	if (r == -EINVAL)
@@ -3903,6 +3904,7 @@ _scsih_internal_device_unblock(struct scsi_device *sdev,
 	sdev_printk(KERN_WARNING, sdev, "device_unblock and setting to running, "
 	    "handle(0x%04x)\n", sas_device_priv_data->sas_target->handle);
 	sas_device_priv_data->block = 0;
+	sas_device_priv_data->block_deadline = 0;
 	r = scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING);
 	if (r == -EINVAL) {
 		/* The device has been set to SDEV_RUNNING by SD layer during
@@ -4121,6 +4123,7 @@ _scsih_ublock_io_device_wait(struct MPT3SAS_ADAPTER *ioc, u64 sas_address,
 			&& count++ <= command_retry_count);
 
 		sas_device_priv_data->block = 0;
+		sas_device_priv_data->block_deadline = 0;
 		if (rc != DEVICE_READY)
 			sas_device_priv_data->deleted = 1;
 		scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING);
@@ -4221,6 +4224,74 @@ _scsih_block_io_all_device(struct MPT3SAS_ADAPTER *ioc)
 	}
 }
 
+/*
+ * Margin on top of the firmware's report device missing delay before
+ * _scsih_dnr_unblock_work() releases a delayed not-responding block.
+ */
+#define MPT3SAS_DNR_BLOCK_SLACK	30
+
+static unsigned long
+_scsih_dnr_block_timeout(struct MPT3SAS_ADAPTER *ioc)
+{
+	return (max(ioc->device_missing_delay, ioc->pcie_device_missing_delay) +
+	    MPT3SAS_DNR_BLOCK_SLACK) * HZ;
+}
+
+/**
+ * _scsih_dnr_unblock_work - release expired delayed not-responding blocks
+ * @work: the dnr_unblock_work of the adapter
+ *
+ * Within the device missing delay, the firmware either reports the device
+ * as not responding, and the event callback unblocks it, or the device
+ * comes back, and only the firmware event worker unblocks it.  The worker
+ * may first need shost->scan_mutex or the SAS transport's host lock, and
+ * a scan holding those can have a command queued on the blocked sdev.
+ * Past the delay the block has no further use, so release it here.
+ */
+static void
+_scsih_dnr_unblock_work(struct work_struct *work)
+{
+	struct MPT3SAS_ADAPTER *ioc = container_of(to_delayed_work(work),
+	    struct MPT3SAS_ADAPTER, dnr_unblock_work);
+	struct MPT3SAS_DEVICE *sas_device_priv_data;
+	struct scsi_device *sdev;
+	unsigned long deadline, next = 0;
+
+	if (ioc->remove_host)
+		return;
+	if (ioc->shost_recovery || ioc->pci_error_recovery) {
+		queue_delayed_work(system_dfl_wq, &ioc->dnr_unblock_work, HZ);
+		return;
+	}
+
+	shost_for_each_device(sdev, ioc->shost) {
+		sas_device_priv_data = sdev->hostdata;
+		if (!sas_device_priv_data || !sas_device_priv_data->block)
+			continue;
+		deadline = sas_device_priv_data->block_deadline;
+		if (!deadline)
+			continue;
+		if (time_before(jiffies, deadline)) {
+			if (!next || time_before(deadline, next))
+				next = deadline;
+			continue;
+		}
+		sdev_printk(KERN_WARNING, sdev,
+		    "delayed not-responding block expired, handle(0x%04x)\n",
+		    sas_device_priv_data->sas_target->handle);
+		_scsih_internal_device_unblock(sdev, sas_device_priv_data);
+	}
+
+	/*
+	 * A block made while this ran may have queued the work already,
+	 * with its own later deadline.  Pull the timer in to the earliest
+	 * one seen here; the next run reschedules for the rest.
+	 */
+	if (next)
+		mod_delayed_work(system_dfl_wq, &ioc->dnr_unblock_work,
+		    max_t(long, next - jiffies, 1));
+}
+
 /**
  * _scsih_block_io_device - set the device state to SDEV_BLOCK
  * @ioc: per adapter object
@@ -4234,6 +4305,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
 	struct MPT3SAS_DEVICE *sas_device_priv_data;
 	struct scsi_device *sdev;
 	struct _sas_device *sas_device;
+	unsigned long timeout = _scsih_dnr_block_timeout(ioc);
+	bool blocked = false;
 
 	sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
 
@@ -4254,10 +4327,16 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
 			continue;
 		}
 		_scsih_internal_device_block(sdev, sas_device_priv_data);
+		sas_device_priv_data->block_deadline = (jiffies + timeout) ?: 1;
+		blocked = true;
 	}
 
 	if (sas_device)
 		sas_device_put(sas_device);
+
+	if (blocked)
+		queue_delayed_work(system_dfl_wq, &ioc->dnr_unblock_work,
+		    timeout);
 }
 
 /**
@@ -12541,6 +12620,7 @@ static void scsih_remove(struct pci_dev *pdev)
 		return;
 
 	ioc->remove_host = 1;
+	disable_delayed_work_sync(&ioc->dnr_unblock_work);
 
 	if (!pci_device_is_present(pdev)) {
 		mpt3sas_base_pause_mq_polling(ioc);
@@ -12641,6 +12721,7 @@ scsih_shutdown(struct pci_dev *pdev)
 		return;
 
 	ioc->remove_host = 1;
+	disable_delayed_work_sync(&ioc->dnr_unblock_work);
 
 	if (!pci_device_is_present(pdev)) {
 		mpt3sas_base_pause_mq_polling(ioc);
@@ -13553,6 +13634,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
 	INIT_LIST_HEAD(&ioc->reply_queue_list);
 	INIT_LIST_HEAD(&ioc->port_table_list);
+	INIT_DELAYED_WORK(&ioc->dnr_unblock_work, _scsih_dnr_unblock_work);
 
 	sprintf(ioc->name, "%s_cm%d", ioc->driver_name, ioc->id);
 

---
base-commit: 65ba8f34ec886ec72b2c07ddc8cf3d815c32869d
change-id: 20261030-sas-abba-eacfcc45fe36

Best regards,
-- 
Jeff Layton <jlayton@kernel.org>


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] scsi: mpt3sas: Time out delayed not-responding device blocks
  2026-10-30 14:49 [PATCH] scsi: mpt3sas: Time out delayed not-responding device blocks Jeff Layton
@ 2026-10-30 15:11 ` sashiko-bot
  0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-10-30 15:11 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] scsi: mpt3sas: use-after-free of sdev->hostdata in _scsih_dnr_unblock_work()
- [High] scsi: mpt3sas: race on block state in _scsih_dnr_unblock_work()
--

commit e9db80ae705cdf5de784aed30440e0d8af678dd9
Author: Jeff Layton <jlayton@kernel.org>

scsi: mpt3sas: Time out delayed not-responding device blocks

This commit adds a delayed work item (dnr_unblock_work) to time out and
release delayed not-responding SDEV_BLOCK states on SCSI devices after the
firmware's report device missing delay plus a 30-second margin, preventing
deadlocks during concurrent sysfs scans.

> diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
> index 085d4672db854..dda5a429a9173 100644
> --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
> +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
> @@ -3878,6 +3878,7 @@ _scsih_internal_device_block(struct scsi_device *sdev,
>  	sdev_printk(KERN_INFO, sdev, "device_block, handle(0x%04x)\n",
>  	    sas_device_priv_data->sas_target->handle);
>  	sas_device_priv_data->block = 1;
> +	sas_device_priv_data->block_deadline = 0;
>  
>  	r = scsi_internal_device_block_nowait(sdev);
>  	if (r == -EINVAL)
> @@ -3903,6 +3904,7 @@ _scsih_internal_device_unblock(struct scsi_device *sdev,
>  	sdev_printk(KERN_WARNING, sdev, "device_unblock and setting to running, "
>  	    "handle(0x%04x)\n", sas_device_priv_data->sas_target->handle);
>  	sas_device_priv_data->block = 0;
> +	sas_device_priv_data->block_deadline = 0;
>  	r = scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING);
>  	if (r == -EINVAL) {
>  		/* The device has been set to SDEV_RUNNING by SD layer during
> @@ -4121,6 +4123,7 @@ _scsih_ublock_io_device_wait(struct MPT3SAS_ADAPTER *ioc, u64 sas_address,
>  			&& count++ <= command_retry_count);
>  
>  		sas_device_priv_data->block = 0;
> +		sas_device_priv_data->block_deadline = 0;
>  		if (rc != DEVICE_READY)
>  			sas_device_priv_data->deleted = 1;
>  		scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING);
> @@ -4221,6 +4224,74 @@ _scsih_block_io_all_device(struct MPT3SAS_ADAPTER *ioc)
>  	}
>  }
>  
> +/*
> + * Margin on top of the firmware's report device missing delay before
> + * _scsih_dnr_unblock_work() releases a delayed not-responding block.
> + */
> +#define MPT3SAS_DNR_BLOCK_SLACK	30
> +
> +static unsigned long
> +_scsih_dnr_block_timeout(struct MPT3SAS_ADAPTER *ioc)
> +{
> +	return (max(ioc->device_missing_delay, ioc->pcie_device_missing_delay) +
> +	    MPT3SAS_DNR_BLOCK_SLACK) * HZ;
> +}
> +
> +/**
> + * _scsih_dnr_unblock_work - release expired delayed not-responding blocks
> + * @work: the dnr_unblock_work of the adapter
> + *
> + * Within the device missing delay, the firmware either reports the device
> + * as not responding, and the event callback unblocks it, or the device
> + * comes back, and only the firmware event worker unblocks it.  The worker
> + * may first need shost->scan_mutex or the SAS transport's host lock, and
> + * a scan holding those can have a command queued on the blocked sdev.
> + * Past the delay the block has no further use, so release it here.
> + */
> +static void
> +_scsih_dnr_unblock_work(struct work_struct *work)
> +{
> +	struct MPT3SAS_ADAPTER *ioc = container_of(to_delayed_work(work),
> +	    struct MPT3SAS_ADAPTER, dnr_unblock_work);
> +	struct MPT3SAS_DEVICE *sas_device_priv_data;
> +	struct scsi_device *sdev;
> +	unsigned long deadline, next = 0;
> +
> +	if (ioc->remove_host)
> +		return;
> +	if (ioc->shost_recovery || ioc->pci_error_recovery) {
> +		queue_delayed_work(system_dfl_wq, &ioc->dnr_unblock_work, HZ);
> +		return;
> +	}
> +
> +	shost_for_each_device(sdev, ioc->shost) {
> +		sas_device_priv_data = sdev->hostdata;
> +		if (!sas_device_priv_data || !sas_device_priv_data->block)
> +			continue;
> +		deadline = sas_device_priv_data->block_deadline;
> +		if (!deadline)
> +			continue;
> +		if (time_before(jiffies, deadline)) {
> +			if (!next || time_before(deadline, next))
> +				next = deadline;
> +			continue;
> +		}
> +		sdev_printk(KERN_WARNING, sdev,
> +		    "delayed not-responding block expired, handle(0x%04x)\n",
> +		    sas_device_priv_data->sas_target->handle);
> +		_scsih_internal_device_unblock(sdev, sas_device_priv_data);
> +	}

[Severity: High]
Can _scsih_dnr_unblock_work() trigger a use-after-free on sdev->hostdata
(struct MPT3SAS_DEVICE) and sas_device_priv_data->sas_target (struct
MPT3SAS_TARGET)?

_scsih_dnr_unblock_work() runs on system_dfl_wq without holding
shost->scan_mutex, shost->host_lock, or any adapter lock. Inside
shost_for_each_device(), __scsi_iterate_devices() only holds
shost->host_lock while calling scsi_device_get(sdev) to take a reference on
sdev->sdev_gendev, then drops shost->host_lock before returning sdev to the
loop body.

Concurrently on another CPU, __scsi_remove_device(sdev) can run (for
example, when scsi_probe_and_add_lun() fails on a newly allocated sdev
after TARG_NOT_RESPONDING unblocks it, when ioc->firmware_event_thread
removes the target via scsi_remove_target(), or via sysfs delete).
__scsi_remove_device() synchronously invokes scsih_sdev_destroy() before
put_device(&sdev->sdev_gendev):

drivers/scsi/mpt3sas/mpt3sas_scsih.c:scsih_sdev_destroy() {
    ...
	kfree(sdev->hostdata);
	sdev->hostdata = NULL;
}

and scsi_target_reap() invokes scsih_target_destroy(), freeing
starget->hostdata (sas_target).

Because holding a reference on sdev->sdev_gendev does not prevent
__scsi_remove_device() from calling ->sdev_destroy(),
_scsih_dnr_unblock_work() and _scsih_internal_device_unblock() can read and
write freed sas_device_priv_data (block and block_deadline) and dereference
freed sas_device_priv_data->sas_target->handle.

> +
> +	/*
> +	 * A block made while this ran may have queued the work already,
> +	 * with its own later deadline.  Pull the timer in to the earliest
> +	 * one seen here; the next run reschedules for the rest.
> +	 */
> +	if (next)
> +		mod_delayed_work(system_dfl_wq, &ioc->dnr_unblock_work,
> +		    max_t(long, next - jiffies, 1));
> +}
> +
>  /**
>   * _scsih_block_io_device - set the device state to SDEV_BLOCK
>   * @ioc: per adapter object
> @@ -4234,6 +4305,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>  	struct MPT3SAS_DEVICE *sas_device_priv_data;
>  	struct scsi_device *sdev;
>  	struct _sas_device *sas_device;
> +	unsigned long timeout = _scsih_dnr_block_timeout(ioc);
> +	bool blocked = false;
>  
>  	sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
>  
> @@ -4254,10 +4327,16 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>  			continue;
>  		}
>  		_scsih_internal_device_block(sdev, sas_device_priv_data);
> +		sas_device_priv_data->block_deadline = (jiffies + timeout) ?: 1;
> +		blocked = true;
>  	}

[Severity: High]
Does running _scsih_dnr_unblock_work() on system_dfl_wq without
synchronization race with _scsih_block_io_device() in interrupt context and
_scsih_ublock_io_device_wait() on firmware_event_thread?

There appear to be two races on sas_device_priv_data->block,
sas_device_priv_data->block_deadline, and sdev->sdev_state:

1. _scsih_dnr_unblock_work() runs in process context with interrupts
enabled and calls _scsih_internal_device_unblock():

drivers/scsi/mpt3sas/mpt3sas_scsih.c:_scsih_internal_device_unblock() {
    ...
	sas_device_priv_data->block = 0;
	sas_device_priv_data->block_deadline = 0;
	r = scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING);
    ...
}

If an interrupt for a new DELAY_NOT_RESPONDING event fires right after
sas_device_priv_data->block = 0 is written,
mpt3sas_scsih_event_callback()->_scsih_block_io_device() sees
sas_device_priv_data->block == 0, calls _scsih_internal_device_block()
(setting sas_device_priv_data->block = 1 and sdev->sdev_state = SDEV_BLOCK),
and sets a new non-zero sas_device_priv_data->block_deadline.

When _scsih_internal_device_unblock() resumes, it overwrites
sas_device_priv_data->block_deadline = 0 and calls
scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING). That leaves sdev
in SDEV_RUNNING with sas_device_priv_data->block == 1 and
block_deadline == 0, causing scsih_qcmd() to reject all commands with
SCSI_MLQUEUE_DEVICE_BUSY indefinitely while _scsih_dnr_unblock_work()
ignores the device because block_deadline is 0.

2. In _scsih_ublock_io_device_wait() (and _scsih_ublock_io_all_device()),
sas_device_priv_data->block_deadline remains armed throughout the
_scsih_wait_for_device_to_become_ready() retry loop (up to
command_retry_count = 144 retries). If block_deadline expires while
_scsih_ublock_io_device_wait() is still polling the returning device or
offlining a failed device, _scsih_dnr_unblock_work() will concurrently call
_scsih_internal_device_unblock() and transition the device to SDEV_RUNNING.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261030-sas-abba-v1-1-b8cdd714a37c@kernel.org?part=1

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-30 15:11 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-30 14:49 [PATCH] scsi: mpt3sas: Time out delayed not-responding device blocks Jeff Layton
2026-10-30 15:11 ` sashiko-bot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.