locks: allow lockd to process blocked locks during grace period
[safe/jmp/linux-2.6] / drivers / ata / libata-sff.c
index 6e8de3c..2a4c516 100644 (file)
@@ -44,11 +44,13 @@ 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,
@@ -245,7 +247,7 @@ u8 ata_sff_check_status(struct ata_port *ap)
  *     LOCKING:
  *     Inherited from caller.
  */
-u8 ata_sff_altstatus(struct ata_port *ap)
+static u8 ata_sff_altstatus(struct ata_port *ap)
 {
        if (ap->ops->sff_check_altstatus)
                return ap->ops->sff_check_altstatus(ap);
@@ -254,10 +256,97 @@ u8 ata_sff_altstatus(struct ata_port *ap)
 }
 
 /**
+ *     ata_sff_irq_status - Check if the device is busy
+ *     @ap: port where the device is
+ *
+ *     Determine if the port is currently busy. Uses altstatus
+ *     if available in order to avoid clearing shared IRQ status
+ *     when finding an IRQ source. Non ctl capable devices don't
+ *     share interrupt lines fortunately for us.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+static u8 ata_sff_irq_status(struct ata_port *ap)
+{
+       u8 status;
+
+       if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+               status = ata_sff_altstatus(ap);
+               /* Not us: We are busy */
+               if (status & ATA_BUSY)
+                       return status;
+       }
+       /* Clear INTRQ latch */
+       status = ap->ops->sff_check_status(ap);
+       return status;
+}
+
+/**
+ *     ata_sff_sync - Flush writes
+ *     @ap: Port to wait for.
+ *
+ *     CAUTION:
+ *     If we have an mmio device with no ctl and no altstatus
+ *     method this will fail. No such devices are known to exist.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+static void ata_sff_sync(struct ata_port *ap)
+{
+       if (ap->ops->sff_check_altstatus)
+               ap->ops->sff_check_altstatus(ap);
+       else if (ap->ioaddr.altstatus_addr)
+               ioread8(ap->ioaddr.altstatus_addr);
+}
+
+/**
+ *     ata_sff_pause           -       Flush writes and wait 400nS
+ *     @ap: Port to pause for.
+ *
+ *     CAUTION:
+ *     If we have an mmio device with no ctl and no altstatus
+ *     method this will fail. No such devices are known to exist.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+void ata_sff_pause(struct ata_port *ap)
+{
+       ata_sff_sync(ap);
+       ndelay(400);
+}
+
+/**
+ *     ata_sff_dma_pause       -       Pause before commencing DMA
+ *     @ap: Port to pause for.
+ *
+ *     Perform I/O fencing and ensure sufficient cycle delays occur
+ *     for the HDMA1:0 transition
+ */
+void ata_sff_dma_pause(struct ata_port *ap)
+{
+       if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+               /* An altstatus read will cause the needed delay without
+                  messing up the IRQ status */
+               ata_sff_altstatus(ap);
+               return;
+       }
+       /* There are no DMA controllers without ctl. BUG here to ensure
+          we never violate the HDMA1:0 transition timing and risk
+          corruption. */
+       BUG();
+}
+
+/**
  *     ata_sff_busy_sleep - sleep until BSY clears, or timeout
  *     @ap: port containing status register to be polled
- *     @tmout_pat: impatience timeout
- *     @tmout: overall timeout
+ *     @tmout_pat: impatience timeout in msecs
+ *     @tmout: overall timeout in msecs
  *
  *     Sleep until ATA Status register bit BSY clears,
  *     or a timeout occurs.
@@ -276,7 +365,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
 
        status = ata_sff_busy_wait(ap, ATA_BUSY, 300);
        timer_start = jiffies;
-       timeout = timer_start + tmout_pat;
+       timeout = ata_deadline(timer_start, tmout_pat);
        while (status != 0xff && (status & ATA_BUSY) &&
               time_before(jiffies, timeout)) {
                msleep(50);
@@ -288,7 +377,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
                                "port is slow to respond, please be patient "
                                "(Status 0x%x)\n", status);
 
-       timeout = timer_start + tmout;
+       timeout = ata_deadline(timer_start, tmout);
        while (status != 0xff && (status & ATA_BUSY) &&
               time_before(jiffies, timeout)) {
                msleep(50);
@@ -301,13 +390,20 @@ int ata_sff_busy_sleep(struct ata_port *ap,
        if (status & ATA_BUSY) {
                ata_port_printk(ap, KERN_ERR, "port failed to respond "
                                "(%lu secs, Status 0x%x)\n",
-                               tmout / HZ, status);
+                               DIV_ROUND_UP(tmout, 1000), status);
                return -EBUSY;
        }
 
        return 0;
 }
 
+static int ata_sff_check_ready(struct ata_link *link)
+{
+       u8 status = link->ap->ops->sff_check_status(link->ap);
+
+       return ata_check_ready(status);
+}
+
 /**
  *     ata_sff_wait_ready - sleep until BSY clears, or timeout
  *     @link: SFF link to wait ready status for
@@ -324,56 +420,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
  */
 int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline)
 {
-       struct ata_port *ap = link->ap;
-       unsigned long start = jiffies;
-       unsigned long nodev_deadline = start + ATA_TMOUT_FF_WAIT;
-       int warned = 0;
-
-       if (time_after(nodev_deadline, deadline))
-               nodev_deadline = deadline;
-
-       while (1) {
-               u8 status = ap->ops->sff_check_status(ap);
-               unsigned long now = jiffies;
-
-               if (!(status & ATA_BUSY))
-                       return 0;
-
-               /* No device status could be transient.  Ignore it if
-                * link is online.  Also, 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.  Wait for
-                * ATA_TMOUT_FF_WAIT on -ENODEV if link isn't offline.
-                *
-                * Note that some PATA controllers (pata_ali) explode
-                * if status register is read more than once when
-                * there's no device attached.
-                */
-               if (status == 0xff) {
-                       if (ata_link_online(link))
-                               status = ATA_BUSY;
-                       else if ((link->ap->flags & ATA_FLAG_SATA) &&
-                                !ata_link_offline(link) &&
-                                time_before(now, nodev_deadline))
-                               status = ATA_BUSY;
-                       if (status == 0xff)
-                               return -ENODEV;
-               }
-
-               if (time_after(now, deadline))
-                       return -EBUSY;
-
-               if (!warned && time_after(now, start + 5 * HZ) &&
-                   (deadline - now > 3 * HZ)) {
-                       ata_link_printk(link, KERN_WARNING,
-                               "link 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);
 }
 
 /**
@@ -782,7 +829,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
        } else
                ata_pio_sector(qc);
 
-       ata_sff_altstatus(qc->ap); /* flush */
+       ata_sff_sync(qc->ap); /* flush */
 }
 
 /**
@@ -803,8 +850,9 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
        WARN_ON(qc->dev->cdb_len < 12);
 
        ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
-       ata_sff_altstatus(ap); /* flush */
-
+       ata_sff_sync(ap);
+       /* FIXME: If the CDB is for DMA do we need to do the transition delay
+          or is bmdma_start guaranteed to do it ? */
        switch (qc->tf.protocol) {
        case ATAPI_PROT_PIO:
                ap->hsm_task_state = HSM_ST;
@@ -945,7 +993,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
 
        if (unlikely(__atapi_pio_bytes(qc, bytes)))
                goto err_out;
-       ata_sff_altstatus(ap); /* flush */
+       ata_sff_sync(ap); /* flush */
 
        return;
 
@@ -1046,6 +1094,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
 int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
                     u8 status, int in_wq)
 {
+       struct ata_eh_info *ehi = &ap->link.eh_info;
        unsigned long flags = 0;
        int poll_next;
 
@@ -1077,9 +1126,12 @@ fsm_start:
                        if (likely(status & (ATA_ERR | ATA_DF)))
                                /* device stops HSM for abort/error */
                                qc->err_mask |= AC_ERR_DEV;
-                       else
+                       else {
                                /* HSM violation. Let EH handle this */
+                               ata_ehi_push_desc(ehi,
+                                       "ST_FIRST: !(DRQ|ERR|DF)");
                                qc->err_mask |= AC_ERR_HSM;
+                       }
 
                        ap->hsm_task_state = HSM_ST_ERR;
                        goto fsm_start;
@@ -1098,9 +1150,9 @@ fsm_start:
                         * the CDB.
                         */
                        if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) {
-                               ata_port_printk(ap, KERN_WARNING,
-                                               "DRQ=1 with device error, "
-                                               "dev_stat 0x%X\n", status);
+                               ata_ehi_push_desc(ehi, "ST_FIRST: "
+                                       "DRQ=1 with device error, "
+                                       "dev_stat 0x%X", status);
                                qc->err_mask |= AC_ERR_HSM;
                                ap->hsm_task_state = HSM_ST_ERR;
                                goto fsm_start;
@@ -1157,9 +1209,9 @@ fsm_start:
                         * let the EH abort the command or reset the device.
                         */
                        if (unlikely(status & (ATA_ERR | ATA_DF))) {
-                               ata_port_printk(ap, KERN_WARNING, "DRQ=1 with "
-                                               "device error, dev_stat 0x%X\n",
-                                               status);
+                               ata_ehi_push_desc(ehi, "ST-ATAPI: "
+                                       "DRQ=1 with device error, "
+                                       "dev_stat 0x%X", status);
                                qc->err_mask |= AC_ERR_HSM;
                                ap->hsm_task_state = HSM_ST_ERR;
                                goto fsm_start;
@@ -1178,13 +1230,17 @@ fsm_start:
                                if (likely(status & (ATA_ERR | ATA_DF)))
                                        /* device stops HSM for abort/error */
                                        qc->err_mask |= AC_ERR_DEV;
-                               else
+                               else {
                                        /* HSM violation. Let EH handle this.
                                         * Phantom devices also trigger this
                                         * condition.  Mark hint.
                                         */
+                                       ata_ehi_push_desc(ehi, "ST-ATA: "
+                                               "DRQ=1 with device error, "
+                                               "dev_stat 0x%X", status);
                                        qc->err_mask |= AC_ERR_HSM |
                                                        AC_ERR_NODEV_HINT;
+                               }
 
                                ap->hsm_task_state = HSM_ST_ERR;
                                goto fsm_start;
@@ -1209,8 +1265,12 @@ fsm_start:
                                        status = ata_wait_idle(ap);
                                }
 
-                               if (status & (ATA_BUSY | ATA_DRQ))
+                               if (status & (ATA_BUSY | ATA_DRQ)) {
+                                       ata_ehi_push_desc(ehi, "ST-ATA: "
+                                               "BUSY|DRQ persists on ERR|DF, "
+                                               "dev_stat 0x%X", status);
                                        qc->err_mask |= AC_ERR_HSM;
+                               }
 
                                /* ata_pio_sectors() might change the
                                 * state to HSM_ST_LAST. so, the state
@@ -1244,7 +1304,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;
 
@@ -1255,11 +1315,6 @@ fsm_start:
                break;
 
        case HSM_ST_ERR:
-               /* make sure qc->err_mask is available to
-                * know what's wrong and recover
-                */
-               WARN_ON(qc->err_mask == 0);
-
                ap->hsm_task_state = HSM_ST_IDLE;
 
                /* complete taskfile transaction */
@@ -1445,6 +1500,25 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
 }
 
 /**
+ *     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...)
  *     @qc: Taskfile currently active in engine
@@ -1510,14 +1584,10 @@ inline unsigned int ata_sff_host_intr(struct ata_port *ap,
                goto idle_irq;
        }
 
-       /* check altstatus */
-       status = ata_sff_altstatus(ap);
-       if (status & ATA_BUSY)
-               goto idle_irq;
 
-       /* check main status, clearing INTRQ */
-       status = ap->ops->sff_check_status(ap);
-       if (unlikely(status & ATA_BUSY))
+       /* check main status, clearing INTRQ if needed */
+       status = ata_sff_irq_status(ap);
+       if (status & ATA_BUSY)
                goto idle_irq;
 
        /* ack bmdma irq events */
@@ -1813,7 +1883,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
        unsigned int dev1 = devmask & (1 << 1);
        int rc, ret = 0;
 
-       msleep(ATA_WAIT_AFTER_RESET_MSECS);
+       msleep(ATA_WAIT_AFTER_RESET);
 
        /* always check readiness of the master device */
        rc = ata_sff_wait_ready(link, deadline);
@@ -1906,11 +1976,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);
@@ -1936,7 +2001,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;
 }
