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
