sata_mv: Clean up hard coded array size calculation.
[safe/jmp/linux-2.6] / drivers / ata / sata_inic162x.c
index cdae435..4406902 100644 (file)
  * right.  Documentation is available at initio's website but it only
  * documents registers (not programming model).
  *
- * - ATA disks work.
- * - Hotplug works.
- * - ATAPI read works but burning doesn't.  This thing is really
- *   peculiar about ATAPI and I couldn't figure out how ATAPI PIO and
- *   ATAPI DMA WRITE should be programmed.  If you've got a clue, be
- *   my guest.
- * - Both STR and STD work.
+ * This driver has interesting history.  The first version was written
+ * from the documentation and a 2.4 IDE driver posted on a Taiwan
+ * company, which didn't use any IDMA features and couldn't handle
+ * LBA48.  The resulting driver couldn't handle LBA48 devices either
+ * making it pretty useless.
+ *
+ * After a while, initio picked the driver up, renamed it to
+ * sata_initio162x, updated it to use IDMA for ATA DMA commands and
+ * posted it on their website.  It only used ATA_PROT_DMA for IDMA and
+ * attaching both devices and issuing IDMA and !IDMA commands
+ * simultaneously broke it due to PIRQ masking interaction but it did
+ * show how to use the IDMA (ADMA + some initio specific twists)
+ * engine.
+ *
+ * Then, I picked up their changes again and here's the usable driver
+ * which uses IDMA for everything.  Everything works now including
+ * LBA48, CD/DVD burning, suspend/resume and hotplug.  There are some
+ * issues tho.  Result Tf is not resported properly, NCQ isn't
+ * supported yet and CD/DVD writing works with DMA assisted PIO
+ * protocol (which, for native SATA devices, shouldn't cause any
+ * noticeable difference).
+ *
+ * Anyways, so, here's finally a working driver for inic162x.  Enjoy!
+ *
+ * initio: If you guys wanna improve the driver regarding result TF
+ * access and other stuff, please feel free to contact me.  I'll be
+ * happy to assist.
  */
 
 #include <linux/kernel.h>
 #include <scsi/scsi_device.h>
 
 #define DRV_NAME       "sata_inic162x"
