Skip to content

Commit 8c59fc1

Browse files
0xIO32martinkpetersen
authored andcommitted
scsi: ata: Stop disk on restart if ACPI power resources are found
Some embedded devices have the ability to control whether power is provided to the disks via the SATA power connector or not. ACPI power resources are usually off by default, thus making it unclear if the specific power resource will retain its state after a restart. If power resources are defined on ATA ports / devices in ACPI, we should stop the disk on SYSTEM_RESTART, to ensure the disk will not lose power while active. Add a new function, ata_acpi_dev_manage_restart(), that will be used to determine if a disk should be stopped before restarting the system. If a usable ACPI power resource has been found, it is assumed that the disk will lose power after a restart and should be stopped to avoid unclean shutdown due to power loss. Reviewed-by: Damien Le Moal <dlemoal@kernel.org> Signed-off-by: Markus Probst <markus.probst@posteo.de> Link: https://patch.msgid.link/20251104142413.322347-4-markus.probst@posteo.de Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent ce6d26b commit 8c59fc1

3 files changed

Lines changed: 29 additions & 0 deletions

File tree

drivers/ata/libata-acpi.c

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

248+
/**
249+
* ata_acpi_dev_manage_restart - if the disk should be stopped (spun down) on
250+
* system restart.
251+
* @dev: target ATA device
252+
*
253+
* RETURNS:
254+
* true if the disk should be stopped, otherwise false.
255+
*/
256+
bool ata_acpi_dev_manage_restart(struct ata_device *dev)
257+
{
258+
struct device *tdev;
259+
260+
/*
261+
* If ATA_FLAG_ACPI_SATA is set, the acpi fwnode is attached to the
262+
* ata_device instead of the ata_port.
263+
*/
264+
if (dev->link->ap->flags & ATA_FLAG_ACPI_SATA)
265+
tdev = &dev->tdev;
266+
else
267+
tdev = &dev->link->ap->tdev;
268+
269+
if (!is_acpi_device_node(tdev->fwnode))
270+
return false;
271+
return acpi_bus_power_manageable(ACPI_HANDLE(tdev));
272+
}
273+
248274
/**
249275
* ata_acpi_port_power_on - set the power state of the ata port to D0
250276
* @ap: target ATA port

drivers/ata/libata-scsi.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,7 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct queue_limits *lim,
10951095
*/
10961096
sdev->manage_runtime_start_stop = 1;
10971097
sdev->manage_shutdown = 1;
1098+
sdev->manage_restart = ata_acpi_dev_manage_restart(dev);
10981099
sdev->force_runtime_start_on_system_start = 1;
10991100
}
11001101

drivers/ata/libata.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ 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);
133133
extern void ata_acpi_port_power_on(struct ata_port *ap);
134+
extern bool ata_acpi_dev_manage_restart(struct ata_device *dev);
134135
extern acpi_handle ata_dev_acpi_handle(struct ata_device *dev);
135136
#else
136137
static inline void ata_acpi_dissociate(struct ata_host *host) { }
@@ -142,6 +143,7 @@ static inline void ata_acpi_set_state(struct ata_port *ap,
142143
static inline void ata_acpi_bind_port(struct ata_port *ap) {}
143144
static inline void ata_acpi_bind_dev(struct ata_device *dev) {}
144145
static inline void ata_acpi_port_power_on(struct ata_port *ap) {}
146+
static inline bool ata_acpi_dev_manage_restart(struct ata_device *dev) { return 0; }
145147
#endif
146148

147149
/* libata-scsi.c */

0 commit comments

Comments
 (0)