@@ -1959,50 +2023,18 @@ 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");
-
-       /* 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;
-       }
-
-       /* TODO: phy layer with polling, timeouts, etc. */
-       if (ata_link_offline(link)) {
-               *class = ATA_DEV_NONE;
-               DPRINTK("EXIT, link offline\n");
-               return 0;
-       }
-
-       /* 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_after_reset(link, 1, jiffies + HZ);
-               return -EAGAIN;
-       }
-
-       /* wait for the link to become online */
-       rc = ata_sff_wait_after_reset(link, 1, deadline);
-       /* link occupied, -ENODEV too is an error */
-       if (rc) {
-               ata_link_printk(link, KERN_ERR,
-                               "COMRESET failed (errno=%d)\n", rc);
-               return rc;
-       }
-
-       *class = ata_sff_dev_classify(link->device, 1, NULL);
+       rc = sata_link_hardreset(link, timing, deadline, &online,
+                                ata_sff_check_ready);
+       if (online)
+               *class = ata_sff_dev_classify(link->device, 1, NULL);
 
        DPRINTK("EXIT, class=%u\n", *class);
-       return 0;
+       return rc;
 }
 
 /**
@@ -2089,7 +2121,7 @@ void ata_sff_error_handler(struct ata_port *ap)
                ap->ops->bmdma_stop(qc);
        }
 
-       ata_sff_altstatus(ap);
+       ata_sff_sync(ap);               /* FIXME: We don't need this */
        ap->ops->sff_check_status(ap);
        ap->ops->sff_irq_clear(ap);
 