-#define DRV_VERSION    "0.3"
+#define DRV_VERSION    "0.4"
 
 enum {
-       MMIO_BAR                = 5,
+       MMIO_BAR_PCI            = 5,
+       MMIO_BAR_CARDBUS        = 1,
 
        NR_PORTS                = 2,
 
@@ -75,6 +96,7 @@ enum {
        PORT_SCR                = 0x20,
 
        /* HOST_CTL bits */
+       HCTL_LEDEN              = (1 << 3),  /* enable LED operation */
        HCTL_IRQOFF             = (1 << 8),  /* global IRQ off */
        HCTL_FTHD0              = (1 << 10), /* fifo threshold 0 */
        HCTL_FTHD1              = (1 << 11), /* fifo threshold 1*/
@@ -101,7 +123,7 @@ enum {
        PIRQ_PENDING            = (1 << 7),  /* port IRQ pending (STAT only) */
 
        PIRQ_ERR                = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL,
-       PIRQ_MASK_DEFAULT       = PIRQ_REPLY,
+       PIRQ_MASK_DEFAULT       = PIRQ_REPLY | PIRQ_ATA,
        PIRQ_MASK_FREEZE        = 0xff,
 
        /* PORT_PRD_CTL bits */
@@ -197,6 +219,7 @@ struct inic_pkt {
 } __packed;
 
 struct inic_host_priv {
+       void __iomem    *mmio_base;
        u16             cached_hctl;
 };
 
@@ -221,37 +244,34 @@ static const int scr_map[] = {
 
 static void __iomem *inic_port_base(struct ata_port *ap)
 {
-       return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
+       struct inic_host_priv *hpriv = ap->host->private_data;
+
+       return hpriv->mmio_base + ap->port_no * PORT_SIZE;
 }
 
 static void inic_reset_port(void __iomem *port_base)
 {
        void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
-       u16 ctl;
 
-       ctl = readw(idma_ctl);
-       ctl &= ~(IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN | IDMA_CTL_GO);
+       /* stop IDMA engine */
+       readw(idma_ctl); /* flush */
+       msleep(1);
 
        /* mask IRQ and assert reset */
-       writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl);
+       writew(IDMA_CTL_RST_IDMA, idma_ctl);
        readw(idma_ctl); /* flush */
-
-       /* give it some time */
        msleep(1);
 
        /* release reset */
-       writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl);
+       writew(0, idma_ctl);
 
        /* clear irq */
        writeb(0xff, port_base + PORT_IRQ_STAT);
-
-       /* reenable ATA IRQ, turn off IDMA mode */
-       writew(ctl, idma_ctl);
 }
 
-static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
+static int inic_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val)
 {
-       void __iomem *scr_addr = ap->ioaddr.scr_addr;
+       void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
        void __iomem *addr;
 
        if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
@@ -266,9 +286,9 @@ static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
        return 0;
 }
 
-static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_link *link, unsigned sc_reg, u32 val)
 {
-       void __iomem *scr_addr = ap->ioaddr.scr_addr;
+       void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
 
        if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
                return -EINVAL;
@@ -357,10 +377,8 @@ static void inic_host_intr(struct ata_port *ap)
        if (unlikely((irq_stat & PIRQ_ERR) || (idma_stat & IDMA_STAT_ERR)))
                inic_host_err_intr(ap, irq_stat, idma_stat);
 
-       if (unlikely(!qc)) {
-               ap->ops->sff_check_status(ap); /* clear ATA interrupt */
+       if (unlikely(!qc))
                goto spurious;
-       }
 
        if (likely(idma_stat & IDMA_STAT_DONE)) {
                inic_stop_idma(ap);
@@ -377,17 +395,19 @@ static void inic_host_intr(struct ata_port *ap)
        }
 
  spurious:
-       ap->ops->sff_check_status(ap); /* clear ATA interrupt */
+       ata_port_printk(ap, KERN_WARNING, "unhandled interrupt: "
+                       "cmd=0x%x irq_stat=0x%x idma_stat=0x%x\n",
+                       qc ? qc->tf.command : 0xff, irq_stat, idma_stat);
 }
 
 static irqreturn_t inic_interrupt(int irq, void *dev_instance)
 {
        struct ata_host *host = dev_instance;
-       void __iomem *mmio_base = host->iomap[MMIO_BAR];
+       struct inic_host_priv *hpriv = host->private_data;
        u16 host_irq_stat;
-       int i, handled = 0;;
+       int i, handled = 0;
 
-       host_irq_stat = readw(mmio_base + HOST_IRQ_STAT);
+       host_irq_stat = readw(hpriv->mmio_base + HOST_IRQ_STAT);
 
        if (unlikely(!(host_irq_stat & HIRQ_GLOBAL)))
                goto out;
@@ -521,7 +541,7 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
        void __iomem *port_base = inic_port_base(ap);
 
        /* fire up the ADMA engine */
-       writew(HCTL_FTHD0, port_base + HOST_CTL);
+       writew(HCTL_FTHD0 | HCTL_LEDEN, port_base + HOST_CTL);
        writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
        writeb(0, port_base + PORT_CPB_PTQFIFO);
 
@@ -568,7 +588,6 @@ static void inic_freeze(struct ata_port *ap)
        void __iomem *port_base = inic_port_base(ap);
 
        writeb(PIRQ_MASK_FREEZE, port_base + PORT_IRQ_MASK);
-       ap->ops->sff_check_status(ap);
        writeb(0xff, port_base + PORT_IRQ_STAT);
 }
 
@@ -576,7 +595,6 @@ static void inic_thaw(struct ata_port *ap)
 {
        void __iomem *port_base = inic_port_base(ap);
 
-       ap->ops->sff_check_status(ap);
        writeb(0xff, port_base + PORT_IRQ_STAT);
        writeb(PIRQ_MASK_DEFAULT, port_base + PORT_IRQ_MASK);
 }
@@ -599,17 +617,15 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
        void __iomem *port_base = inic_port_base(ap);
        void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
        const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
-       u16 val;
        int rc;
 
        /* hammer it into sane state */
        inic_reset_port(port_base);
 
-       val = readw(idma_ctl);
-       writew(val | IDMA_CTL_RST_ATA, idma_ctl);
+       writew(IDMA_CTL_RST_ATA, idma_ctl);
        readw(idma_ctl);        /* flush */
        msleep(1);
