Skip to content

Commit c114a72

Browse files
damien-lemoalgregkh
authored andcommitted
ata: libata-sata: Add link_power_management_supported sysfs attribute
commit 0060bee upstream. A port link power management (LPM) policy can be controlled using the link_power_management_policy sysfs host attribute. However, this attribute exists also for hosts that do not support LPM and in such case, attempting to change the LPM policy for the host (port) will fail with -EOPNOTSUPP. Introduce the new sysfs link_power_management_supported host attribute to indicate to the user if a the port and the devices connected to the port for the host support LPM, which implies that the link_power_management_policy attribute can be used. Since checking that a port and its devices support LPM is common between the new ata_scsi_lpm_supported_show() function and the existing ata_scsi_lpm_store() function, the new helper ata_scsi_lpm_supported() is introduced. Fixes: 413e800 ("ata: libata-sata: Disallow changing LPM state if not supported") Reported-by: Borah, Chaitanya Kumar <[email protected]> Reported-by: kernel test robot <[email protected]> Closes: https://lore.kernel.org/oe-lkp/[email protected] Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Martin K. Petersen <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent dda0f3c commit c114a72

4 files changed

Lines changed: 44 additions & 12 deletions

File tree

drivers/ata/ata_piix.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,7 @@ static struct ata_port_operations ich_pata_ops = {
10891089
};
10901090

10911091
static struct attribute *piix_sidpr_shost_attrs[] = {
1092+
&dev_attr_link_power_management_supported.attr,
10921093
&dev_attr_link_power_management_policy.attr,
10931094
NULL
10941095
};

drivers/ata/libahci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
111111
static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);
112112

113113
static struct attribute *ahci_shost_attrs[] = {
114+
&dev_attr_link_power_management_supported.attr,
114115
&dev_attr_link_power_management_policy.attr,
115116
&dev_attr_em_message_type.attr,
116117
&dev_attr_em_message.attr,

drivers/ata/libata-sata.c

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -900,14 +900,52 @@ static const char *ata_lpm_policy_names[] = {
900900
[ATA_LPM_MIN_POWER] = "min_power",
901901
};
902902

903+
/*
904+
* Check if a port supports link power management.
905+
* Must be called with the port locked.
906+
*/
907+
static bool ata_scsi_lpm_supported(struct ata_port *ap)
908+
{
909+
struct ata_link *link;
910+
struct ata_device *dev;
911+
912+
if (ap->flags & ATA_FLAG_NO_LPM)
913+
return false;
914+
915+
ata_for_each_link(link, ap, EDGE) {
916+
ata_for_each_dev(dev, &ap->link, ENABLED) {
917+
if (dev->quirks & ATA_QUIRK_NOLPM)
918+
return false;
919+
}
920+
}
921+
922+
return true;
923+
}
924+
925+
static ssize_t ata_scsi_lpm_supported_show(struct device *dev,
926+
struct device_attribute *attr, char *buf)
927+
{
928+
struct Scsi_Host *shost = class_to_shost(dev);
929+
struct ata_port *ap = ata_shost_to_port(shost);
930+
unsigned long flags;
931+
bool supported;
932+
933+
spin_lock_irqsave(ap->lock, flags);
934+
supported = ata_scsi_lpm_supported(ap);
935+
spin_unlock_irqrestore(ap->lock, flags);
936+
937+
return sysfs_emit(buf, "%d\n", supported);
938+
}
939+
DEVICE_ATTR(link_power_management_supported, S_IRUGO,
940+
ata_scsi_lpm_supported_show, NULL);
941+
EXPORT_SYMBOL_GPL(dev_attr_link_power_management_supported);
942+
903943
static ssize_t ata_scsi_lpm_store(struct device *device,
904944
struct device_attribute *attr,
905945
const char *buf, size_t count)
906946
{
907947
struct Scsi_Host *shost = class_to_shost(device);
908948
struct ata_port *ap = ata_shost_to_port(shost);
909-
struct ata_link *link;
910-
struct ata_device *dev;
911949
enum ata_lpm_policy policy;
912950
unsigned long flags;
913951

@@ -924,20 +962,11 @@ static ssize_t ata_scsi_lpm_store(struct device *device,
924962

925963
spin_lock_irqsave(ap->lock, flags);
926964

927-
if (ap->flags & ATA_FLAG_NO_LPM) {
965+
if (!ata_scsi_lpm_supported(ap)) {
928966
count = -EOPNOTSUPP;
929967
goto out_unlock;
930968
}
931969

932-
ata_for_each_link(link, ap, EDGE) {
933-
ata_for_each_dev(dev, &ap->link, ENABLED) {
934-
if (dev->quirks & ATA_QUIRK_NOLPM) {
935-
count = -EOPNOTSUPP;
936-
goto out_unlock;
937-
}
938-
}
939-
}
940-
941970
ap->target_lpm_policy = policy;
942971
ata_port_schedule_eh(ap);
943972
out_unlock:

include/linux/libata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes)
534534

535535
extern struct device_attribute dev_attr_unload_heads;
536536
#ifdef CONFIG_SATA_HOST
537+
extern struct device_attribute dev_attr_link_power_management_supported;
537538
extern struct device_attribute dev_attr_link_power_management_policy;
538539
extern struct device_attribute dev_attr_ncq_prio_supported;
539540
extern struct device_attribute dev_attr_ncq_prio_enable;

0 commit comments

Comments
 (0)