@@ -2100,14 +2132,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,
@@ -2264,7 +2294,7 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc)
                 mmio + ATA_DMA_CMD);
 
        /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
-       ata_sff_altstatus(ap);        /* dummy read */
+       ata_sff_dma_pause(ap);
 }
 
 /**
@@ -2336,7 +2366,8 @@ void ata_bus_reset(struct ata_port *ap)
 
        /* issue bus reset */
        if (ap->flags & ATA_FLAG_SRST) {
-               rc = ata_bus_softreset(ap, devmask, jiffies + 40 * HZ);
+               rc = ata_bus_softreset(ap, devmask,
+                                      ata_deadline(jiffies, 40000));
                if (rc && rc != -ENODEV)
                        goto err_out;
        }
@@ -2783,7 +2814,8 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_prep);
 EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep);
 EXPORT_SYMBOL_GPL(ata_sff_dev_select);
 EXPORT_SYMBOL_GPL(ata_sff_check_status);
-EXPORT_SYMBOL_GPL(ata_sff_altstatus);
+EXPORT_SYMBOL_GPL(ata_sff_dma_pause);
+EXPORT_SYMBOL_GPL(ata_sff_pause);
 EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
 EXPORT_SYMBOL_GPL(ata_sff_wait_ready);
 EXPORT_SYMBOL_GPL(ata_sff_tf_load);
@@ -2795,6 +2827,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);