diff options
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 60 |
1 files changed, 50 insertions, 10 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 17a637877d0..df3f3140c9c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -587,11 +587,43 @@ static void ata_eh_unload(struct ata_port *ap) | |||
587 | void ata_scsi_error(struct Scsi_Host *host) | 587 | void ata_scsi_error(struct Scsi_Host *host) |
588 | { | 588 | { |
589 | struct ata_port *ap = ata_shost_to_port(host); | 589 | struct ata_port *ap = ata_shost_to_port(host); |
590 | int i; | ||
591 | unsigned long flags; | 590 | unsigned long flags; |
591 | LIST_HEAD(eh_work_q); | ||
592 | 592 | ||
593 | DPRINTK("ENTER\n"); | 593 | DPRINTK("ENTER\n"); |
594 | 594 | ||
595 | spin_lock_irqsave(host->host_lock, flags); | ||
596 | list_splice_init(&host->eh_cmd_q, &eh_work_q); | ||
597 | spin_unlock_irqrestore(host->host_lock, flags); | ||
598 | |||
599 | ata_scsi_cmd_error_handler(host, ap, &eh_work_q); | ||
600 | |||
601 | /* If we timed raced normal completion and there is nothing to | ||
602 | recover nr_timedout == 0 why exactly are we doing error recovery ? */ | ||
603 | ata_scsi_port_error_handler(host, ap); | ||
604 | |||
605 | /* finish or retry handled scmd's and clean up */ | ||
606 | WARN_ON(host->host_failed || !list_empty(&eh_work_q)); | ||
607 | |||
608 | DPRINTK("EXIT\n"); | ||
609 | } | ||
610 | |||
611 | /** | ||
612 | * ata_scsi_cmd_error_handler - error callback for a list of commands | ||
613 | * @host: scsi host containing the port | ||
614 | * @ap: ATA port within the host | ||
615 | * @eh_work_q: list of commands to process | ||
616 | * | ||
617 | * process the given list of commands and return those finished to the | ||
618 | * ap->eh_done_q. This function is the first part of the libata error | ||
619 | * handler which processes a given list of failed commands. | ||
620 | */ | ||
621 | void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, | ||
622 | struct list_head *eh_work_q) | ||
623 | { | ||
624 | int i; | ||
625 | unsigned long flags; | ||
626 | |||
595 | /* make sure sff pio task is not running */ | 627 | /* make sure sff pio task is not running */ |
596 | ata_sff_flush_pio_task(ap); | 628 | ata_sff_flush_pio_task(ap); |
597 | 629 | ||
@@ -627,7 +659,7 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
627 | if (ap->ops->lost_interrupt) | 659 | if (ap->ops->lost_interrupt) |
628 | ap->ops->lost_interrupt(ap); | 660 | ap->ops->lost_interrupt(ap); |
629 | 661 | ||
630 | list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) { | 662 | list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) { |
631 | struct ata_queued_cmd *qc; | 663 | struct ata_queued_cmd *qc; |
632 | 664 | ||
633 | for (i = 0; i < ATA_MAX_QUEUE; i++) { | 665 | for (i = 0; i < ATA_MAX_QUEUE; i++) { |
@@ -671,8 +703,20 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
671 | } else | 703 | } else |
672 | spin_unlock_wait(ap->lock); | 704 | spin_unlock_wait(ap->lock); |
673 | 705 | ||
674 | /* If we timed raced normal completion and there is nothing to | 706 | } |
675 | recover nr_timedout == 0 why exactly are we doing error recovery ? */ | 707 | EXPORT_SYMBOL(ata_scsi_cmd_error_handler); |
708 | |||
709 | /** | ||
710 | * ata_scsi_port_error_handler - recover the port after the commands | ||
711 | * @host: SCSI host containing the port | ||
712 | * @ap: the ATA port | ||
713 | * | ||
714 | * Handle the recovery of the port @ap after all the commands | ||
715 | * have been recovered. | ||
716 | */ | ||
717 | void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) | ||
718 | { | ||
719 | unsigned long flags; | ||
676 | 720 | ||
677 | /* invoke error handler */ | 721 | /* invoke error handler */ |
678 | if (ap->ops->error_handler) { | 722 | if (ap->ops->error_handler) { |
@@ -761,9 +805,6 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
761 | ap->ops->eng_timeout(ap); | 805 | ap->ops->eng_timeout(ap); |
762 | } | 806 | } |
763 | 807 | ||
764 | /* finish or retry handled scmd's and clean up */ | ||
765 | WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q)); | ||
766 | |||
767 | scsi_eh_flush_done_q(&ap->eh_done_q); | 808 | scsi_eh_flush_done_q(&ap->eh_done_q); |
768 | 809 | ||
769 | /* clean up */ | 810 | /* clean up */ |
@@ -784,9 +825,8 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
784 | wake_up_all(&ap->eh_wait_q); | 825 | wake_up_all(&ap->eh_wait_q); |
785 | 826 | ||
786 | spin_unlock_irqrestore(ap->lock, flags); | 827 | spin_unlock_irqrestore(ap->lock, flags); |
787 | |||
788 | DPRINTK("EXIT\n"); | ||
789 | } | 828 | } |
829 | EXPORT_SYMBOL_GPL(ata_scsi_port_error_handler); | ||
790 | 830 | ||
791 | /** | 831 | /** |
792 | * ata_port_wait_eh - Wait for the currently pending EH to complete | 832 | * ata_port_wait_eh - Wait for the currently pending EH to complete |
@@ -1618,7 +1658,7 @@ static void ata_eh_analyze_serror(struct ata_link *link) | |||
1618 | * host links. For disabled PMP links, only N bit is | 1658 | * host links. For disabled PMP links, only N bit is |
1619 | * considered as X bit is left at 1 for link plugging. | 1659 | * considered as X bit is left at 1 for link plugging. |
1620 | */ | 1660 | */ |
1621 | if (link->lpm_policy != ATA_LPM_MAX_POWER) | 1661 | if (link->lpm_policy > ATA_LPM_MAX_POWER) |
1622 | hotplug_mask = 0; /* hotplug doesn't work w/ LPM */ | 1662 | hotplug_mask = 0; /* hotplug doesn't work w/ LPM */ |
1623 | else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) | 1663 | else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) |
1624 | hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; | 1664 | hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; |