diff options
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 126 |
1 files changed, 125 insertions, 1 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 99037a4860d9..33ac5ea4f531 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -2536,6 +2536,80 @@ int ata_eh_reset(struct ata_link *link, int classify, | |||
2536 | goto retry; | 2536 | goto retry; |
2537 | } | 2537 | } |
2538 | 2538 | ||
2539 | static inline void ata_eh_pull_park_action(struct ata_port *ap) | ||
2540 | { | ||
2541 | struct ata_link *link; | ||
2542 | struct ata_device *dev; | ||
2543 | unsigned long flags; | ||
2544 | |||
2545 | /* | ||
2546 | * This function can be thought of as an extended version of | ||
2547 | * ata_eh_about_to_do() specially crafted to accommodate the | ||
2548 | * requirements of ATA_EH_PARK handling. Since the EH thread | ||
2549 | * does not leave the do {} while () loop in ata_eh_recover as | ||
2550 | * long as the timeout for a park request to *one* device on | ||
2551 | * the port has not expired, and since we still want to pick | ||
2552 | * up park requests to other devices on the same port or | ||
2553 | * timeout updates for the same device, we have to pull | ||
2554 | * ATA_EH_PARK actions from eh_info into eh_context.i | ||
2555 | * ourselves at the beginning of each pass over the loop. | ||
2556 | * | ||
2557 | * Additionally, all write accesses to &ap->park_req_pending | ||
2558 | * through INIT_COMPLETION() (see below) or complete_all() | ||
2559 | * (see ata_scsi_park_store()) are protected by the host lock. | ||
2560 | * As a result we have that park_req_pending.done is zero on | ||
2561 | * exit from this function, i.e. when ATA_EH_PARK actions for | ||
2562 | * *all* devices on port ap have been pulled into the | ||
2563 | * respective eh_context structs. If, and only if, | ||
2564 | * park_req_pending.done is non-zero by the time we reach | ||
2565 | * wait_for_completion_timeout(), another ATA_EH_PARK action | ||
2566 | * has been scheduled for at least one of the devices on port | ||
2567 | * ap and we have to cycle over the do {} while () loop in | ||
2568 | * ata_eh_recover() again. | ||
2569 | */ | ||
2570 | |||
2571 | spin_lock_irqsave(ap->lock, flags); | ||
2572 | INIT_COMPLETION(ap->park_req_pending); | ||
2573 | ata_port_for_each_link(link, ap) { | ||
2574 | ata_link_for_each_dev(dev, link) { | ||
2575 | struct ata_eh_info *ehi = &link->eh_info; | ||
2576 | |||
2577 | link->eh_context.i.dev_action[dev->devno] |= | ||
2578 | ehi->dev_action[dev->devno] & ATA_EH_PARK; | ||
2579 | ata_eh_clear_action(link, dev, ehi, ATA_EH_PARK); | ||
2580 | } | ||
2581 | } | ||
2582 | spin_unlock_irqrestore(ap->lock, flags); | ||
2583 | } | ||
2584 | |||
2585 | static void ata_eh_park_issue_cmd(struct ata_device *dev, int park) | ||
2586 | { | ||
2587 | struct ata_eh_context *ehc = &dev->link->eh_context; | ||
2588 | struct ata_taskfile tf; | ||
2589 | unsigned int err_mask; | ||
2590 | |||
2591 | ata_tf_init(dev, &tf); | ||
2592 | if (park) { | ||
2593 | ehc->unloaded_mask |= 1 << dev->devno; | ||
2594 | tf.command = ATA_CMD_IDLEIMMEDIATE; | ||
2595 | tf.feature = 0x44; | ||
2596 | tf.lbal = 0x4c; | ||
2597 | tf.lbam = 0x4e; | ||
2598 | tf.lbah = 0x55; | ||
2599 | } else { | ||
2600 | ehc->unloaded_mask &= ~(1 << dev->devno); | ||
2601 | tf.command = ATA_CMD_CHK_POWER; | ||
2602 | } | ||
2603 | |||
2604 | tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; | ||
2605 | tf.protocol |= ATA_PROT_NODATA; | ||
2606 | err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); | ||
2607 | if (park && (err_mask || tf.lbal != 0xc4)) { | ||
2608 | ata_dev_printk(dev, KERN_ERR, "head unload failed!\n"); | ||
2609 | ehc->unloaded_mask &= ~(1 << dev->devno); | ||
2610 | } | ||
2611 | } | ||
2612 | |||
2539 | static int ata_eh_revalidate_and_attach(struct ata_link *link, | 2613 | static int ata_eh_revalidate_and_attach(struct ata_link *link, |
2540 | struct ata_device **r_failed_dev) | 2614 | struct ata_device **r_failed_dev) |
2541 | { | 2615 | { |
@@ -2845,7 +2919,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
2845 | struct ata_device *dev; | 2919 | struct ata_device *dev; |
2846 | int nr_failed_devs; | 2920 | int nr_failed_devs; |
2847 | int rc; | 2921 | int rc; |
2848 | unsigned long flags; | 2922 | unsigned long flags, deadline; |
2849 | 2923 | ||
2850 | DPRINTK("ENTER\n"); | 2924 | DPRINTK("ENTER\n"); |
2851 | 2925 | ||
@@ -2919,6 +2993,56 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
2919 | } | 2993 | } |
2920 | } | 2994 | } |
2921 | 2995 | ||
2996 | do { | ||
2997 | unsigned long now; | ||
2998 | |||
2999 | /* | ||
3000 | * clears ATA_EH_PARK in eh_info and resets | ||
3001 | * ap->park_req_pending | ||
3002 | */ | ||
3003 | ata_eh_pull_park_action(ap); | ||
3004 | |||
3005 | deadline = jiffies; | ||
3006 | ata_port_for_each_link(link, ap) { | ||
3007 | ata_link_for_each_dev(dev, link) { | ||
3008 | struct ata_eh_context *ehc = &link->eh_context; | ||
3009 | unsigned long tmp; | ||
3010 | |||
3011 | if (dev->class != ATA_DEV_ATA) | ||
3012 | continue; | ||
3013 | if (!(ehc->i.dev_action[dev->devno] & | ||
3014 | ATA_EH_PARK)) | ||
3015 | continue; | ||
3016 | tmp = dev->unpark_deadline; | ||
3017 | if (time_before(deadline, tmp)) | ||
3018 | deadline = tmp; | ||
3019 | else if (time_before_eq(tmp, jiffies)) | ||
3020 | continue; | ||
3021 | if (ehc->unloaded_mask & (1 << dev->devno)) | ||
3022 | continue; | ||
3023 | |||
3024 | ata_eh_park_issue_cmd(dev, 1); | ||
3025 | } | ||
3026 | } | ||
3027 | |||
3028 | now = jiffies; | ||
3029 | if (time_before_eq(deadline, now)) | ||
3030 | break; | ||
3031 | |||
3032 | deadline = wait_for_completion_timeout(&ap->park_req_pending, | ||
3033 | deadline - now); | ||
3034 | } while (deadline); | ||
3035 | ata_port_for_each_link(link, ap) { | ||
3036 | ata_link_for_each_dev(dev, link) { | ||
3037 | if (!(link->eh_context.unloaded_mask & | ||
3038 | (1 << dev->devno))) | ||
3039 | continue; | ||
3040 | |||
3041 | ata_eh_park_issue_cmd(dev, 0); | ||
3042 | ata_eh_done(link, dev, ATA_EH_PARK); | ||
3043 | } | ||
3044 | } | ||
3045 | |||
2922 | /* the rest */ | 3046 | /* the rest */ |
2923 | ata_port_for_each_link(link, ap) { | 3047 | ata_port_for_each_link(link, ap) { |
2924 | struct ata_eh_context *ehc = &link->eh_context; | 3048 | struct ata_eh_context *ehc = &link->eh_context; |