]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/ata/libata-eh.c
[SCSI] libata: separate error handler into usable components
[karo-tx-linux.git] / drivers / ata / libata-eh.c
index fc3f339a8d3c3d1a98b5cdf3650dcb86a17c6a1f..e02455b751ca0cf5c25b345e8bd93d578ccd2816 100644 (file)
@@ -587,7 +587,6 @@ static void ata_eh_unload(struct ata_port *ap)
 void ata_scsi_error(struct Scsi_Host *host)
 {
        struct ata_port *ap = ata_shost_to_port(host);
-       int i;
        unsigned long flags;
        LIST_HEAD(eh_work_q);
 
@@ -597,6 +596,34 @@ void ata_scsi_error(struct Scsi_Host *host)
        list_splice_init(&host->eh_cmd_q, &eh_work_q);
        spin_unlock_irqrestore(host->host_lock, flags);
 
+       ata_scsi_cmd_error_handler(host, ap, &eh_work_q);
+
+       /* If we timed raced normal completion and there is nothing to
+          recover nr_timedout == 0 why exactly are we doing error recovery ? */
+       ata_scsi_port_error_handler(host, ap);
+
+       /* finish or retry handled scmd's and clean up */
+       WARN_ON(host->host_failed || !list_empty(&eh_work_q));
+
+       DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_scsi_cmd_error_handler - error callback for a list of commands
+ * @host:      scsi host containing the port
+ * @ap:                ATA port within the host
+ * @eh_work_q: list of commands to process
+ *
+ * process the given list of commands and return those finished to the
+ * ap->eh_done_q.  This function is the first part of the libata error
+ * handler which processes a given list of failed commands.
+ */
+void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
+                               struct list_head *eh_work_q)
+{
+       int i;
+       unsigned long flags;
+
        /* make sure sff pio task is not running */
        ata_sff_flush_pio_task(ap);
 
@@ -632,7 +659,7 @@ void ata_scsi_error(struct Scsi_Host *host)
                if (ap->ops->lost_interrupt)
                        ap->ops->lost_interrupt(ap);
 
-               list_for_each_entry_safe(scmd, tmp, &eh_work_q, eh_entry) {
+               list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) {
                        struct ata_queued_cmd *qc;
 
                        for (i = 0; i < ATA_MAX_QUEUE; i++) {
@@ -676,8 +703,20 @@ void ata_scsi_error(struct Scsi_Host *host)
        } else
                spin_unlock_wait(ap->lock);
 
-       /* If we timed raced normal completion and there is nothing to
-          recover nr_timedout == 0 why exactly are we doing error recovery ? */
+}
+EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
+
+/**
+ * ata_scsi_port_error_handler - recover the port after the commands
+ * @host:      SCSI host containing the port
+ * @ap:                the ATA port
+ *
+ * Handle the recovery of the port @ap after all the commands
+ * have been recovered.
+ */
+void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
+{
+       unsigned long flags;
 
        /* invoke error handler */
        if (ap->ops->error_handler) {
@@ -766,9 +805,6 @@ void ata_scsi_error(struct Scsi_Host *host)
                ap->ops->eng_timeout(ap);
        }
 
-       /* finish or retry handled scmd's and clean up */
-       WARN_ON(host->host_failed || !list_empty(&eh_work_q));
-
        scsi_eh_flush_done_q(&ap->eh_done_q);
 
        /* clean up */
@@ -789,9 +825,8 @@ void ata_scsi_error(struct Scsi_Host *host)
        wake_up_all(&ap->eh_wait_q);
 
        spin_unlock_irqrestore(ap->lock, flags);
-
-       DPRINTK("EXIT\n");
 }
+EXPORT_SYMBOL_GPL(ata_scsi_port_error_handler);
 
 /**
  *     ata_port_wait_eh - Wait for the currently pending EH to complete