This patch doesn't apply to the .36 stable tree
If someone wants it applied there, please email the backport
to [email protected]

thanks,

greg k-h

> commit: e5005b15c91f3362036067bde5210d5c78af2f0d
> From: Tejun Heo <[email protected]>
> Date: Thu, 9 Dec 2010 16:13:15 +0100
> Subject: [PATCH] libata: issue DIPM enable commands with LPM state updated
> 
> Low level drivers may behave differently depending on the current
> link->lpm_policy.  During ata_eh_set_lpm(), DIPM enable commands are
> issued after the successful completion of ap->ops->set_lpm(), which
> means that the controller is already in the target state.  This causes
> DIPM enable commands to be processed with mismatching controller power
> state and link->lpm_policy value.
> 
> In ahci, link->lpm_policy is used to ignore certain PHY events if LPM
> is enabled; however, as DIPM commands are issued with stale
> link->lpm_policy, they sometimes end up triggering these conditions
> and get aborted leading to LPM configuration failure.
> 
> Fix it by updating link->lpm_policy before issuing DIPM enable
> commands.
> 
> Signed-off-by: Tejun Heo <[email protected]>
> Reported-by: Kyle McMartin <[email protected]>
> Cc: [email protected]
> Signed-off-by: Jeff Garzik <[email protected]>
> ---
>  drivers/ata/libata-eh.c |   17 ++++++++++++++---
>  1 files changed, 14 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
> index 5e59050..17a6378 100644
> --- a/drivers/ata/libata-eh.c
> +++ b/drivers/ata/libata-eh.c
> @@ -3275,6 +3275,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum 
> ata_lpm_policy policy,
>       struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL;
>       struct ata_eh_context *ehc = &link->eh_context;
>       struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
> +     enum ata_lpm_policy old_policy = link->lpm_policy;
>       unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
>       unsigned int err_mask;
>       int rc;
> @@ -3338,6 +3339,14 @@ static int ata_eh_set_lpm(struct ata_link *link, enum 
> ata_lpm_policy policy,
>               goto fail;
>       }
>  
> +     /*
> +      * Low level driver acked the transition.  Issue DIPM command
> +      * with the new policy set.
> +      */
> +     link->lpm_policy = policy;
> +     if (ap && ap->slave_link)
> +             ap->slave_link->lpm_policy = policy;
> +
>       /* host config updated, enable DIPM if transitioning to MIN_POWER */
>       ata_for_each_dev(dev, link, ENABLED) {
>               if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) {
> @@ -3353,12 +3362,14 @@ static int ata_eh_set_lpm(struct ata_link *link, enum 
> ata_lpm_policy policy,
>               }
>       }
>  
> -     link->lpm_policy = policy;
> -     if (ap && ap->slave_link)
> -             ap->slave_link->lpm_policy = policy;
>       return 0;
>  
>  fail:
> +     /* restore the old policy */
> +     link->lpm_policy = old_policy;
> +     if (ap && ap->slave_link)
> +             ap->slave_link->lpm_policy = old_policy;
> +
>       /* if no device or only one more chance is left, disable LPM */
>       if (!dev || ehc->tries[dev->devno] <= 2) {
>               ata_link_printk(link, KERN_WARNING,
> 
> _______________________________________________
> stable mailing list
> [email protected]
> http://linux.kernel.org/mailman/listinfo/stable

_______________________________________________
stable mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/stable

Reply via email to