]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/sata_sil24.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild
[linux-2.6-omap-h63xx.git] / drivers / scsi / sata_sil24.c
index 032d9c093979d9000dbdbf49bd40079ac2ea1fa1..4682a50650b4914e0b219d46ba90cbb4e998c229 100644 (file)
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
+#include <linux/device.h>
 #include <scsi/scsi_host.h>
-#include "scsi.h"
+#include <scsi/scsi_cmnd.h>
 #include <linux/libata.h>
 #include <asm/io.h>
 
 #define DRV_NAME       "sata_sil24"
-#define DRV_VERSION    "0.21"  /* Silicon Image's preview driver was 0.10 */
-
-#define NR_PORTS       4
+#define DRV_VERSION    "0.22"  /* Silicon Image's preview driver was 0.10 */
 
 /*
  * Port request block (PRB) 32 bytes
@@ -198,6 +197,7 @@ enum {
        /* board id */
        BID_SIL3124             = 0,
        BID_SIL3132             = 1,
+       BID_SIL3131             = 2,
 
        IRQ_STAT_4PORTS         = 0xf,
 };
@@ -216,18 +216,19 @@ struct sil24_cmd_block {
 struct sil24_port_priv {
        struct sil24_cmd_block *cmd_block;      /* 32 cmd blocks */
        dma_addr_t cmd_block_dma;               /* DMA base addr for them */
+       struct ata_taskfile tf;                 /* Cached taskfile registers */
 };
 
 /* ap->host_set->private_data */
 struct sil24_host_priv {
-       void *host_base;        /* global controller control (128 bytes @BAR0) */
-       void *port_base;        /* port registers (4 * 8192 bytes @BAR2) */
+       void __iomem *host_base;        /* global controller control (128 bytes @BAR0) */
+       void __iomem *port_base;        /* port registers (4 * 8192 bytes @BAR2) */
 };
 
 static u8 sil24_check_status(struct ata_port *ap);
-static u8 sil24_check_err(struct ata_port *ap);
 static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
 static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void sil24_phy_reset(struct ata_port *ap);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static int sil24_qc_issue(struct ata_queued_cmd *qc);
@@ -242,6 +243,9 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 static struct pci_device_id sil24_pci_tbl[] = {
        { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
        { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
+       { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
+       { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
+       { } /* terminate list */
 };
 
 static struct pci_driver sil24_pci_driver = {
@@ -251,7 +255,7 @@ static struct pci_driver sil24_pci_driver = {
        .remove                 = ata_pci_remove_one, /* safe? */
 };
 
-static Scsi_Host_Template sil24_sht = {
+static struct scsi_host_template sil24_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
@@ -271,14 +275,15 @@ static Scsi_Host_Template sil24_sht = {
        .ordered_flush          = 1, /* NCQ not supported yet */
 };
 
-static struct ata_port_operations sil24_ops = {
+static const struct ata_port_operations sil24_ops = {
        .port_disable           = ata_port_disable,
 
        .check_status           = sil24_check_status,
        .check_altstatus        = sil24_check_status,
-       .check_err              = sil24_check_err,
        .dev_select             = ata_noop_dev_select,
 
+       .tf_read                = sil24_tf_read,
+
        .phy_reset              = sil24_phy_reset,
 
        .qc_prep                = sil24_qc_prep,
@@ -297,13 +302,20 @@ static struct ata_port_operations sil24_ops = {
        .host_stop              = sil24_host_stop,
 };
 
+/*
+ * Use bits 30-31 of host_flags to encode available port numbers.
+ * Current maxium is 4.
+ */
+#define SIL24_NPORTS2FLAG(nports)      ((((unsigned)(nports) - 1) & 0x3) << 30)
+#define SIL24_FLAG2NPORTS(flag)                ((((flag) >> 30) & 0x3) + 1)
+
 static struct ata_port_info sil24_port_info[] = {
        /* sil_3124 */
        {
                .sht            = &sil24_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
-                                 ATA_FLAG_PIO_DMA,
+                                 ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4),
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = 0x3f,                 /* udma0-5 */
@@ -314,7 +326,18 @@ static struct ata_port_info sil24_port_info[] = {
                .sht            = &sil24_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
-                                 ATA_FLAG_PIO_DMA,
+                                 ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2),
+               .pio_mask       = 0x1f,                 /* pio0-4 */
+               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
+               .udma_mask      = 0x3f,                 /* udma0-5 */
+               .port_ops       = &sil24_ops,
+       },
+       /* sil_3131/sil_3531 */
+       {
+               .sht            = &sil24_sht,
+               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+                                 ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1),
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = 0x3f,                 /* udma0-5 */
@@ -322,14 +345,21 @@ static struct ata_port_info sil24_port_info[] = {
        },
 };
 
-static u8 sil24_check_status(struct ata_port *ap)
+static inline void sil24_update_tf(struct ata_port *ap)
 {
-       return ATA_DRDY;
+       struct sil24_port_priv *pp = ap->private_data;
+       void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+       struct sil24_prb __iomem *prb = port;
+       u8 fis[6 * 4];
+
+       memcpy_fromio(fis, prb->fis, 6 * 4);
+       ata_tf_from_fis(fis, &pp->tf);
 }
 
-static u8 sil24_check_err(struct ata_port *ap)
+static u8 sil24_check_status(struct ata_port *ap)
 {
-       return 0;
+       struct sil24_port_priv *pp = ap->private_data;
+       return pp->tf.command;
 }
 
 static int sil24_scr_map[] = {
@@ -341,9 +371,9 @@ static int sil24_scr_map[] = {
 
 static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
 {
-       void *scr_addr = (void *)ap->ioaddr.scr_addr;
+       void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
        if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
-               void *addr;
+               void __iomem *addr;
                addr = scr_addr + sil24_scr_map[sc_reg] * 4;
                return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
        }
@@ -352,14 +382,20 @@ static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
 
 static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
 {
-       void *scr_addr = (void *)ap->ioaddr.scr_addr;
+       void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
        if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
-               void *addr;
+               void __iomem *addr;
                addr = scr_addr + sil24_scr_map[sc_reg] * 4;
                writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
        }
 }
 
+static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+       struct sil24_port_priv *pp = ap->private_data;
+       *tf = pp->tf;
+}
+
 static void sil24_phy_reset(struct ata_port *ap)
 {
        __sata_phy_reset(ap);
@@ -375,15 +411,20 @@ static void sil24_phy_reset(struct ata_port *ap)
 static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
                                 struct sil24_cmd_block *cb)
 {
-       struct scatterlist *sg = qc->sg;
        struct sil24_sge *sge = cb->sge;
-       unsigned i;
+       struct scatterlist *sg;
+       unsigned int idx = 0;
 
-       for (i = 0; i < qc->n_elem; i++, sg++, sge++) {
+       ata_for_each_sg(sg, qc) {
                sge->addr = cpu_to_le64(sg_dma_address(sg));
                sge->cnt = cpu_to_le32(sg_dma_len(sg));
-               sge->flags = 0;
-               sge->flags = i < qc->n_elem - 1 ? 0 : cpu_to_le32(SGE_TRM);
+               if (ata_sg_is_last(sg, qc))
+                       sge->flags = cpu_to_le32(SGE_TRM);
+               else
+                       sge->flags = 0;
+
+               sge++;
+               idx++;
        }
 }
 
@@ -413,7 +454,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
 static int sil24_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       void *port = (void *)ap->ioaddr.cmd_addr;
+       void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
        struct sil24_port_priv *pp = ap->private_data;
        dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block);
 
@@ -426,7 +467,7 @@ static void sil24_irq_clear(struct ata_port *ap)
        /* unused */
 }
 
-static int __sil24_reset_controller(void *port)
+static int __sil24_reset_controller(void __iomem *port)
 {
        int cnt;
        u32 tmp;
@@ -452,7 +493,7 @@ static void sil24_reset_controller(struct ata_port *ap)
 {
        printk(KERN_NOTICE DRV_NAME
               " ata%u: resetting controller...\n", ap->id);
-       if (__sil24_reset_controller((void *)ap->ioaddr.cmd_addr))
+       if (__sil24_reset_controller((void __iomem *)ap->ioaddr.cmd_addr))
                 printk(KERN_ERR DRV_NAME
                        " ata%u: failed to reset controller\n", ap->id);
 }
@@ -463,7 +504,7 @@ static void sil24_eng_timeout(struct ata_port *ap)
 
        qc = ata_qc_from_tag(ap, ap->active_tag);
        if (!qc) {
-               printk(KERN_ERR "ata%u: BUG: tiemout without command\n",
+               printk(KERN_ERR "ata%u: BUG: timeout without command\n",
                       ap->id);
                return;
        }
@@ -477,7 +518,7 @@ static void sil24_eng_timeout(struct ata_port *ap)
         */
        printk(KERN_ERR "ata%u: command timeout\n", ap->id);
        qc->scsidone = scsi_finish_command;
-       ata_qc_complete(qc, ATA_ERR);
+       ata_qc_complete(qc, AC_ERR_OTHER);
 
        sil24_reset_controller(ap);
 }
@@ -485,8 +526,10 @@ static void sil24_eng_timeout(struct ata_port *ap)
 static void sil24_error_intr(struct ata_port *ap, u32 slot_stat)
 {
        struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
-       void *port = (void *)ap->ioaddr.cmd_addr;
+       struct sil24_port_priv *pp = ap->private_data;
+       void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
        u32 irq_stat, cmd_err, sstatus, serror;
+       unsigned int err_mask;
 
        irq_stat = readl(port + PORT_IRQ_STAT);
        writel(irq_stat, port + PORT_IRQ_STAT);         /* clear irq */
@@ -509,8 +552,23 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat)
               "  stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n",
               ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror);
 
+       if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB) {
+               /*
+                * Device is reporting error, tf registers are valid.
+                */
+               sil24_update_tf(ap);
+               err_mask = ac_err_mask(pp->tf.command);
+       } else {
+               /*
+                * Other errors.  libata currently doesn't have any
+                * mechanism to report these errors.  Just turn on
+                * ATA_ERR.
+                */
+               err_mask = AC_ERR_OTHER;
+       }
+
        if (qc)
-               ata_qc_complete(qc, ATA_ERR);
+               ata_qc_complete(qc, err_mask);
 
        sil24_reset_controller(ap);
 }
@@ -518,13 +576,24 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat)
 static inline void sil24_host_intr(struct ata_port *ap)
 {
        struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
-       void *port = (void *)ap->ioaddr.cmd_addr;
+       void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
        u32 slot_stat;
 
        slot_stat = readl(port + PORT_SLOT_STAT);
        if (!(slot_stat & HOST_SSTAT_ATTN)) {
+               struct sil24_port_priv *pp = ap->private_data;
+               /*
+                * !HOST_SSAT_ATTN guarantees successful completion,
+                * so reading back tf registers is unnecessary for
+                * most commands.  TODO: read tf registers for
+                * commands which require these values on successful
+                * completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER,
+                * DEVICE RESET and READ PORT MULTIPLIER (any more?).
+                */
+               sil24_update_tf(ap);
+
                if (qc)
-                       ata_qc_complete(qc, 0);
+                       ata_qc_complete(qc, ac_err_mask(pp->tf.command));
        } else
                sil24_error_intr(ap, slot_stat);
 }
@@ -566,6 +635,13 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *
        return IRQ_RETVAL(handled);
 }
 
+static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
+{
+       const size_t cb_size = sizeof(*pp->cmd_block);
+
+       dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
+}
+
 static int sil24_port_start(struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
@@ -573,34 +649,44 @@ static int sil24_port_start(struct ata_port *ap)
        struct sil24_cmd_block *cb;
        size_t cb_size = sizeof(*cb);
        dma_addr_t cb_dma;
+       int rc = -ENOMEM;
 
-       pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+       pp = kzalloc(sizeof(*pp), GFP_KERNEL);
        if (!pp)
-               return -ENOMEM;
-       memset(pp, 0, sizeof(*pp));
+               goto err_out;
+
+       pp->tf.command = ATA_DRDY;
 
        cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
-       if (!cb) {
-               kfree(pp);
-               return -ENOMEM;
-       }
+       if (!cb)
+               goto err_out_pp;
        memset(cb, 0, cb_size);
 
+       rc = ata_pad_alloc(ap, dev);
+       if (rc)
+               goto err_out_pad;
+
        pp->cmd_block = cb;
        pp->cmd_block_dma = cb_dma;
 
        ap->private_data = pp;
 
        return 0;
+
+err_out_pad:
+       sil24_cblk_free(pp, dev);
+err_out_pp:
+       kfree(pp);
+err_out:
+       return rc;
 }
 
 static void sil24_port_stop(struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
        struct sil24_port_priv *pp = ap->private_data;
-       size_t cb_size = sizeof(*pp->cmd_block);
 
-       dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
+       sil24_cblk_free(pp, dev);
        kfree(pp);
 }
 
@@ -617,13 +703,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version = 0;
        unsigned int board_id = (unsigned int)ent->driver_data;
+       struct ata_port_info *pinfo = &sil24_port_info[board_id];
        struct ata_probe_ent *probe_ent = NULL;
        struct sil24_host_priv *hpriv = NULL;
-       void *host_base = NULL, *port_base = NULL;
+       void __iomem *host_base = NULL;
+       void __iomem *port_base = NULL;
        int i, rc;
 
        if (!printed_version++)
-               printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+               dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
        rc = pci_enable_device(pdev);
        if (rc)
@@ -657,12 +745,12 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
-       probe_ent->sht          = sil24_port_info[board_id].sht;
-       probe_ent->host_flags   = sil24_port_info[board_id].host_flags;
-       probe_ent->pio_mask     = sil24_port_info[board_id].pio_mask;
-       probe_ent->udma_mask    = sil24_port_info[board_id].udma_mask;
-       probe_ent->port_ops     = sil24_port_info[board_id].port_ops;
-       probe_ent->n_ports      = (board_id == BID_SIL3124) ? 4 : 2;
+       probe_ent->sht          = pinfo->sht;
+       probe_ent->host_flags   = pinfo->host_flags;
+       probe_ent->pio_mask     = pinfo->pio_mask;
+       probe_ent->udma_mask    = pinfo->udma_mask;
+       probe_ent->port_ops     = pinfo->port_ops;
+       probe_ent->n_ports      = SIL24_FLAG2NPORTS(pinfo->host_flags);
 
        probe_ent->irq = pdev->irq;
        probe_ent->irq_flags = SA_SHIRQ;
@@ -683,14 +771,14 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
         */
        rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
        if (rc) {
-               printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n",
-                      pci_name(pdev));
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "32-bit DMA enable failed\n");
                goto out_free;
        }
        rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
        if (rc) {
-               printk(KERN_ERR DRV_NAME "(%s): 32-bit consistent DMA enable failed\n",
-                      pci_name(pdev));
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "32-bit consistent DMA enable failed\n");
                goto out_free;
        }
 
@@ -701,7 +789,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        writel(0, host_base + HOST_CTRL);
 
        for (i = 0; i < probe_ent->n_ports; i++) {
-               void *port = port_base + i * PORT_REGS_SIZE;
+               void __iomem *port = port_base + i * PORT_REGS_SIZE;
                unsigned long portu = (unsigned long)port;
                u32 tmp;
                int cnt;
@@ -726,9 +814,8 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                                        break;
                        }
                        if (tmp & PORT_CS_PORT_RST)
-                               printk(KERN_ERR DRV_NAME
-                                      "(%s): failed to clear port RST\n",
-                                      pci_name(pdev));
+                               dev_printk(KERN_ERR, &pdev->dev,
+                                          "failed to clear port RST\n");
                }
 
                /* Zero error counters. */
@@ -757,9 +844,8 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
                /* Reset itself */
                if (__sil24_reset_controller(port))
-                       printk(KERN_ERR DRV_NAME
-                              "(%s): failed to reset controller\n",
-                              pci_name(pdev));
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "failed to reset controller\n");
        }
 
        /* Turn on interrupts */