ppp: fix BUG on non-linear SKB (multilink receive)
[safe/jmp/linux-2.6] / drivers / ata / libata-sff.c
index 0a8567c..bbbb1fa 100644 (file)
@@ -52,6 +52,7 @@ const struct ata_port_operations ata_sff_port_ops = {
        .softreset              = ata_sff_softreset,
        .hardreset              = sata_sff_hardreset,
        .postreset              = ata_sff_postreset,
+       .drain_fifo             = ata_sff_drain_fifo,
        .error_handler          = ata_sff_error_handler,
        .post_internal_cmd      = ata_sff_post_internal_cmd,
 
@@ -64,6 +65,8 @@ const struct ata_port_operations ata_sff_port_ops = {
        .sff_irq_on             = ata_sff_irq_on,
        .sff_irq_clear          = ata_sff_irq_clear,
 
+       .lost_interrupt         = ata_sff_lost_interrupt,
+
        .port_start             = ata_sff_port_start,
 };
 EXPORT_SYMBOL_GPL(ata_sff_port_ops);
@@ -84,6 +87,7 @@ const struct ata_port_operations ata_bmdma32_port_ops = {
        .inherits               = &ata_bmdma_port_ops,
 
        .sff_data_xfer          = ata_sff_data_xfer32,
+       .port_start             = ata_sff_port_start32,
 };
 EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops);
 
@@ -723,17 +727,23 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
        else
                iowrite16_rep(data_addr, buf, words);
 
-       /* Transfer trailing byte, if any. */
+       /* Transfer trailing byte, if any. */
        if (unlikely(buflen & 0x01)) {
-               __le16 align_buf[1] = { 0 };
-               unsigned char *trailing_buf = buf + buflen - 1;
+               unsigned char pad[2];
+
+               /* Point buf to the tail of buffer */
+               buf += buflen - 1;
 
+               /*
+                * Use io*16_rep() accessors here as well to avoid pointlessly
+                * swapping bytes to and fro on the big endian machines...
+                */
                if (rw == READ) {
-                       align_buf[0] = cpu_to_le16(ioread16(data_addr));
-                       memcpy(trailing_buf, align_buf, 1);
+                       ioread16_rep(data_addr, pad, 1);
+                       *buf = pad[0];
                } else {
-                       memcpy(align_buf, trailing_buf, 1);
-                       iowrite16(le16_to_cpu(align_buf[0]), data_addr);
+                       pad[0] = *buf;
+                       iowrite16_rep(data_addr, pad, 1);
                }
                words++;
        }
@@ -766,6 +776,9 @@ unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
        void __iomem *data_addr = ap->ioaddr.data_addr;
        unsigned int words = buflen >> 2;
        int slop = buflen & 3;
+       
+       if (!(ap->pflags & ATA_PFLAG_PIO32))
+               return ata_sff_data_xfer(dev, buf, buflen, rw);
 
        /* Transfer multiple of 4 bytes */
        if (rw == READ)
@@ -773,18 +786,32 @@ unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
        else
                iowrite32_rep(data_addr, buf, words);
 
+       /* Transfer trailing bytes, if any */
        if (unlikely(slop)) {
-               __le32 pad;
+               unsigned char pad[4];
+
+               /* Point buf to the tail of buffer */
+               buf += buflen - slop;
+
+               /*
+                * Use io*_rep() accessors here as well to avoid pointlessly
+                * swapping bytes to and fro on the big endian machines...
+                */
                if (rw == READ) {
-                       pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
-                       memcpy(buf + buflen - slop, &pad, slop);
+                       if (slop < 3)
+                               ioread16_rep(data_addr, pad, 1);
+                       else
+                               ioread32_rep(data_addr, pad, 1);
+                       memcpy(buf, pad, slop);
                } else {
-                       memcpy(&pad, buf + buflen - slop, slop);
-                       iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
+                       memcpy(pad, buf, slop);
+                       if (slop < 3)
+                               iowrite16_rep(data_addr, pad, 1);
+                       else
+                               iowrite32_rep(data_addr, pad, 1);
                }
-               words++;
        }
-       return words << 2;
+       return (buflen + 1) & ~1;
 }
 EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
 
@@ -1358,6 +1385,16 @@ fsm_start:
                                        qc->err_mask |= AC_ERR_HSM;
                                }
 
+                               /* There are oddball controllers with
+                                * status register stuck at 0x7f and
+                                * lbal/m/h at zero which makes it
+                                * pass all other presence detection
+                                * mechanisms we have.  Set NODEV_HINT
+                                * for it.  Kernel bz#7241.
+                                */
+                               if (status == 0x7f)
+                                       qc->err_mask |= AC_ERR_NODEV_HINT;
+
                                /* ata_pio_sectors() might change the
                                 * state to HSM_ST_LAST. so, the state
                                 * is changed after ata_pio_sectors().
@@ -1622,7 +1659,7 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
  *     RETURNS:
  *     One if interrupt was handled, zero if not (shared irq).
  */
