* [PATCH v3 1/2] scsi: libsas: Add PHYE_NOTIFY_ENABLE_SPINUP phy event for ASC/ASCQ=0x04/0x11
2026-08-03 2:05 [PATCH v3 0/2] scsi: libsas: Support spinup notification for SAS devices Xingui Yang
@ 2026-08-03 2:05 ` Xingui Yang
2026-08-03 2:05 ` [PATCH v3 2/2] scsi: hisi_sas: Add lldd_notify_enable_spinup callback for SAS devices Xingui Yang
2026-08-04 7:35 ` [PATCH v3 0/2] scsi: libsas: Support spinup notification " John Garry
2 siblings, 0 replies; 7+ messages in thread
From: Xingui Yang @ 2026-08-03 2:05 UTC (permalink / raw)
To: john.g.garry, yanaijie, jejb, martin.petersen
Cc: linux-scsi, linux-kernel, linuxarm, yangxingui, liuyonglong,
kangfenglong
When a SAS device is in the Active_Wait or Idle_Wait power state, it
returns NOT_READY with ASC/ASCQ = 0x04/0x11 (notify (enable spinup)
required), indicating that a NOTIFY(ENABLE SPINUP) primitive is needed to
trigger media spinup.
Add a PHYE_NOTIFY_ENABLE_SPINUP phy event and an optional
lldd_notify_enable_spinup callback to sas_domain_function_template. Sense
detection is done in sas_ssp_task_spinup_notify(), called from
sas_ssp_task_response() which is the common entry point for all SAS LLDDs.
Signed-off-by: Xingui Yang <yangxingui@huawei.com>
---
drivers/scsi/libsas/sas_internal.h | 2 ++
drivers/scsi/libsas/sas_phy.c | 12 ++++++++
drivers/scsi/libsas/sas_scsi_host.c | 45 +++++++++++++++++++++++++++++
drivers/scsi/libsas/sas_task.c | 2 ++
include/scsi/libsas.h | 9 ++++++
5 files changed, 70 insertions(+)
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 7dce0f587149..fa06f50b0bf0 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -107,6 +107,8 @@ extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS];
void sas_task_internal_done(struct sas_task *task);
void sas_task_internal_timedout(struct timer_list *t);
+void sas_ssp_task_spinup_notify(struct sas_task *task,
+ struct ssp_response_iu *iu);
int sas_execute_tmf(struct domain_device *device, void *parameter,
int para_len, int force_phy_id,
struct sas_tmf_task *tmf);
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index 58f08dc2c187..897a5b46db78 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -111,6 +111,17 @@ static void sas_phye_shutdown(struct work_struct *work)
phy->in_shutdown = 0;
}
+static void sas_phye_notify_enable_spinup(struct work_struct *work)
+{
+ struct asd_sas_event *ev = to_asd_sas_event(work);
+ struct asd_sas_phy *phy = ev->phy;
+ struct sas_ha_struct *sas_ha = phy->ha;
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->shost->transportt);
+
+ i->dft->lldd_notify_enable_spinup(phy);
+}
+
/* ---------- Phy class registration ---------- */
int sas_register_phys(struct sas_ha_struct *sas_ha)
@@ -186,4 +197,5 @@ const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
[PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
[PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
[PHYE_SHUTDOWN] = sas_phye_shutdown,
+ [PHYE_NOTIFY_ENABLE_SPINUP] = sas_phye_notify_enable_spinup,
};
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index c83282733ec4..bb1dfc16d8d1 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -34,6 +34,51 @@
#include <linux/scatterlist.h>
#include <linux/libata.h>
+/*
+ * If the SSP response carries NOT_READY sense with ASC/ASCQ = 0x04/0x11
+ * ("notify (enable spinup) required"), queue a PHYE_NOTIFY_ENABLE_SPINUP
+ * phy event so the LLDD can send a NOTIFY(ENABLE SPINUP) primitive.
+ */
+void sas_ssp_task_spinup_notify(struct sas_task *task,
+ struct ssp_response_iu *iu)
+{
+ struct domain_device *dev = task->dev;
+ struct sas_ha_struct *ha = dev->port->ha;
+ struct sas_internal *i = to_sas_internal(ha->shost->transportt);
+ struct scsi_sense_hdr sshdr;
+ struct sas_phy *local_phy;
+ struct asd_sas_phy *phy;
+ u32 sense_len;
+
+ /*
+ * NOTIFY(ENABLE SPINUP) must be sent on the local phy directly
+ * attached to the target. Skip expander-attached devices.
+ */
+ if (dev->parent && dev_is_expander(dev->parent->dev_type))
+ return;
+
+ if (!i->dft->lldd_notify_enable_spinup)
+ return;
+
+ if (iu->status != SAM_STAT_CHECK_CONDITION)
+ return;
+
+ sense_len = min_t(u32, be32_to_cpu(iu->sense_data_len),
+ SAS_STATUS_BUF_SIZE);
+ if (!scsi_normalize_sense(iu->sense_data, sense_len, &sshdr))
+ return;
+
+ if (sshdr.sense_key != NOT_READY ||
+ sshdr.asc != 0x04 || sshdr.ascq != 0x11)
+ return;
+
+ local_phy = sas_get_local_phy(dev);
+ phy = ha->sas_phy[local_phy->number];
+ sas_put_local_phy(local_phy);
+
+ sas_notify_phy_event(phy, PHYE_NOTIFY_ENABLE_SPINUP, GFP_ATOMIC);
+}
+
/* record final status and free the task */
static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task)
{
diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
index e9d291007817..d1eb6ce90626 100644
--- a/drivers/scsi/libsas/sas_task.c
+++ b/drivers/scsi/libsas/sas_task.c
@@ -29,6 +29,8 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task,
be32_to_cpu(iu->sense_data_len));
memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
+ sas_ssp_task_spinup_notify(task, iu);
+
if (iu->status != SAM_STAT_CHECK_CONDITION)
dev_warn(dev, "dev %016llx sent sense data, but stat(0x%x) is not CHECK CONDITION\n",
SAS_ADDR(task->dev->sas_addr), iu->status);
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 163f23c92b41..945b7cfe0224 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -49,6 +49,7 @@ enum phy_event {
PHYE_SPINUP_HOLD, /* hot plug SATA, no COMWAKE sent */
PHYE_RESUME_TIMEOUT,
PHYE_SHUTDOWN,
+ PHYE_NOTIFY_ENABLE_SPINUP, /* NOTIFY(ENABLE SPINUP) primitive */
PHY_NUM_EVENTS,
};
@@ -674,6 +675,14 @@ struct sas_domain_function_template {
/* GPIO support */
int (*lldd_write_gpio)(struct sas_ha_struct *, u8 reg_type,
u8 reg_index, u8 reg_count, u8 *write_data);
+
+ /*
+ * Optional callback invoked when an SSP target returns NOT_READY
+ * with ASC/ASCQ = 0x04/0x11 ("notify (enable spinup) required"),
+ * indicating the device is in Active_Wait/Idle_Wait state and
+ * needs a NOTIFY(ENABLE SPINUP) primitive to proceed.
+ */
+ void (*lldd_notify_enable_spinup)(struct asd_sas_phy *phy);
};
extern int sas_register_ha(struct sas_ha_struct *);
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v3 2/2] scsi: hisi_sas: Add lldd_notify_enable_spinup callback for SAS devices
2026-08-03 2:05 [PATCH v3 0/2] scsi: libsas: Support spinup notification for SAS devices Xingui Yang
2026-08-03 2:05 ` [PATCH v3 1/2] scsi: libsas: Add PHYE_NOTIFY_ENABLE_SPINUP phy event for ASC/ASCQ=0x04/0x11 Xingui Yang
@ 2026-08-03 2:05 ` Xingui Yang
2026-08-04 7:35 ` [PATCH v3 0/2] scsi: libsas: Support spinup notification " John Garry
2 siblings, 0 replies; 7+ messages in thread
From: Xingui Yang @ 2026-08-03 2:05 UTC (permalink / raw)
To: john.g.garry, yanaijie, jejb, martin.petersen
Cc: linux-scsi, linux-kernel, linuxarm, yangxingui, liuyonglong,
kangfenglong
Register the lldd_notify_enable_spinup callback. The callback sends a
NOTIFY(ENABLE SPINUP) primitive via sl_notify_ssp() to trigger media spinup
on SAS devices in Active_Wait or Idle_Wait state.
Signed-off-by: Xingui Yang <yangxingui@huawei.com>
---
drivers/scsi/hisi_sas/hisi_sas_main.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 944ce19ae2fc..a726d6680386 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -2081,6 +2081,16 @@ static int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type,
reg_index, reg_count, write_data);
}
+static void hisi_sas_notify_enable_spinup(struct asd_sas_phy *phy)
+{
+ struct hisi_sas_phy *hisi_phy =
+ container_of(phy, struct hisi_sas_phy, sas_phy);
+ struct hisi_hba *hisi_hba = hisi_phy->hisi_hba;
+
+ hisi_hba->hw->sl_notify_ssp(hisi_hba, phy->id);
+ dev_info(hisi_hba->dev, "phy%d notify enable spinup\n", phy->id);
+}
+
static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
{
struct asd_sas_phy *sas_phy = &phy->sas_phy;
@@ -2180,6 +2190,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = {
.lldd_write_gpio = hisi_sas_write_gpio,
.lldd_tmf_aborted = hisi_sas_tmf_aborted,
.lldd_abort_timeout = hisi_sas_internal_abort_timeout,
+ .lldd_notify_enable_spinup = hisi_sas_notify_enable_spinup,
};
void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v3 0/2] scsi: libsas: Support spinup notification for SAS devices
2026-08-03 2:05 [PATCH v3 0/2] scsi: libsas: Support spinup notification for SAS devices Xingui Yang
2026-08-03 2:05 ` [PATCH v3 1/2] scsi: libsas: Add PHYE_NOTIFY_ENABLE_SPINUP phy event for ASC/ASCQ=0x04/0x11 Xingui Yang
2026-08-03 2:05 ` [PATCH v3 2/2] scsi: hisi_sas: Add lldd_notify_enable_spinup callback for SAS devices Xingui Yang
@ 2026-08-04 7:35 ` John Garry
2026-08-04 9:30 ` yangxingui
2 siblings, 1 reply; 7+ messages in thread
From: John Garry @ 2026-08-04 7:35 UTC (permalink / raw)
To: Xingui Yang, yanaijie, jejb, martin.petersen
Cc: linux-scsi, linux-kernel, linuxarm, liuyonglong, kangfenglong
On 03/08/2026 03:05, Xingui Yang wrote:
> When a SAS device is in the Active_Wait or Idle_Wait power state, it
> returns NOT_READY with ASC/ASCQ = 0x04/0x11 (notify (enable spinup)
> required), indicating that a NOTIFY(ENABLE SPINUP) primitive is needed to
> trigger media spinup.
>
> Without handling this condition, the SCSI mid-layer will indefinitely retry
> the command with ACTION_DELAYED_RETRY, resulting in the disk never spinning
> up and becoming unusable. A typical manifestation is:
>
> sd 4:0:9:0: [sde] Spinning up disk...
> ...not responding...
> sd 4:0:9:0: [sde] Sense Key : Not Ready
> sd 4:0:9:0: [sde] Add. Sense: Logical unit not ready, notify (enable spinup) required
>
> To resolve this, the SAS controller needs to send a NOTIFY(ENABLE SPINUP)
> primitive to the target phy, which transitions the device out of the
> waiting state and allows normal spinup to proceed.
>
How would other SAS HBAs which use libsas handle this scenario? Since
they have FW, would the FW automatically issue this NOTIFY(ENABLE SPINUP)?
I just wonder why hisi_sas seems to be only driver which would need this.
> This patch series addresses the issue entirely within the SAS transport
> layer (libsas), reusing the existing phy event framework, without modifying
> the generic SCSI mid-layer. This addresses the review feedback from
> John Garry on v2.
>
> Changes in v3 (addressing John Garry's review on v2):
> - Move spinup notification from scsi_host_template to libsas. Reuse
> the existing phy event framework: add PHYE_NOTIFY_ENABLE_SPINUP
> and lldd_notify_enable_spinup callback.
> - Sense detection in sas_ssp_task_response() covers all SAS LLDDs.
>
> Changes in v2 (addressing Sashiko AI review on v1):
> - Add softirq context documentation to spinup_notify in
> scsi_host.h
> - Defer sl_notify_ssp() to ordered workqueue, fixing
> msleep-in-atomic bug, preventing RMW races on SL_CONTROL, and
> deduplicating concurrent callbacks via queue_work()
>
> Xingui Yang (2):
> scsi: libsas: Add PHYE_NOTIFY_ENABLE_SPINUP phy event for
> ASC/ASCQ=0x04/0x11
> scsi: hisi_sas: Add lldd_notify_enable_spinup callback for SAS devices
>
> drivers/scsi/hisi_sas/hisi_sas_main.c | 11 +++++++
> drivers/scsi/libsas/sas_internal.h | 2 ++
> drivers/scsi/libsas/sas_phy.c | 12 +++++++
> drivers/scsi/libsas/sas_scsi_host.c | 45 +++++++++++++++++++++++++++
> drivers/scsi/libsas/sas_task.c | 2 ++
> include/scsi/libsas.h | 9 ++++++
> 6 files changed, 81 insertions(+)
>
^ permalink raw reply [flat|nested] 7+ messages in thread