]> err.no Git - linux-2.6/blobdiff - drivers/ata/libata-sff.c
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[linux-2.6] / drivers / ata / libata-sff.c
index 04024a55666052e25da6b29fd73cfdd98f971a9b..2ec65a8fda79ecc46986ed0da6de7d886c71ccf5 100644 (file)
@@ -44,10 +44,14 @@ const struct ata_port_operations ata_sff_port_ops = {
 
        .qc_prep                = ata_sff_qc_prep,
        .qc_issue               = ata_sff_qc_issue,
+       .qc_fill_rtf            = ata_sff_qc_fill_rtf,
 
        .freeze                 = ata_sff_freeze,
        .thaw                   = ata_sff_thaw,
+       .prereset               = ata_sff_prereset,
        .softreset              = ata_sff_softreset,
+       .hardreset              = sata_sff_hardreset,
+       .postreset              = ata_sff_postreset,
        .error_handler          = ata_sff_error_handler,
        .post_internal_cmd      = ata_sff_post_internal_cmd,
 
@@ -58,6 +62,7 @@ const struct ata_port_operations ata_sff_port_ops = {
        .sff_exec_command       = ata_sff_exec_command,
        .sff_data_xfer          = ata_sff_data_xfer,
        .sff_irq_on             = ata_sff_irq_on,
+       .sff_irq_clear          = ata_sff_irq_clear,
 
        .port_start             = ata_sff_port_start,
 };
@@ -71,7 +76,6 @@ const struct ata_port_operations ata_bmdma_port_ops = {
        .bmdma_start            = ata_bmdma_start,
        .bmdma_stop             = ata_bmdma_stop,
        .bmdma_status           = ata_bmdma_status,
-       .sff_irq_clear          = ata_sff_irq_clear,
 };
 
 /**
@@ -306,9 +310,20 @@ int ata_sff_busy_sleep(struct ata_port *ap,
        return 0;
 }
 
+static int ata_sff_check_ready(struct ata_link *link)
+{
+       u8 status = link->ap->ops->sff_check_status(link->ap);
+
+       if (!(status & ATA_BUSY))
+               return 1;
+       if (status == 0xff)
+               return -ENODEV;
+       return 0;
+}
+
 /**
  *     ata_sff_wait_ready - sleep until BSY clears, or timeout
- *     @ap: port containing status register to be polled
+ *     @link: SFF link to wait ready status for
  *     @deadline: deadline jiffies for the operation
  *
  *     Sleep until ATA Status register bit BSY clears, or timeout
@@ -320,32 +335,9 @@ int ata_sff_busy_sleep(struct ata_port *ap,
  *     RETURNS:
  *     0 on success, -errno otherwise.
  */
-int ata_sff_wait_ready(struct ata_port *ap, unsigned long deadline)
+int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline)
 {
-       unsigned long start = jiffies;
-       int warned = 0;
-
-       while (1) {
-               u8 status = ap->ops->sff_check_status(ap);
-               unsigned long now = jiffies;
-
-               if (!(status & ATA_BUSY))
-                       return 0;
-               if (!ata_link_online(&ap->link) && status == 0xff)
-                       return -ENODEV;
-               if (time_after(now, deadline))
-                       return -EBUSY;
-
-               if (!warned && time_after(now, start + 5 * HZ) &&
-                   (deadline - now > 3 * HZ)) {
-                       ata_port_printk(ap, KERN_WARNING,
-                               "port is slow to respond, please be patient "
-                               "(Status 0x%x)\n", status);
-                       warned = 1;
-               }
-
-               msleep(50);
-       }
+       return ata_wait_ready(link, deadline, ata_sff_check_ready);
 }
 
 /**
@@ -1216,7 +1208,7 @@ fsm_start:
                DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
                        ap->print_id, qc->dev->devno, status);
 
-               WARN_ON(qc->err_mask);
+               WARN_ON(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM));
 
                ap->hsm_task_state = HSM_ST_IDLE;
 
@@ -1230,7 +1222,7 @@ fsm_start:
                /* make sure qc->err_mask is available to
                 * know what's wrong and recover
                 */
