]> err.no Git - linux-2.6/blobdiff - drivers/ata/libata-eh.c
libata: IORDY handling
[linux-2.6] / drivers / ata / libata-eh.c
index ed8813b222a0219e98536bb6fc49495e95cc37e7..1d7faab64810afe1524a5884104ac5d6c8d74286 100644 (file)
@@ -559,101 +559,6 @@ void ata_port_wait_eh(struct ata_port *ap)
        }
 }
 
-/**
- *     ata_qc_timeout - Handle timeout of queued command
- *     @qc: Command that timed out
- *
- *     Some part of the kernel (currently, only the SCSI layer)
- *     has noticed that the active command on port @ap has not
- *     completed after a specified length of time.  Handle this
- *     condition by disabling DMA (if necessary) and completing
- *     transactions, with error if necessary.
- *
- *     This also handles the case of the "lost interrupt", where
- *     for some reason (possibly hardware bug, possibly driver bug)
- *     an interrupt was not delivered to the driver, even though the
- *     transaction completed successfully.
- *
- *     TODO: kill this function once old EH is gone.
- *
- *     LOCKING:
- *     Inherited from SCSI layer (none, can sleep)
- */
-static void ata_qc_timeout(struct ata_queued_cmd *qc)
-{
-       struct ata_port *ap = qc->ap;
-       u8 host_stat = 0, drv_stat;
-       unsigned long flags;
-
-       DPRINTK("ENTER\n");
-
-       ap->hsm_task_state = HSM_ST_IDLE;
-
-       spin_lock_irqsave(ap->lock, flags);
-
-       switch (qc->tf.protocol) {
-
-       case ATA_PROT_DMA:
-       case ATA_PROT_ATAPI_DMA:
-               host_stat = ap->ops->bmdma_status(ap);
-
-               /* before we do anything else, clear DMA-Start bit */
-               ap->ops->bmdma_stop(qc);
-
-               /* fall through */
-
-       default:
-               ata_altstatus(ap);
-               drv_stat = ata_chk_status(ap);
-
-               /* ack bmdma irq events */
-               ap->ops->irq_clear(ap);
-
-               ata_dev_printk(qc->dev, KERN_ERR, "command 0x%x timeout, "
-                              "stat 0x%x host_stat 0x%x\n",
-                              qc->tf.command, drv_stat, host_stat);
-
-               /* complete taskfile transaction */
-               qc->err_mask |= AC_ERR_TIMEOUT;
-               break;
-       }
-
-       spin_unlock_irqrestore(ap->lock, flags);
-
-       ata_eh_qc_complete(qc);
-
-       DPRINTK("EXIT\n");
-}
-
-/**
- *     ata_eng_timeout - Handle timeout of queued command
- *     @ap: Port on which timed-out command is active
- *
- *     Some part of the kernel (currently, only the SCSI layer)
- *     has noticed that the active command on port @ap has not
- *     completed after a specified length of time.  Handle this
- *     condition by disabling DMA (if necessary) and completing
- *     transactions, with error if necessary.
- *
- *     This also handles the case of the "lost interrupt", where
- *     for some reason (possibly hardware bug, possibly driver bug)
- *     an interrupt was not delivered to the driver, even though the
- *     transaction completed successfully.
- *
- *     TODO: kill this function once old EH is gone.
- *
- *     LOCKING:
- *     Inherited from SCSI layer (none, can sleep)
- */
-void ata_eng_timeout(struct ata_port *ap)
-{
-       DPRINTK("ENTER\n");
-
-       ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag));
-
-       DPRINTK("EXIT\n");
-}
-
 static int ata_eh_nr_in_flight(struct ata_port *ap)
 {
        unsigned int tag;
@@ -1359,8 +1264,8 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
                tf.feature |= ATAPI_PKT_DMA;
        } else {
                tf.protocol = ATA_PROT_ATAPI;
-               tf.lbam = (8 * 1024) & 0xff;
-               tf.lbah = (8 * 1024) >> 8;
+               tf.lbam = SCSI_SENSE_BUFFERSIZE;
+               tf.lbah = 0;
        }
 
        return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
@@ -1828,11 +1733,15 @@ static void ata_eh_link_autopsy(struct ata_link *link)
                ehc->i.action &= ~ATA_EH_PERDEV_MASK;
        }
 
-       /* consider speeding down */
+       /* propagate timeout to host link */
+       if ((all_err_mask & AC_ERR_TIMEOUT) && !ata_is_host_link(link))
+               ap->link.eh_context.i.err_mask |= AC_ERR_TIMEOUT;
+
+       /* record error and consider speeding down */
        dev = ehc->i.dev;
-       if (!dev && ata_link_max_devices(link) == 1 &&
-           ata_dev_enabled(link->device))
-               dev = link->device;
+       if (!dev && ((ata_link_max_devices(link) == 1 &&
+                     ata_dev_enabled(link->device))))
+           dev = link->device;
 
        if (dev)
                ehc->i.action |= ata_eh_speed_down(dev, is_io, all_err_mask);