-inline unsigned int ata_sff_host_intr(struct ata_port *ap,
+unsigned int ata_sff_host_intr(struct ata_port *ap,
                                      struct ata_queued_cmd *qc)
 {
        struct ata_eh_info *ehi = &ap->link.eh_info;
@@ -1751,6 +1788,48 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
 EXPORT_SYMBOL_GPL(ata_sff_interrupt);
 
 /**
+ *     ata_sff_lost_interrupt  -       Check for an apparent lost interrupt
+ *     @ap: port that appears to have timed out
+ *
+ *     Called from the libata error handlers when the core code suspects
+ *     an interrupt has been lost. If it has complete anything we can and
+ *     then return. Interface must support altstatus for this faster
+ *     recovery to occur.
+ *
+ *     Locking:
+ *     Caller holds host lock
+ */
+
+void ata_sff_lost_interrupt(struct ata_port *ap)
+{
+       u8 status;
+       struct ata_queued_cmd *qc;
+
+       /* Only one outstanding command per SFF channel */
+       qc = ata_qc_from_tag(ap, ap->link.active_tag);
+       /* Check we have a live one.. */
+       if (qc == NULL ||  !(qc->flags & ATA_QCFLAG_ACTIVE))
+               return;
+       /* We cannot lose an interrupt on a polled command */
+       if (qc->tf.flags & ATA_TFLAG_POLLING)
+               return;
+       /* See if the controller thinks it is still busy - if so the command
+          isn't a lost IRQ but is still in progress */
+       status = ata_sff_altstatus(ap);
+       if (status & ATA_BUSY)
+               return;
+
+       /* There was a command running, we are no longer busy and we have
+          no interrupt. */
+       ata_port_printk(ap, KERN_WARNING, "lost interrupt (Status 0x%x)\n",
+                                                               status);
+       /* Run the host interrupt logic as if the interrupt had not been
+          lost */
+       ata_sff_host_intr(ap, qc);
+}
+EXPORT_SYMBOL_GPL(ata_sff_lost_interrupt);
+
+/**
  *     ata_sff_freeze - Freeze SFF controller port
  *     @ap: port to freeze
  *
@@ -2042,6 +2121,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
        iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
        udelay(20);     /* FIXME: flush */
        iowrite8(ap->ctl, ioaddr->ctl_addr);
+       ap->last_ctl = ap->ctl;
 
        /* wait the port to become ready */
        return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
@@ -2166,12 +2246,47 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes)
        }
 
        /* set up device control */
-       if (ap->ioaddr.ctl_addr)
+       if (ap->ioaddr.ctl_addr) {
                iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
+               ap->last_ctl = ap->ctl;
+       }
 }
 EXPORT_SYMBOL_GPL(ata_sff_postreset);
 
 /**
+ *     ata_sff_drain_fifo - Stock FIFO drain logic for SFF controllers
+ *     @qc: command
+ *
+ *     Drain the FIFO and device of any stuck data following a command
+ *     failing to complete. In some cases this is neccessary before a
+ *     reset will recover the device.
+ *
+ */
+
+void ata_sff_drain_fifo(struct ata_queued_cmd *qc)
+{
+       int count;
+       struct ata_port *ap;
+
+       /* We only need to flush incoming data when a command was running */
+       if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+               return;
+
+       ap = qc->ap;
+       /* Drain up to 64K of data before we give up this recovery method */
+       for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
+                                               && count < 32768; count++)
+               ioread16(ap->ioaddr.data_addr);
+
+       /* Can become DEBUG later */
+       if (count)
+               ata_port_printk(ap, KERN_DEBUG,
+                       "drained %d bytes to clear DRQ.\n", count);
+
+}
+EXPORT_SYMBOL_GPL(ata_sff_drain_fifo);
+
+/**
  *     ata_sff_error_handler - Stock error handler for BMDMA controller
  *     @ap: port to handle error for
  *
@@ -2212,7 +2327,8 @@ void ata_sff_error_handler(struct ata_port *ap)
                 * really a timeout event, adjust error mask and
                 * cancel frozen state.
                 */
-               if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) {
+               if (qc->err_mask == AC_ERR_TIMEOUT
+                                               && (host_stat & ATA_DMA_ERR)) {
                        qc->err_mask = AC_ERR_HOST_BUS;
                        thaw = 1;
                }
@@ -2223,6 +2339,13 @@ void ata_sff_error_handler(struct ata_port *ap)
        ata_sff_sync(ap);               /* FIXME: We don't need this */
        ap->ops->sff_check_status(ap);
        ap->ops->sff_irq_clear(ap);
+       /* We *MUST* do FIFO draining before we issue a reset as several
+        * devices helpfully clear their internal state and will lock solid
+        * if we touch the data port post reset. Pass qc in case anyone wants
+        *  to do different PIO/DMA recovery or has per command fixups
+        */
+       if (ap->ops->drain_fifo)
+               ap->ops->drain_fifo(qc);
 
        spin_unlock_irqrestore(ap->lock, flags);
 
@@ -2289,6 +2412,29 @@ int ata_sff_port_start(struct ata_port *ap)
 EXPORT_SYMBOL_GPL(ata_sff_port_start);
 
 /**
+ *     ata_sff_port_start32 - Set port up for dma.
+ *     @ap: Port to initialize
+ *
+ *     Called just after data structures for each port are
+ *     initialized.  Allocates space for PRD table if the device
+ *     is DMA capable SFF.
+ *
+ *     May be used as the port_start() entry in ata_port_operations for
+ *     devices that are capable of 32bit PIO.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+int ata_sff_port_start32(struct ata_port *ap)
+{
+       ap->pflags |= ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE;
+       if (ap->ioaddr.bmdma_addr)
+               return ata_port_start(ap);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_sff_port_start32);
+
+/**
  *     ata_sff_std_ports - initialize ioaddr with standard port offsets.
  *     @ioaddr: IO address structure to be initialized
  *
@@ -2510,6 +2656,7 @@ void ata_bus_reset(struct ata_port *ap)
        if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
                /* set up device control for ATA_FLAG_SATA_RESET */
                iowrite8(ap->ctl, ioaddr->ctl_addr);
+               ap->last_ctl = ap->ctl;
        }
 
        DPRINTK("EXIT\n");
@@ -2931,4 +3078,3 @@ out:
 EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
 
 #endif /* CONFIG_PCI */
-