diff options
author | James Bottomley <James.Bottomley@suse.de> | 2011-01-23 10:42:50 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2011-03-02 02:36:45 -0500 |
commit | 0e0b494ca8c54a7297d0cc549405091019b3b77e (patch) | |
tree | 7d675c0ccae0763402585e91c38f1aa42818031c /drivers/ata | |
parent | c34aeebc06e8bdde93e8c8f40d9903b1aaab63c6 (diff) |
libata: separate error handler into usable components
Right at the moment, the libata error handler is incredibly
monolithic. This makes it impossible to use from composite drivers
like libsas and ipr which have to handle error themselves in the first
instance.
The essence of the change is to split the monolithic error handler
into two components: one which handles a queue of ata commands for
processing and the other which handles the back end of readying a
port. This allows the upper error handler fine grained control in
calling libsas functions (and making sure they only get called for ATA
commands whose lower errors have been fixed up).
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-eh.c | 53 |
1 files changed, 44 insertions, 9 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 073b88156b3c..df3f3140c9c7 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -587,7 +587,6 @@ 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; |
592 | LIST_HEAD(eh_work_q); | 591 | LIST_HEAD(eh_work_q); |
593 | 592 | ||
@@ -597,6 +596,34 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
597 | list_splice_init(&host->eh_cmd_q, &eh_work_q); | 596 | list_splice_init(&host->eh_cmd_q, &eh_work_q); |
598 | spin_unlock_irqrestore(host->host_lock, flags); | 597 | spin_unlock_irqrestore(host->host_lock, flags); |
599 | 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 | |||
600 | /* make sure sff pio task is not running */ | 627 | /* make sure sff pio task is not running */ |
601 | ata_sff_flush_pio_task(ap); | 628 | ata_sff_flush_pio_task(ap); |
602 | 629 | ||
@@ -632,7 +659,7 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
632 | if (ap->ops->lost_interrupt) | 659 | if (ap->ops->lost_interrupt) |
633 | ap->ops->lost_interrupt(ap); | 660 | ap->ops->lost_interrupt(ap); |
634 | 661 | ||
635 | list_for_each_entry_safe(scmd, tmp, &eh_work_q, eh_entry) { | 662 | list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) { |
636 | struct ata_queued_cmd *qc; | 663 | struct ata_queued_cmd *qc; |
637 | 664 | ||
638 | for (i = 0; i < ATA_MAX_QUEUE; i++) { | 665 | for (i = 0; i < ATA_MAX_QUEUE; i++) { |
@@ -676,8 +703,20 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
676 | } else | 703 | } else |
677 | spin_unlock_wait(ap->lock); | 704 | spin_unlock_wait(ap->lock); |
678 | 705 | ||
679 | /* If we timed raced normal completion and there is nothing to | 706 | } |
680 | 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; | ||
681 | 720 | ||
682 | /* invoke error handler */ | 721 | /* invoke error handler */ |
683 | if (ap->ops->error_handler) { | 722 | if (ap->ops->error_handler) { |
@@ -766,9 +805,6 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
766 | ap->ops->eng_timeout(ap); | 805 | ap->ops->eng_timeout(ap); |
767 | } | 806 | } |
768 | 807 | ||
769 | /* finish or retry handled scmd's and clean up */ | ||
770 | WARN_ON(host->host_failed || !list_empty(&eh_work_q)); | ||
771 | |||
772 | scsi_eh_flush_done_q(&ap->eh_done_q); | 808 | scsi_eh_flush_done_q(&ap->eh_done_q); |
773 | 809 | ||
774 | /* clean up */ | 810 | /* clean up */ |
@@ -789,9 +825,8 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
789 | wake_up_all(&ap->eh_wait_q); | 825 | wake_up_all(&ap->eh_wait_q); |
790 | 826 | ||
791 | spin_unlock_irqrestore(ap->lock, flags); | 827 | spin_unlock_irqrestore(ap->lock, flags); |
792 | |||
793 | DPRINTK("EXIT\n"); | ||
794 | } | 828 | } |
829 | EXPORT_SYMBOL_GPL(ata_scsi_port_error_handler); | ||
795 | 830 | ||
796 | /** | 831 | /** |
797 | * 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 |