-               WARN_ON(qc->err_mask == 0);
+               WARN_ON(!(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM)));
 
                ap->hsm_task_state = HSM_ST_IDLE;
 
@@ -1416,6 +1408,25 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
        return 0;
 }
 
+/**
+ *     ata_sff_qc_fill_rtf - fill result TF using ->sff_tf_read
+ *     @qc: qc to fill result TF for
+ *
+ *     @qc is finished and result TF needs to be filled.  Fill it
+ *     using ->sff_tf_read.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     true indicating that result TF is successfully filled.
+ */
+bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+       qc->ap->ops->sff_tf_read(qc->ap, &qc->result_tf);
+       return true;
+}
+
 /**
  *     ata_sff_host_intr - Handle host interrupt for given (port, task)
  *     @ap: Port on which interrupt arrived (possibly...)
@@ -1606,6 +1617,47 @@ void ata_sff_thaw(struct ata_port *ap)
        ap->ops->sff_irq_on(ap);
 }
 
+/**
+ *     ata_sff_prereset - prepare SFF link for reset
+ *     @link: SFF link to be reset
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     SFF link @link is about to be reset.  Initialize it.  It first
+ *     calls ata_std_prereset() and wait for !BSY if the port is
+ *     being softreset.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_sff_prereset(struct ata_link *link, unsigned long deadline)
+{
+       struct ata_eh_context *ehc = &link->eh_context;
+       int rc;
+
+       rc = ata_std_prereset(link, deadline);
+       if (rc)
+               return rc;
+
+       /* if we're about to do hardreset, nothing more to do */
+       if (ehc->i.action & ATA_EH_HARDRESET)
+               return 0;
+
+       /* wait for !BSY if we don't know that no device is attached */
+       if (!ata_link_offline(link)) {
+               rc = ata_sff_wait_ready(link, deadline);
+               if (rc && rc != -ENODEV) {
+                       ata_link_printk(link, KERN_WARNING, "device not ready "
+                                       "(errno=%d), forcing hardreset\n", rc);
+                       ehc->i.action |= ATA_EH_HARDRESET;
+               }
+       }
+
+       return 0;
+}
+
 /**
  *     ata_devchk - PATA device presence detection
  *     @ap: ATA channel to examine
@@ -1718,25 +1770,41 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present,
        return class;
 }
 
-static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
-                             unsigned long deadline)
+/**
+ *     ata_sff_wait_after_reset - wait for devices to become ready after reset
+ *     @link: SFF link which is just reset
+ *     @devmask: mask of present devices
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     Wait devices attached to SFF @link to become ready after
+ *     reset.  It contains preceding 150ms wait to avoid accessing TF
+ *     status register too early.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -ENODEV if some or all of devices in @devmask
+ *     don't seem to exist.  -errno on other errors.
+ */
+int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
+                            unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct ata_ioports *ioaddr = &ap->ioaddr;
        unsigned int dev0 = devmask & (1 << 0);
        unsigned int dev1 = devmask & (1 << 1);
        int rc, ret = 0;
 
-       /* if device 0 was found in ata_devchk, wait for its
-        * BSY bit to clear
+       msleep(ATA_WAIT_AFTER_RESET_MSECS);
+
+       /* always check readiness of the master device */
+       rc = ata_sff_wait_ready(link, deadline);
+       /* -ENODEV means the odd clown forgot the D7 pulldown resistor
+        * and TF status is 0xff, bail out on it too.
         */
-       if (dev0) {
-               rc = ata_sff_wait_ready(ap, deadline);
-               if (rc) {
-                       if (rc != -ENODEV)
-                               return rc;
-                       ret = rc;
-               }
-       }
+       if (rc)
+               return rc;
 
        /* if device 1 was found in ata_devchk, wait for register
         * access briefly, then wait for BSY to clear.
@@ -1760,7 +1828,7 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
                        msleep(50);     /* give drive a breather */
                }
 