-       writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
+       writew(0, idma_ctl);
 
        rc = sata_link_resume(link, timing, deadline);
        if (rc) {
@@ -641,16 +657,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
 static void inic_error_handler(struct ata_port *ap)
 {
        void __iomem *port_base = inic_port_base(ap);
-       unsigned long flags;
 
-       /* reset PIO HSM and stop DMA engine */
        inic_reset_port(port_base);
-
-       spin_lock_irqsave(ap->lock, flags);
-       ap->hsm_task_state = HSM_ST_IDLE;
-       spin_unlock_irqrestore(ap->lock, flags);
-
-       /* PIO and DMA engines have been stopped, perform recovery */
        ata_std_error_handler(ap);
 }
 
@@ -714,7 +722,7 @@ static int inic_port_start(struct ata_port *ap)
 }
 
 static struct ata_port_operations inic_port_ops = {
-       .inherits               = &ata_sff_port_ops,
+       .inherits               = &sata_port_ops,
 
        .check_atapi_dma        = inic_check_atapi_dma,
        .qc_prep                = inic_qc_prep,
@@ -723,7 +731,6 @@ static struct ata_port_operations inic_port_ops = {
 
        .freeze                 = inic_freeze,
        .thaw                   = inic_thaw,
-       .softreset              = ATA_OP_NULL,  /* softreset is broken */
        .hardreset              = inic_hardreset,
        .error_handler          = inic_error_handler,
        .post_internal_cmd      = inic_post_internal_cmd,
@@ -737,8 +744,8 @@ static struct ata_port_operations inic_port_ops = {
 
 static struct ata_port_info inic_port_info = {
        .flags                  = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
-       .pio_mask               = 0x1f, /* pio0-4 */
-       .mwdma_mask             = 0x07, /* mwdma0-2 */
+       .pio_mask               = ATA_PIO4,
+       .mwdma_mask             = ATA_MWDMA2,
        .udma_mask              = ATA_UDMA6,
        .port_ops               = &inic_port_ops
 };
@@ -788,7 +795,6 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
        struct inic_host_priv *hpriv = host->private_data;
-       void __iomem *mmio_base = host->iomap[MMIO_BAR];
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
@@ -796,7 +802,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
                return rc;
 
        if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
-               rc = init_controller(mmio_base, hpriv->cached_hctl);
+               rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
                if (rc)
                        return rc;
        }
@@ -814,6 +820,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct ata_host *host;
        struct inic_host_priv *hpriv;
        void __iomem * const *iomap;
+       int mmio_bar;
        int i, rc;
 
        if (!printed_version++)
@@ -827,48 +834,41 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        host->private_data = hpriv;
 
-       /* acquire resources and fill host */
+       /* Acquire resources and fill host.  Note that PCI and cardbus
+        * use different BARs.
+        */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
 
-       rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
+       if (pci_resource_flags(pdev, MMIO_BAR_PCI) & IORESOURCE_MEM)
+               mmio_bar = MMIO_BAR_PCI;
+       else
+               mmio_bar = MMIO_BAR_CARDBUS;
+
+       rc = pcim_iomap_regions(pdev, 1 << mmio_bar, DRV_NAME);
        if (rc)
                return rc;
        host->iomap = iomap = pcim_iomap_table(pdev);
+       hpriv->mmio_base = iomap[mmio_bar];
+       hpriv->cached_hctl = readw(hpriv->mmio_base + HOST_CTL);
 
        for (i = 0; i < NR_PORTS; i++) {
                struct ata_port *ap = host->ports[i];
-               struct ata_ioports *port = &ap->ioaddr;
-               unsigned int offset = i * PORT_SIZE;
-
-               port->cmd_addr = iomap[2 * i];
-               port->altstatus_addr =
-               port->ctl_addr = (void __iomem *)
-                       ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
-               port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
-
-               ata_sff_std_ports(port);
-
-               ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
-               ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
-               ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
-                 (unsigned long long)pci_resource_start(pdev, 2 * i),
-                 (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
-                                     ATA_PCI_CTL_OFS);
-       }
 
-       hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
+               ata_port_pbar_desc(ap, mmio_bar, -1, "mmio");
+               ata_port_pbar_desc(ap, mmio_bar, i * PORT_SIZE, "port");
+       }
 
        /* Set dma_mask.  This devices doesn't support 64bit addressing. */
-       rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
        if (rc) {
                dev_printk(KERN_ERR, &pdev->dev,
                           "32-bit DMA enable failed\n");
                return rc;
        }
 
-       rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
        if (rc) {
                dev_printk(KERN_ERR, &pdev->dev,
                           "32-bit consistent DMA enable failed\n");
@@ -887,7 +887,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                return rc;
        }
 
-       rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
+       rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
        if (rc) {
                dev_printk(KERN_ERR, &pdev->dev,
                           "failed to initialize controller\n");