Re: [PATCH] scsi: libsas: Fix SMP IO deadlock during HA resume
From: yangxingui
Date: Thu Sep 17 2026 - 05:42:05 EST
Hi John
Thank you for the review.
On 2026/9/16 21:58, John Garry wrote:
On 9/11/26 02:00, yangxingui wrote:
Hi John & Jason,
Kindly ping for review...
What about the sashiko comment:
- [High] Bypassing PM reference counting via a global state flag creates a race condition where concurrent independent threads can submit SMP I/Os without holding a PM reference, risking premature hardware suspend.
It looks correct.
Agreed. Although the possibility is very slim.
The SMP IO which sas_drain_work() waits on cannot outlive the
SAS_HA_RESUMING window, but a BSG request submitted during the window
takes no PM reference for the duration of its IO, and the controller
may autosuspend underneath it. v2 takes the reference with
pm_runtime_get_noresume()/pm_runtime_put_noidle() instead: the usage
counter stays elevated for the IO duration, without waiting for the
already ongoing resume.
On 2026/8/26 11:28, Xingui Yang wrote:
During sas_resume_ha() -> sas_drain_work(),
This is poorly described - what does during sas_resume_ha() -> sas_drain_work() even mean?
The deadlock happens during a runtime resume, while
sas_resume_ha() is inside sas_drain_work(), flushing the event and
discovery workqueues. That flush includes the DISCE_RESUME work queued
when the phys come back up: sas_resume_devices() -> sas_resume_sata()
resumes the ATA ports through the libata error handler and waits for
it in sas_ata_flush_pm_eh(). So the resume is blocked in
sas_drain_work() waiting on that error handling - and the error
handling's reset of the expander-attached ATA device blocks on the
host being RPM_RESUMING, i.e. on the very resume which is waiting on
it.
ATA EH will trigger SMP
IOs via
sas_phy_reset() -> sas_smp_phy_control() for expander-attached ATA devices.
What commands are these specifically?
SMP PHY CONTROL (hard reset or link reset) commands, sent to the
expander which owns the phy of the ATA device being recovered:
ata_eh_recover() -> ata_eh_reset() -> sas_ata_hard_reset()
-> lldd_I_T_nexus_reset() -> sas_phy_reset()
-> sas_smp_phy_control() -> smp_execute_task_sg()
A directly-attached device would take the lldd_control_phy() path
instead, which is why only the EXP topology deadlocks.
Thanks,
Xingui
.