aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-eh.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-09-01 11:50:06 -0400
committerJeff Garzik <jgarzik@redhat.com>2010-10-21 20:21:04 -0400
commit6b7ae9545ad9875a289f4191c0216b473e313cb9 (patch)
tree216b4db276202d727ba134d256144a6670497180 /drivers/ata/libata-eh.c
parent1152b2617a6e1943b6b82e07c962950e56f1000c (diff)
libata: reimplement link power management
The current LPM implementation has the following issues. * Operation order isn't well thought-out. e.g. HIPM should be configured after IPM in SControl is properly configured. Not the other way around. * Suspend/resume paths call ata_lpm_enable/disable() which must only be called from EH context directly. Also, ata_lpm_enable/disable() were called whether LPM was in use or not. * Implementation is per-port when it should be per-link. As a result, it can't be used for controllers with slave links or PMP. * LPM state isn't managed consistently. After a link reset for whatever reason including suspend/resume the actual LPM state would be reset leaving ap->lpm_policy inconsistent. * Generic/driver-specific logic boundary isn't clear. Currently, libahci has to mangle stuff which libata EH proper should be handling. This makes the implementation unnecessarily complex and fragile. * Tied to ALPM. Doesn't consider DIPM only cases and doesn't check whether the device allows HIPM. * Error handling isn't implemented. Given the extent of mismatch with the rest of libata, I don't think trying to fix it piecewise makes much sense. This patch reimplements LPM support. * The new implementation is per-link. The target policy is still port-wide (ap->target_lpm_policy) but all the mechanisms and states are per-link and integrate well with the rest of link abstraction and can work with slave and PMP links. * Core EH has proper control of LPM state. LPM state is reconfigured when and only when reconfiguration is necessary. It makes sure that LPM state is reset when probing for new device on the link. Controller agnostic logic is now implemented in libata EH proper and driver implementation only has to deal with controller specifics. * Proper error handling. LPM config failure is attributed to the device on the link and LPM is disabled for the link if it fails repeatedly. * ops->enable/disable_pm() are replaced with single ops->set_lpm() which takes @policy and @hints. This simplifies driver specific implementation. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r--drivers/ata/libata-eh.c164
1 files changed, 145 insertions, 19 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 96aa75ddf87f..a645cd3ab163 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1580,9 +1580,9 @@ static void ata_eh_analyze_serror(struct ata_link *link)
1580 * host links. For disabled PMP links, only N bit is 1580 * host links. For disabled PMP links, only N bit is
1581 * considered as X bit is left at 1 for link plugging. 1581 * considered as X bit is left at 1 for link plugging.
1582 */ 1582 */
1583 hotplug_mask = 0; 1583 if (link->lpm_policy != ATA_LPM_MAX_POWER)
1584 1584 hotplug_mask = 0; /* hotplug doesn't work w/ LPM */
1585 if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) 1585 else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
1586 hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; 1586 hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
1587 else 1587 else
1588 hotplug_mask = SERR_PHYRDY_CHG; 1588 hotplug_mask = SERR_PHYRDY_CHG;
@@ -2784,8 +2784,9 @@ int ata_eh_reset(struct ata_link *link, int classify,
2784 ata_eh_done(link, NULL, ATA_EH_RESET); 2784 ata_eh_done(link, NULL, ATA_EH_RESET);
2785 if (slave) 2785 if (slave)
2786 ata_eh_done(slave, NULL, ATA_EH_RESET); 2786 ata_eh_done(slave, NULL, ATA_EH_RESET);
2787 ehc->last_reset = jiffies; /* update to completion time */ 2787 ehc->last_reset = jiffies; /* update to completion time */
2788 ehc->i.action |= ATA_EH_REVALIDATE; 2788 ehc->i.action |= ATA_EH_REVALIDATE;
2789 link->lpm_policy = ATA_LPM_UNKNOWN; /* reset LPM state */
2789 2790
2790 rc = 0; 2791 rc = 0;
2791 out: 2792 out:
@@ -3211,6 +3212,121 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev)
3211 return rc; 3212 return rc;
3212} 3213}
3213 3214
3215/**
3216 * ata_eh_set_lpm - configure SATA interface power management
3217 * @link: link to configure power management
3218 * @policy: the link power management policy
3219 * @r_failed_dev: out parameter for failed device
3220 *
3221 * Enable SATA Interface power management. This will enable
3222 * Device Interface Power Management (DIPM) for min_power
3223 * policy, and then call driver specific callbacks for
3224 * enabling Host Initiated Power management.
3225 *
3226 * LOCKING:
3227 * EH context.
3228 *
3229 * RETURNS:
3230 * 0 on success, -errno on failure.
3231 */
3232static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
3233 struct ata_device **r_failed_dev)
3234{
3235 struct ata_port *ap = link->ap;
3236 struct ata_eh_context *ehc = &link->eh_context;
3237 struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
3238 unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
3239 unsigned int err_mask;
3240 int rc;
3241
3242 /* if the link or host doesn't do LPM, noop */
3243 if ((link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm))
3244 return 0;
3245
3246 /*
3247 * DIPM is enabled only for MIN_POWER as some devices
3248 * misbehave when the host NACKs transition to SLUMBER. Order
3249 * device and link configurations such that the host always
3250 * allows DIPM requests.
3251 */
3252 ata_for_each_dev(dev, link, ENABLED) {
3253 bool hipm = ata_id_has_hipm(dev->id);
3254 bool dipm = ata_id_has_dipm(dev->id);
3255
3256 /* find the first enabled and LPM enabled devices */
3257 if (!link_dev)
3258 link_dev = dev;
3259
3260 if (!lpm_dev && (hipm || dipm))
3261 lpm_dev = dev;
3262
3263 hints &= ~ATA_LPM_EMPTY;
3264 if (!hipm)
3265 hints &= ~ATA_LPM_HIPM;
3266
3267 /* disable DIPM before changing link config */
3268 if (policy != ATA_LPM_MIN_POWER && dipm) {
3269 err_mask = ata_dev_set_feature(dev,
3270 SETFEATURES_SATA_DISABLE, SATA_DIPM);
3271 if (err_mask && err_mask != AC_ERR_DEV) {
3272 ata_dev_printk(dev, KERN_WARNING,
3273 "failed to disable DIPM, Emask 0x%x\n",
3274 err_mask);
3275 rc = -EIO;
3276 goto fail;
3277 }
3278 }
3279 }
3280
3281 rc = ap->ops->set_lpm(link, policy, hints);
3282 if (!rc && ap->slave_link)
3283 rc = ap->ops->set_lpm(ap->slave_link, policy, hints);
3284
3285 /*
3286 * Attribute link config failure to the first (LPM) enabled
3287 * device on the link.
3288 */
3289 if (rc) {
3290 if (rc == -EOPNOTSUPP) {
3291 link->flags |= ATA_LFLAG_NO_LPM;
3292 return 0;
3293 }
3294 dev = lpm_dev ? lpm_dev : link_dev;
3295 goto fail;
3296 }
3297
3298 /* host config updated, enable DIPM if transitioning to MIN_POWER */
3299 ata_for_each_dev(dev, link, ENABLED) {
3300 if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) {
3301 err_mask = ata_dev_set_feature(dev,
3302 SETFEATURES_SATA_ENABLE, SATA_DIPM);
3303 if (err_mask && err_mask != AC_ERR_DEV) {
3304 ata_dev_printk(dev, KERN_WARNING,
3305 "failed to enable DIPM, Emask 0x%x\n",
3306 err_mask);
3307 rc = -EIO;
3308 goto fail;
3309 }
3310 }
3311 }
3312
3313 link->lpm_policy = policy;
3314 if (ap && ap->slave_link)
3315 ap->slave_link->lpm_policy = policy;
3316 return 0;
3317
3318fail:
3319 /* if no device or only one more chance is left, disable LPM */
3320 if (!dev || ehc->tries[dev->devno] <= 2) {
3321 ata_link_printk(link, KERN_WARNING,
3322 "disabling LPM on the link\n");
3323 link->flags |= ATA_LFLAG_NO_LPM;
3324 }
3325 if (r_failed_dev)
3326 *r_failed_dev = dev;
3327 return rc;
3328}
3329
3214static int ata_link_nr_enabled(struct ata_link *link) 3330static int ata_link_nr_enabled(struct ata_link *link)
3215{ 3331{
3216 struct ata_device *dev; 3332 struct ata_device *dev;
@@ -3295,6 +3411,10 @@ static int ata_eh_schedule_probe(struct ata_device *dev)
3295 ehc->saved_xfer_mode[dev->devno] = 0; 3411 ehc->saved_xfer_mode[dev->devno] = 0;
3296 ehc->saved_ncq_enabled &= ~(1 << dev->devno); 3412 ehc->saved_ncq_enabled &= ~(1 << dev->devno);
3297 3413
3414 /* the link maybe in a deep sleep, wake it up */
3415 if (link->lpm_policy > ATA_LPM_MAX_POWER)
3416 link->ap->ops->set_lpm(link, ATA_LPM_MAX_POWER, ATA_LPM_EMPTY);
3417
3298 /* Record and count probe trials on the ering. The specific 3418 /* Record and count probe trials on the ering. The specific
3299 * error mask used is irrelevant. Because a successful device 3419 * error mask used is irrelevant. Because a successful device
3300 * detection clears the ering, this count accumulates only if 3420 * detection clears the ering, this count accumulates only if
@@ -3396,8 +3516,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
3396{ 3516{
3397 struct ata_link *link; 3517 struct ata_link *link;
3398 struct ata_device *dev; 3518 struct ata_device *dev;
3399 int nr_failed_devs; 3519 int rc, nr_fails;
3400 int rc;
3401 unsigned long flags, deadline; 3520 unsigned long flags, deadline;
3402 3521
3403 DPRINTK("ENTER\n"); 3522 DPRINTK("ENTER\n");
@@ -3438,7 +3557,6 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
3438 3557
3439 retry: 3558 retry:
3440 rc = 0; 3559 rc = 0;
3441 nr_failed_devs = 0;
3442 3560
3443 /* if UNLOADING, finish immediately */ 3561 /* if UNLOADING, finish immediately */
3444 if (ap->pflags & ATA_PFLAG_UNLOADING) 3562 if (ap->pflags & ATA_PFLAG_UNLOADING)
@@ -3523,13 +3641,17 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
3523 } 3641 }
3524 3642
3525 /* the rest */ 3643 /* the rest */
3526 ata_for_each_link(link, ap, EDGE) { 3644 nr_fails = 0;
3645 ata_for_each_link(link, ap, PMP_FIRST) {
3527 struct ata_eh_context *ehc = &link->eh_context; 3646 struct ata_eh_context *ehc = &link->eh_context;
3528 3647
3648 if (sata_pmp_attached(ap) && ata_is_host_link(link))
3649 goto config_lpm;
3650
3529 /* revalidate existing devices and attach new ones */ 3651 /* revalidate existing devices and attach new ones */
3530 rc = ata_eh_revalidate_and_attach(link, &dev); 3652 rc = ata_eh_revalidate_and_attach(link, &dev);
3531 if (rc) 3653 if (rc)
3532 goto dev_fail; 3654 goto rest_fail;
3533 3655
3534 /* if PMP got attached, return, pmp EH will take care of it */ 3656 /* if PMP got attached, return, pmp EH will take care of it */
3535 if (link->device->class == ATA_DEV_PMP) { 3657 if (link->device->class == ATA_DEV_PMP) {
@@ -3541,7 +3663,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
3541 if (ehc->i.flags & ATA_EHI_SETMODE) { 3663 if (ehc->i.flags & ATA_EHI_SETMODE) {
3542 rc = ata_set_mode(link, &dev); 3664 rc = ata_set_mode(link, &dev);
3543 if (rc) 3665 if (rc)
3544 goto dev_fail; 3666 goto rest_fail;
3545 ehc->i.flags &= ~ATA_EHI_SETMODE; 3667 ehc->i.flags &= ~ATA_EHI_SETMODE;
3546 } 3668 }
3547 3669
@@ -3554,7 +3676,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
3554 continue; 3676 continue;
3555 rc = atapi_eh_clear_ua(dev); 3677 rc = atapi_eh_clear_ua(dev);
3556 if (rc) 3678 if (rc)
3557 goto dev_fail; 3679 goto rest_fail;
3558 } 3680 }
3559 } 3681 }
3560 3682
@@ -3564,21 +3686,25 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
3564 continue; 3686 continue;
3565 rc = ata_eh_maybe_retry_flush(dev); 3687 rc = ata_eh_maybe_retry_flush(dev);
3566 if (rc) 3688 if (rc)
3567 goto dev_fail; 3689 goto rest_fail;
3568 } 3690 }
3569 3691
3692 config_lpm:
3570 /* configure link power saving */ 3693 /* configure link power saving */
3571 if (ehc->i.action & ATA_EH_LPM) 3694 if (link->lpm_policy != ap->target_lpm_policy) {
3572 ata_for_each_dev(dev, link, ALL) 3695 rc = ata_eh_set_lpm(link, ap->target_lpm_policy, &dev);
3573 ata_dev_enable_pm(dev, ap->lpm_policy); 3696 if (rc)
3697 goto rest_fail;
3698 }
3574 3699
3575 /* this link is okay now */ 3700 /* this link is okay now */
3576 ehc->i.flags = 0; 3701 ehc->i.flags = 0;
3577 continue; 3702 continue;
3578 3703
3579dev_fail: 3704 rest_fail:
3580 nr_failed_devs++; 3705 nr_fails++;
3581 ata_eh_handle_dev_fail(dev, rc); 3706 if (dev)
3707 ata_eh_handle_dev_fail(dev, rc);
3582 3708
3583 if (ap->pflags & ATA_PFLAG_FROZEN) { 3709 if (ap->pflags & ATA_PFLAG_FROZEN) {
3584 /* PMP reset requires working host port. 3710 /* PMP reset requires working host port.
@@ -3590,7 +3716,7 @@ dev_fail:
3590 } 3716 }
3591 } 3717 }
3592 3718
3593 if (nr_failed_devs) 3719 if (nr_fails)
3594 goto retry; 3720 goto retry;
3595 3721
3596 out: 3722 out: