Skip to content

Commit c53a741

Browse files
Merge patch series "Support power resources defined in acpi on ata"
Markus Probst <markus.probst@posteo.de> says: This series adds support for power resources defined in acpi on ata ports/devices. A device can define a power resource in an ata port/device, which then gets powered on right before the port is probed. This can be useful for devices, which have sata power connectors that are: a: powered down by default b: can be individually powered on like in some synology nas devices. If thats the case it will be assumed, that the power resource won't survive reboots and therefore the disk will be stopped. Link: https://patch.msgid.link/20251104142413.322347-1-markus.probst@posteo.de Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2 parents 5b5dedf + 8c59fc1 commit c53a741

6 files changed

Lines changed: 113 additions & 1 deletion

File tree

drivers/ata/libata-acpi.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,73 @@ 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+
274+
/**
275+
* ata_acpi_port_power_on - set the power state of the ata port to D0
276+
* @ap: target ATA port
277+
*
278+
* This function is called at the beginning of ata_port_probe().
279+
*/
280+
void ata_acpi_port_power_on(struct ata_port *ap)
281+
{
282+
acpi_handle handle;
283+
int i;
284+
285+
/*
286+
* If ATA_FLAG_ACPI_SATA is set, the acpi fwnode is attached to the
287+
* ata_device instead of the ata_port.
288+
*/
289+
if (ap->flags & ATA_FLAG_ACPI_SATA) {
290+
for (i = 0; i < ATA_MAX_DEVICES; i++) {
291+
struct ata_device *dev = &ap->link.device[i];
292+
293+
if (!is_acpi_device_node(dev->tdev.fwnode))
294+
continue;
295+
handle = ACPI_HANDLE(&dev->tdev);
296+
if (!acpi_bus_power_manageable(handle))
297+
continue;
298+
if (acpi_bus_set_power(handle, ACPI_STATE_D0))
299+
ata_dev_err(dev,
300+
"acpi: failed to set power state to D0\n");
301+
}
302+
return;
303+
}
304+
305+
if (!is_acpi_device_node(ap->tdev.fwnode))
306+
return;
307+
handle = ACPI_HANDLE(&ap->tdev);
308+
if (!acpi_bus_power_manageable(handle))
309+
return;
310+
311+
if (acpi_bus_set_power(handle, ACPI_STATE_D0))
312+
ata_port_err(ap, "acpi: failed to set power state to D0\n");
313+
}
314+
248315
/**
249316
* ata_acpi_dissociate - dissociate ATA host from ACPI objects
250317
* @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-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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ 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);
134+
extern bool ata_acpi_dev_manage_restart(struct ata_device *dev);
133135
extern acpi_handle ata_dev_acpi_handle(struct ata_device *dev);
134136
#else
135137
static inline void ata_acpi_dissociate(struct ata_host *host) { }
@@ -140,6 +142,8 @@ static inline void ata_acpi_set_state(struct ata_port *ap,
140142
pm_message_t state) { }
141143
static inline void ata_acpi_bind_port(struct ata_port *ap) {}
142144
static inline void ata_acpi_bind_dev(struct ata_device *dev) {}
145+
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; }
143147
#endif
144148

145149
/* libata-scsi.c */

drivers/scsi/sd.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,35 @@ static ssize_t manage_shutdown_store(struct device *dev,
318318
}
319319
static DEVICE_ATTR_RW(manage_shutdown);
320320

321+
static ssize_t manage_restart_show(struct device *dev,
322+
struct device_attribute *attr, char *buf)
323+
{
324+
struct scsi_disk *sdkp = to_scsi_disk(dev);
325+
struct scsi_device *sdp = sdkp->device;
326+
327+
return sysfs_emit(buf, "%u\n", sdp->manage_restart);
328+
}
329+
330+
static ssize_t manage_restart_store(struct device *dev,
331+
struct device_attribute *attr,
332+
const char *buf, size_t count)
333+
{
334+
struct scsi_disk *sdkp = to_scsi_disk(dev);
335+
struct scsi_device *sdp = sdkp->device;
336+
bool v;
337+
338+
if (!capable(CAP_SYS_ADMIN))
339+
return -EACCES;
340+
341+
if (kstrtobool(buf, &v))
342+
return -EINVAL;
343+
344+
sdp->manage_restart = v;
345+
346+
return count;
347+
}
348+
static DEVICE_ATTR_RW(manage_restart);
349+
321350
static ssize_t
322351
allow_restart_show(struct device *dev, struct device_attribute *attr, char *buf)
323352
{
@@ -654,6 +683,7 @@ static struct attribute *sd_disk_attrs[] = {
654683
&dev_attr_manage_system_start_stop.attr,
655684
&dev_attr_manage_runtime_start_stop.attr,
656685
&dev_attr_manage_shutdown.attr,
686+
&dev_attr_manage_restart.attr,
657687
&dev_attr_protection_type.attr,
658688
&dev_attr_protection_mode.attr,
659689
&dev_attr_app_tag_own.attr,
@@ -4177,7 +4207,9 @@ static void sd_shutdown(struct device *dev)
41774207
(system_state == SYSTEM_POWER_OFF &&
41784208
sdkp->device->manage_shutdown) ||
41794209
(system_state == SYSTEM_RUNNING &&
4180-
sdkp->device->manage_runtime_start_stop)) {
4210+
sdkp->device->manage_runtime_start_stop) ||
4211+
(system_state == SYSTEM_RESTART &&
4212+
sdkp->device->manage_restart)) {
41814213
sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
41824214
sd_start_stop_device(sdkp, 0);
41834215
}

include/scsi/scsi_device.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ struct scsi_device {
178178
*/
179179
unsigned manage_shutdown:1;
180180

181+
/*
182+
* If true, let the high-level device driver (sd) manage the device
183+
* power state for system restart (reboot) operations.
184+
*/
185+
unsigned manage_restart:1;
186+
181187
/*
182188
* If set and if the device is runtime suspended, ask the high-level
183189
* device driver (sd) to force a runtime resume of the device.

0 commit comments

Comments
 (0)