-               rc = ata_sff_wait_ready(ap, deadline);
+               rc = ata_sff_wait_ready(link, deadline);
                if (rc) {
                        if (rc != -ENODEV)
                                return rc;
@@ -1778,61 +1846,6 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
        return ret;
 }
 
-/**
- *     ata_sff_wait_after_reset - wait before checking status after reset
- *     @ap: port containing status register to be polled
- *     @deadline: deadline jiffies for the operation
- *
- *     After reset, we need to pause a while before reading status.
- *     Also, certain combination of controller and device report 0xff
- *     for some duration (e.g. until SATA PHY is up and running)
- *     which is interpreted as empty port in ATA world.  This
- *     function also waits for such devices to get out of 0xff
- *     status.
- *
- *     LOCKING:
- *     Kernel thread context (may sleep).
- */
-void ata_sff_wait_after_reset(struct ata_port *ap, unsigned long deadline)
-{
-       unsigned long until = jiffies + ATA_TMOUT_FF_WAIT;
-
-       if (time_before(until, deadline))
-               deadline = until;
-
-       /* Spec mandates ">= 2ms" before checking status.  We wait
-        * 150ms, because that was the magic delay used for ATAPI
-        * devices in Hale Landis's ATADRVR, for the period of time
-        * between when the ATA command register is written, and then
-        * status is checked.  Because waiting for "a while" before
-        * checking status is fine, post SRST, we perform this magic
-        * delay here as well.
-        *
-        * Old drivers/ide uses the 2mS rule and then waits for ready.
-        */
-       msleep(150);
-
-       /* Wait for 0xff to clear.  Some SATA devices take a long time
-        * to clear 0xff after reset.  For example, HHD424020F7SV00
-        * iVDR needs >= 800ms while.  Quantum GoVault needs even more
-        * than that.
-        *
-        * Note that some PATA controllers (pata_ali) explode if
-        * status register is read more than once when there's no
-        * device attached.
-        */
-       if (ap->flags & ATA_FLAG_SATA) {
-               while (1) {
-                       u8 status = ap->ops->sff_check_status(ap);
-
-                       if (status != 0xff || time_after(jiffies, deadline))
-                               return;
-
-                       msleep(50);
-               }
-       }
-}
-
 static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
                             unsigned long deadline)
 {
@@ -1847,17 +1860,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
        udelay(20);     /* FIXME: flush */
        iowrite8(ap->ctl, ioaddr->ctl_addr);
 
-       /* wait a while before checking status */
-       ata_sff_wait_after_reset(ap, deadline);
-
-       /* Before we perform post reset processing we want to see if
-        * the bus shows 0xFF because the odd clown forgets the D7
-        * pulldown resistor.
-        */
-       if (ap->ops->sff_check_status(ap) == 0xFF)
-               return -ENODEV;
-
-       return ata_bus_post_reset(ap, devmask, deadline);
+       /* wait the port to become ready */
+       return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
 }
 
 /**
@@ -1885,11 +1889,6 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes,
 
        DPRINTK("ENTER\n");
 
-       if (ata_link_offline(link)) {
-               classes[0] = ATA_DEV_NONE;
-               goto out;
-       }
-
        /* determine if device 0/1 are present */
        if (ata_devchk(ap, 0))
                devmask |= (1 << 0);
@@ -1915,7 +1914,6 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes,
                classes[1] = ata_sff_dev_classify(&link->device[1],
                                                  devmask & (1 << 1), &err);
 
- out:
        DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
        return 0;
 }
@@ -1938,54 +1936,53 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes,
 int sata_sff_hardreset(struct ata_link *link, unsigned int *class,
                       unsigned long deadline)
 {
-       struct ata_port *ap = link->ap;
-       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+       struct ata_eh_context *ehc = &link->eh_context;
+       const unsigned long *timing = sata_ehc_deb_timing(ehc);
+       bool online;
        int rc;
 
-       DPRINTK("ENTER\n");
+       rc = sata_link_hardreset(link, timing, deadline, &online,
+                                ata_sff_check_ready);
+       if (online)
+               *class = ata_sff_dev_classify(link->device, 1, NULL);
 
-       /* do hardreset */
-       rc = sata_link_hardreset(link, timing, deadline);
-       if (rc) {
-               ata_link_printk(link, KERN_ERR,
-                               "COMRESET failed (errno=%d)\n", rc);
-               return rc;
-       }
+       DPRINTK("EXIT, class=%u\n", *class);
+       return rc;
+}
 
