summaryrefslogtreecommitdiff
path: root/drivers/ata/libata-acpi.c
diff options
context:
space:
mode:
authorMarkus Probst <markus.probst@posteo.de>2025-11-04 14:24:33 +0000
committerMartin K. Petersen <martin.petersen@oracle.com>2025-11-08 13:24:55 -0500
commitce6d26b5330c5de4f458143e9675984e367f6a40 (patch)
treed20e66b0875691a54117b0d6e74d5b19e7475a70 /drivers/ata/libata-acpi.c
parent8fdfdb1488162c195f3f0af10b7bc2b8b42928c5 (diff)
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>
Diffstat (limited to 'drivers/ata/libata-acpi.c')
-rw-r--r--drivers/ata/libata-acpi.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index f2140fc06ba0..4782e0f22d7f 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -246,6 +246,47 @@ void ata_acpi_bind_dev(struct ata_device *dev)
}
/**
+ * ata_acpi_port_power_on - set the power state of the ata port to D0
+ * @ap: target ATA port
+ *
+ * This function is called at the beginning of ata_port_probe().
+ */
+void ata_acpi_port_power_on(struct ata_port *ap)
+{
+ acpi_handle handle;
+ int i;
+
+ /*
+ * If ATA_FLAG_ACPI_SATA is set, the acpi fwnode is attached to the
+ * ata_device instead of the ata_port.
+ */
+ if (ap->flags & ATA_FLAG_ACPI_SATA) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->link.device[i];
+
+ if (!is_acpi_device_node(dev->tdev.fwnode))
+ continue;
+ handle = ACPI_HANDLE(&dev->tdev);
+ if (!acpi_bus_power_manageable(handle))
+ continue;
+ if (acpi_bus_set_power(handle, ACPI_STATE_D0))
+ ata_dev_err(dev,
+ "acpi: failed to set power state to D0\n");
+ }
+ return;
+ }
+
+ if (!is_acpi_device_node(ap->tdev.fwnode))
+ return;
+ handle = ACPI_HANDLE(&ap->tdev);
+ if (!acpi_bus_power_manageable(handle))
+ return;
+
+ if (acpi_bus_set_power(handle, ACPI_STATE_D0))
+ ata_port_err(ap, "acpi: failed to set power state to D0\n");
+}
+
+/**
* ata_acpi_dissociate - dissociate ATA host from ACPI objects
* @host: target ATA host
*