aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@suse.de>2011-01-23 10:42:50 -0500
committerJeff Garzik <jgarzik@redhat.com>2011-03-02 02:36:45 -0500
commit0e0b494ca8c54a7297d0cc549405091019b3b77e (patch)
tree7d675c0ccae0763402585e91c38f1aa42818031c
parentc34aeebc06e8bdde93e8c8f40d9903b1aaab63c6 (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>
-rw-r--r--drivers/ata/libata-eh.c53
-rw-r--r--include/linux/libata.h2
2 files changed, 46 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)
587void ata_scsi_error(struct Scsi_Host *host) 587void 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 */
621void 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 ? */ 707EXPORT_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 */
717void 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}
829EXPORT_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
diff --git a/include/linux/libata.h b/include/linux/libata.h
index c9c5d7ad1a2b..9739317c707a 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1050,6 +1050,8 @@ extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
1050 int queue_depth, int reason); 1050 int queue_depth, int reason);
1051extern struct ata_device *ata_dev_pair(struct ata_device *adev); 1051extern struct ata_device *ata_dev_pair(struct ata_device *adev);
1052extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); 1052extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
1053extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap);
1054extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q);
1053 1055
1054extern int ata_cable_40wire(struct ata_port *ap); 1056extern int ata_cable_40wire(struct ata_port *ap);
1055extern int ata_cable_80wire(struct ata_port *ap); 1057extern int ata_cable_80wire(struct ata_port *ap);