-       /* TODO: phy layer with polling, timeouts, etc. */
-       if (ata_link_offline(link)) {
-               *class = ATA_DEV_NONE;
-               DPRINTK("EXIT, link offline\n");
-               return 0;
-       }
+/**
+ *     ata_sff_postreset - SFF postreset callback
+ *     @link: the target SFF ata_link
+ *     @classes: classes of attached devices
+ *
+ *     This function is invoked after a successful reset.  It first
+ *     calls ata_std_postreset() and performs SFF specific postreset
+ *     processing.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ */
+void ata_sff_postreset(struct ata_link *link, unsigned int *classes)
+{
+       struct ata_port *ap = link->ap;
 
-       /* wait a while before checking status */
-       ata_sff_wait_after_reset(ap, deadline);
+       ata_std_postreset(link, classes);
 
-       /* If PMP is supported, we have to do follow-up SRST.  Note
-        * that some PMPs don't send D2H Reg FIS after hardreset at
-        * all if the first port is empty.  Wait for it just for a
-        * second and request follow-up SRST.
-        */
-       if (ap->flags & ATA_FLAG_PMP) {
-               ata_sff_wait_ready(ap, jiffies + HZ);
-               return -EAGAIN;
-       }
+       /* is double-select really necessary? */
+       if (classes[0] != ATA_DEV_NONE)
+               ap->ops->sff_dev_select(ap, 1);
+       if (classes[1] != ATA_DEV_NONE)
+               ap->ops->sff_dev_select(ap, 0);
 
-       rc = ata_sff_wait_ready(ap, deadline);
-       /* link occupied, -ENODEV too is an error */
-       if (rc) {
-               ata_link_printk(link, KERN_ERR,
-                               "COMRESET failed (errno=%d)\n", rc);
-               return rc;
+       /* bail out if no device is present */
+       if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+               DPRINTK("EXIT, no device\n");
+               return;
        }
 
-       ap->ops->sff_dev_select(ap, 0); /* probably unnecessary */
-
-       *class = ata_sff_dev_classify(link->device, 1, NULL);
-
-       DPRINTK("EXIT, class=%u\n", *class);
-       return 0;
+       /* set up device control */
+       if (ap->ioaddr.ctl_addr)
+               iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
 }
 
 /**
@@ -2048,14 +2045,12 @@ void ata_sff_error_handler(struct ata_port *ap)
 
        /* PIO and DMA engines have been stopped, perform recovery */
 
-       /* ata_sff_softreset and sata_sff_hardreset are inherited to
-        * all SFF drivers from ata_sff_port_ops.  Ignore softreset if
-        * ctl isn't accessible.  Ignore hardreset if SCR access isn't
-        * available.
+       /* Ignore ata_sff_softreset if ctl isn't accessible and
+        * built-in hardresets if SCR access isn't available.
         */
        if (softreset == ata_sff_softreset && !ap->ioaddr.ctl_addr)
                softreset = NULL;
-       if (hardreset == sata_sff_hardreset && !sata_scr_valid(&ap->link))
+       if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link))
                hardreset = NULL;
 
        ata_do_eh(ap, ap->ops->prereset, softreset, hardreset,
@@ -2743,6 +2738,7 @@ EXPORT_SYMBOL_GPL(ata_sff_irq_on);
 EXPORT_SYMBOL_GPL(ata_sff_irq_clear);
 EXPORT_SYMBOL_GPL(ata_sff_hsm_move);
 EXPORT_SYMBOL_GPL(ata_sff_qc_issue);
+EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
 EXPORT_SYMBOL_GPL(ata_sff_host_intr);
 EXPORT_SYMBOL_GPL(ata_sff_interrupt);
 EXPORT_SYMBOL_GPL(ata_sff_freeze);