Skip to content

Commit ce6d26b

Browse files
0xIO32martinkpetersen
authored andcommitted
scsi: ata: Use ACPI methods to power on disks
Some embedded devices have the ability to control whether power is provided to the disks via the SATA power connector or not. If power resources are defined on ATA ports / devices in ACPI, we should try to set the power state to D0 before probing the disk to ensure that any power supply or power gate that may exist is providing power to the disk. An example for such devices would be newer synology NAS devices. Every disk slot has its own SATA power connector. Whether the connector is providing power is controlled via an gpio, which is *off by default*. Also the disk loses power on reboots. Add a new function, ata_acpi_port_power_on(), that will be used to power on the SATA power connector if usable ACPI power resources on the associated ATA port / device are found. It will be called right before probing the port, therefore the disk will be powered on just in time. Signed-off-by: Markus Probst <markus.probst@posteo.de> Reviewed-by: Damien Le Moal <dlemoal@kernel.org> Link: https://patch.msgid.link/20251104142413.322347-3-markus.probst@posteo.de Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 8fdfdb1 commit ce6d26b

3 files changed

Lines changed: 45 additions & 0 deletions

File tree

drivers/ata/libata-acpi.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,47 @@ void ata_acpi_bind_dev(struct ata_device *dev)
245245
ata_acpi_dev_uevent);
246246
}
247247

248+
/**
249+
* ata_acpi_port_power_on - set the power state of the ata port to D0
250+
* @ap: target ATA port
251+
*
252+
* This function is called at the beginning of ata_port_probe().
253+
*/
254+
void ata_acpi_port_power_on(struct ata_port *ap)
255+
{
256+
acpi_handle handle;
257+
int i;
258+
259+
/*
260+
* If ATA_FLAG_ACPI_SATA is set, the acpi fwnode is attached to the
261+
* ata_device instead of the ata_port.
262+
*/
263+
if (ap->flags & ATA_FLAG_ACPI_SATA) {
264+
for (i = 0; i < ATA_MAX_DEVICES; i++) {
265+
struct ata_device *dev = &ap->link.device[i];
266+
267+
if (!is_acpi_device_node(dev->tdev.fwnode))
268+
continue;
269+
handle = ACPI_HANDLE(&dev->tdev);
270+
if (!acpi_bus_power_manageable(handle))
271+
continue;
272+
if (acpi_bus_set_power(handle, ACPI_STATE_D0))
273+
ata_dev_err(dev,
274+
"acpi: failed to set power state to D0\n");
275+
}
276+
return;
277+
}
278+
279+
if (!is_acpi_device_node(ap->tdev.fwnode))
280+
return;
281+
handle = ACPI_HANDLE(&ap->tdev);
282+
if (!acpi_bus_power_manageable(handle))
283+
return;
284+
285+
if (acpi_bus_set_power(handle, ACPI_STATE_D0))
286+
ata_port_err(ap, "acpi: failed to set power state to D0\n");
287+
}
288+
248289
/**
249290
* ata_acpi_dissociate - dissociate ATA host from ACPI objects
250291
* @host: target ATA host

drivers/ata/libata-core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5904,6 +5904,8 @@ void ata_port_probe(struct ata_port *ap)
59045904
struct ata_eh_info *ehi = &ap->link.eh_info;
59055905
unsigned long flags;
59065906

5907+
ata_acpi_port_power_on(ap);
5908+
59075909
/* kick EH for boot probing */
59085910
spin_lock_irqsave(ap->lock, flags);
59095911

drivers/ata/libata.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ extern void ata_acpi_on_disable(struct ata_device *dev);
130130
extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
131131
extern void ata_acpi_bind_port(struct ata_port *ap);
132132
extern void ata_acpi_bind_dev(struct ata_device *dev);
133+
extern void ata_acpi_port_power_on(struct ata_port *ap);
133134
extern acpi_handle ata_dev_acpi_handle(struct ata_device *dev);
134135
#else
135136
static inline void ata_acpi_dissociate(struct ata_host *host) { }
@@ -140,6 +141,7 @@ static inline void ata_acpi_set_state(struct ata_port *ap,
140141
pm_message_t state) { }
141142
static inline void ata_acpi_bind_port(struct ata_port *ap) {}
142143
static inline void ata_acpi_bind_dev(struct ata_device *dev) {}
144+
static inline void ata_acpi_port_power_on(struct ata_port *ap) {}
143145
#endif
144146

145147
/* libata-scsi.c */

0 commit comments

Comments
 (0)