diff options
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 6780f4d16e81..5e590504f3aa 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -463,6 +463,41 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev, | |||
463 | } | 463 | } |
464 | 464 | ||
465 | /** | 465 | /** |
466 | * ata_eh_acquire - acquire EH ownership | ||
467 | * @ap: ATA port to acquire EH ownership for | ||
468 | * | ||
469 | * Acquire EH ownership for @ap. This is the basic exclusion | ||
470 | * mechanism for ports sharing a host. Only one port hanging off | ||
471 | * the same host can claim the ownership of EH. | ||
472 | * | ||
473 | * LOCKING: | ||
474 | * EH context. | ||
475 | */ | ||
476 | void ata_eh_acquire(struct ata_port *ap) | ||
477 | { | ||
478 | mutex_lock(&ap->host->eh_mutex); | ||
479 | WARN_ON_ONCE(ap->host->eh_owner); | ||
480 | ap->host->eh_owner = current; | ||
481 | } | ||
482 | |||
483 | /** | ||
484 | * ata_eh_release - release EH ownership | ||
485 | * @ap: ATA port to release EH ownership for | ||
486 | * | ||
487 | * Release EH ownership for @ap if the caller. The caller must | ||
488 | * have acquired EH ownership using ata_eh_acquire() previously. | ||
489 | * | ||
490 | * LOCKING: | ||
491 | * EH context. | ||
492 | */ | ||
493 | void ata_eh_release(struct ata_port *ap) | ||
494 | { | ||
495 | WARN_ON_ONCE(ap->host->eh_owner != current); | ||
496 | ap->host->eh_owner = NULL; | ||
497 | mutex_unlock(&ap->host->eh_mutex); | ||
498 | } | ||
499 | |||
500 | /** | ||
466 | * ata_scsi_timed_out - SCSI layer time out callback | 501 | * ata_scsi_timed_out - SCSI layer time out callback |
467 | * @cmd: timed out SCSI command | 502 | * @cmd: timed out SCSI command |
468 | * | 503 | * |
@@ -639,11 +674,13 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
639 | /* If we timed raced normal completion and there is nothing to | 674 | /* If we timed raced normal completion and there is nothing to |
640 | recover nr_timedout == 0 why exactly are we doing error recovery ? */ | 675 | recover nr_timedout == 0 why exactly are we doing error recovery ? */ |
641 | 676 | ||
642 | repeat: | ||
643 | /* invoke error handler */ | 677 | /* invoke error handler */ |
644 | if (ap->ops->error_handler) { | 678 | if (ap->ops->error_handler) { |
645 | struct ata_link *link; | 679 | struct ata_link *link; |
646 | 680 | ||
681 | /* acquire EH ownership */ | ||
682 | ata_eh_acquire(ap); | ||
683 | repeat: | ||
647 | /* kill fast drain timer */ | 684 | /* kill fast drain timer */ |
648 | del_timer_sync(&ap->fastdrain_timer); | 685 | del_timer_sync(&ap->fastdrain_timer); |
649 | 686 | ||
@@ -718,6 +755,7 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
718 | host->host_eh_scheduled = 0; | 755 | host->host_eh_scheduled = 0; |
719 | 756 | ||
720 | spin_unlock_irqrestore(ap->lock, flags); | 757 | spin_unlock_irqrestore(ap->lock, flags); |
758 | ata_eh_release(ap); | ||
721 | } else { | 759 | } else { |
722 | WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL); | 760 | WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL); |
723 | ap->ops->eng_timeout(ap); | 761 | ap->ops->eng_timeout(ap); |
@@ -2818,8 +2856,10 @@ int ata_eh_reset(struct ata_link *link, int classify, | |||
2818 | "reset failed (errno=%d), retrying in %u secs\n", | 2856 | "reset failed (errno=%d), retrying in %u secs\n", |
2819 | rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000)); | 2857 | rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000)); |
2820 | 2858 | ||
2859 | ata_eh_release(ap); | ||
2821 | while (delta) | 2860 | while (delta) |
2822 | delta = schedule_timeout_uninterruptible(delta); | 2861 | delta = schedule_timeout_uninterruptible(delta); |
2862 | ata_eh_acquire(ap); | ||
2823 | } | 2863 | } |
2824 | 2864 | ||
2825 | if (try == max_tries - 1) { | 2865 | if (try == max_tries - 1) { |
@@ -3635,8 +3675,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
3635 | if (time_before_eq(deadline, now)) | 3675 | if (time_before_eq(deadline, now)) |
3636 | break; | 3676 | break; |
3637 | 3677 | ||
3678 | ata_eh_release(ap); | ||
3638 | deadline = wait_for_completion_timeout(&ap->park_req_pending, | 3679 | deadline = wait_for_completion_timeout(&ap->park_req_pending, |
3639 | deadline - now); | 3680 | deadline - now); |
3681 | ata_eh_acquire(ap); | ||
3640 | } while (deadline); | 3682 | } while (deadline); |
3641 | ata_for_each_link(link, ap, EDGE) { | 3683 | ata_for_each_link(link, ap, EDGE) { |
3642 | ata_for_each_dev(dev, link, ALL) { | 3684 | ata_for_each_dev(dev, link, ALL) { |