@@ -1854,8 +1763,14 @@ void ata_eh_autopsy(struct ata_port *ap)
 {
        struct ata_link *link;
 
-       __ata_port_for_each_link(link, ap)
+       ata_port_for_each_link(link, ap)
                ata_eh_link_autopsy(link);
+
+       /* Autopsy of fanout ports can affect host link autopsy.
+        * Perform host link autopsy last.
+        */
+       if (ap->nr_pmp_links)
+               ata_eh_link_autopsy(&ap->link);
 }
 
 /**
@@ -1945,30 +1860,54 @@ static void ata_eh_link_report(struct ata_link *link)
                  ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "");
 
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
-               static const char *dma_str[] = {
-                       [DMA_BIDIRECTIONAL]     = "bidi",
-                       [DMA_TO_DEVICE]         = "out",
-                       [DMA_FROM_DEVICE]       = "in",
-                       [DMA_NONE]              = "",
-               };
                struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
                struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
+               const u8 *cdb = qc->cdb;
+               char data_buf[20] = "";
+               char cdb_buf[70] = "";
 
                if (!(qc->flags & ATA_QCFLAG_FAILED) ||
                    qc->dev->link != link || !qc->err_mask)
                        continue;
 
+               if (qc->dma_dir != DMA_NONE) {
+                       static const char *dma_str[] = {
+                               [DMA_BIDIRECTIONAL]     = "bidi",
+                               [DMA_TO_DEVICE]         = "out",
+                               [DMA_FROM_DEVICE]       = "in",
+                       };
+                       static const char *prot_str[] = {
+                               [ATA_PROT_PIO]          = "pio",
+                               [ATA_PROT_DMA]          = "dma",
+                               [ATA_PROT_NCQ]          = "ncq",
+                               [ATA_PROT_ATAPI]        = "pio",
+                               [ATA_PROT_ATAPI_DMA]    = "dma",
+                       };
+
+                       snprintf(data_buf, sizeof(data_buf), " %s %u %s",
+                                prot_str[qc->tf.protocol], qc->nbytes,
+                                dma_str[qc->dma_dir]);
+               }
+
+               if (is_atapi_taskfile(&qc->tf))
+                       snprintf(cdb_buf, sizeof(cdb_buf),
+                                "cdb %02x %02x %02x %02x %02x %02x %02x %02x  "
+                                "%02x %02x %02x %02x %02x %02x %02x %02x\n         ",
+                                cdb[0], cdb[1], cdb[2], cdb[3],
+                                cdb[4], cdb[5], cdb[6], cdb[7],
+                                cdb[8], cdb[9], cdb[10], cdb[11],
+                                cdb[12], cdb[13], cdb[14], cdb[15]);
+
                ata_dev_printk(qc->dev, KERN_ERR,
                        "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
-                       "tag %d cdb 0x%x data %u %s\n         "
+                       "tag %d%s\n         %s"
                        "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
                        "Emask 0x%x (%s)%s\n",
                        cmd->command, cmd->feature, cmd->nsect,
                        cmd->lbal, cmd->lbam, cmd->lbah,
                        cmd->hob_feature, cmd->hob_nsect,
                        cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah,
-                       cmd->device, qc->tag, qc->cdb[0], qc->nbytes,
-                       dma_str[qc->dma_dir],
+                       cmd->device, qc->tag, data_buf, cdb_buf,
                        res->command, res->feature, res->nsect,
                        res->lbal, res->lbam, res->lbah,
                        res->hob_feature, res->hob_nsect,
@@ -2228,13 +2167,11 @@ int ata_eh_reset(struct ata_link *link, int classify,
                if (ata_link_offline(link))
                        continue;
 
-               /* apply class override and convert UNKNOWN to NONE */
+               /* apply class override */
                if (lflags & ATA_LFLAG_ASSUME_ATA)
                        classes[dev->devno] = ATA_DEV_ATA;
                else if (lflags & ATA_LFLAG_ASSUME_SEMB)
                        classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
-               else if (classes[dev->devno] == ATA_DEV_UNKNOWN)
-                       classes[dev->devno] = ATA_DEV_NONE;
        }
 
        /* record current link speed */
@@ -2810,6 +2747,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
        if (ap->ops->port_suspend)
                rc = ap->ops->port_suspend(ap, ap->pm_mesg);
 
+       ata_acpi_set_state(ap, PMSG_SUSPEND);
  out:
        /* report result */
        spin_lock_irqsave(ap->lock, flags);
@@ -2855,6 +2793,8 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
 
        WARN_ON(!(ap->pflags & ATA_PFLAG_SUSPENDED));
 
+       ata_acpi_set_state(ap, PMSG_ON);
+
        if (ap->ops->port_resume)
                rc = ap->ops->port_resume(ap);