From: Damien Le Moal dlemoal@kernel.org
[ Upstream commit 65b2c92f69d3df81422d27e5be012e357e733241 ]
Commit fa997b0576c9 ("ata: ahci: Do not enable LPM if no LPM states are supported by the HBA") introduced an early return in ahci_update_initial_lpm_policy() to ensure that the target_lpm_policy of ports belonging to a host that does not support the Partial, Slumber and DevSleep power states is unchanged and remains set to ATA_LPM_UNKNOWN and thus prevents the execution of ata_eh_link_set_lpm().
However, a user or a system daemon (e.g. systemd-udevd) may still attempt changing the LPM policy through the sysfs link_power_management_policy of the host.
Improve this to prevent sysfs LPM policy changes by setting the flag ATA_FLAG_NO_LPM for the port of such host, and initialize the port target_lpm_policy to ATA_LPM_MAX_POWER to guarantee that no unsupported low power state is being used on the port and its link.
Signed-off-by: Damien Le Moal dlemoal@kernel.org Reviewed-by: Hannes Reinecke hare@suse.de Reviewed-by: Niklas Cassel cassel@kernel.org Link: https://lore.kernel.org/r/20250701125321.69496-9-dlemoal@kernel.org Signed-off-by: Niklas Cassel cassel@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
Based on my analysis of the commit message, code changes, and examination of the kernel repository context, I can provide the following assessment:
**Backport Status: YES**
This commit should be backported to stable kernel trees for the following reasons:
1. **Bug Fix Nature**: This commit fixes a real bug where users could still change LPM (Link Power Management) policy through sysfs even when the hardware doesn't support any LPM states. The original commit fa997b0576c9 only prevented automatic LPM enablement but didn't block manual sysfs changes.
2. **User-Visible Issue**: The commit message explicitly mentions that "a user or a system daemon (e.g. systemd-udevd) may still attempt changing the LPM policy through the sysfs link_power_management_policy". This is a user-visible issue that could lead to unexpected behavior or system instability.
3. **Small and Contained Fix**: The code changes are minimal and well- contained: - Only adds 2 lines setting `ATA_FLAG_NO_LPM` flag and `target_lpm_policy = ATA_LPM_MAX_POWER` - Changes one debug message from "not enabling LPM" to "forcing LPM max_power" - The fix is localized to the `ahci_update_initial_lpm_policy()` function
4. **Follows Established Pattern**: The code already uses this exact same pattern for external ports (lines above show `ap->flags |= ATA_FLAG_NO_LPM; ap->target_lpm_policy = ATA_LPM_MAX_POWER;`), so this is extending an existing, proven approach.
5. **Prevents Invalid Configuration**: Looking at the sysfs handler `ata_scsi_lpm_store()` in libata-sata.c, it checks for `ATA_FLAG_NO_LPM` and returns `-EOPNOTSUPP`, which is the correct behavior this patch enables for unsupported hardware.
6. **Builds on Previous Stable Fix**: The referenced commit fa997b0576c9 was already marked for stable ("Cc: stable@vger.kernel.org"), and this commit completes that fix by closing the remaining gap.
7. **Low Risk**: The change has minimal risk of regression since it only affects hardware that doesn't support any LPM states, and for such hardware, preventing LPM policy changes is the correct behavior.
The commit follows stable kernel rules by fixing an important bug with minimal changes and low regression risk, making it an ideal candidate for stable backporting.
drivers/ata/ahci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a6a66d794763..61d34ca0d9f4 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1785,7 +1785,10 @@ static void ahci_update_initial_lpm_policy(struct ata_port *ap) if ((ap->host->flags & ATA_HOST_NO_PART) && (ap->host->flags & ATA_HOST_NO_SSC) && (ap->host->flags & ATA_HOST_NO_DEVSLP)) { - ata_port_dbg(ap, "no LPM states supported, not enabling LPM\n"); + ata_port_dbg(ap, + "No LPM states supported, forcing LPM max_power\n"); + ap->flags |= ATA_FLAG_NO_LPM; + ap->target_lpm_policy = ATA_LPM_MAX_POWER; return; }