The current code performs a SET FEATURES command to disable DIPM if policy < ATA_LPM_MED_POWER_WITH_DIPM, this means that it will disable DIPM for policies: ATA_LPM_UNKNOWN, ATA_LPM_MAX_POWER, ATA_LPM_MED_POWER (but not for policy ATA_LPM_MED_POWER_WITH_DIPM). The code called after calling the set_lpm() callback will later perform a SET FEATURES command to enable DIPM, if policy >= ATA_LPM_MED_POWER_WITH_DIPM It seems very logical to disable DIPM before the set_lpm() callback is called, because the set_lpm() callback is the function (for AHCI) that sets the proper bits in PxSCTL.IPM, reflecting the support of the HBA. PxSCTL.IPM controls the LPM states that the device is allowed to enter. If the device tries to enter a state disabled by PxSCTL.IPM, the host will NAK the transition. It is thus imperative that PxSCTL.IPM is written before DIPM is enabled, to stop the device from entering a state that the host does not support. While AHCI 1.3.1, section "8.3.1.1 Device Initiated" states: """ By default, a device that supports initiating interface power management states has the capability disabled. """ This makes it seem harmless to not disable DIPM before writing PxSCTL.IPM, however, SATA 3.5a section "13.3.4 Enable/disable Device-initiated interface power state transitions feature" states: """ If Software Settings Preservation is enabled and Device Initiated Interface Power Management Software Settings Preservation is supported (see 13.7.11.2.26), then the enable/disable state shall persist across a COMRESET. """ Further SATA 3.5a, section "13.3.7 Enable/disable Software Settings Preservation feature" states that: """ By default, if the device supports software settings preservation, the feature is enabled on power-up. """ Which means that it is possible that DIPM is enabled at probe time, even after ata_eh_reset() has performed a COMRESET, thus, make sure that DIPM is always disabled before calling the set_lpm() callback (which will write PxSCTL.IPM). For a LPM policy that includes DIPM, ata_eh_set_lpm() will still enable DIPM using a SET FEATURES command after the set_lpm() callback has been called (assuming that both the device and host supports DIPM). Signed-off-by: Niklas Cassel <cassel@xxxxxxxxxx> --- drivers/ata/libata-eh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 91d97d98eed1..1727248f135d 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3473,7 +3473,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, hints &= ~ATA_LPM_HIPM; /* disable DIPM before changing link config */ - if (policy < ATA_LPM_MED_POWER_WITH_DIPM && dev_has_dipm) { + if (dev_has_dipm) { err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_DISABLE, SATA_DIPM); if (err_mask && err_mask != AC_ERR_DEV) { -- 2.49.0