]> err.no Git - linux-2.6/blobdiff - drivers/scsi/sata_sil24.c
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / drivers / scsi / sata_sil24.c
index 47a7bfc4a6d8b8dd085a02e487ca0bd684fb6d2a..c66548025657e52339ab89d9f0a1914b8ff58111 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 <linux/libata.h>
 #include <asm/io.h>
 
 #define DRV_NAME       "sata_sil24"
-#define DRV_VERSION    "0.20"  /* 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
@@ -107,14 +106,14 @@ enum {
 
        PORT_PM                 = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */
                /* 32 bit regs */
-       PORT_CTRL_STAT          = 0x1000, /* write:ctrl, read:stat */
-       PORT_CTRL_CLR           = 0x1004,
-       PORT_IRQ_STAT           = 0x1008,
-       PORT_IRQ_ENABLE_SET     = 0x1010,
-       PORT_IRQ_ENABLE_CLR     = 0x1014,
+       PORT_CTRL_STAT          = 0x1000, /* write: ctrl-set, read: stat */
+       PORT_CTRL_CLR           = 0x1004, /* write: ctrl-clear */
+       PORT_IRQ_STAT           = 0x1008, /* high: status, low: interrupt */
+       PORT_IRQ_ENABLE_SET     = 0x1010, /* write: enable-set */
+       PORT_IRQ_ENABLE_CLR     = 0x1014, /* write: enable-clear */
        PORT_ACTIVATE_UPPER_ADDR= 0x101c,
-       PORT_EXEC_FIFO          = 0x1020,
-       PORT_CMD_ERR            = 0x1024,
+       PORT_EXEC_FIFO          = 0x1020, /* command execution fifo */
+       PORT_CMD_ERR            = 0x1024, /* command error number */
        PORT_FIS_CFG            = 0x1028,
        PORT_FIFO_THRES         = 0x102c,
                /* 16 bit regs */
@@ -140,10 +139,10 @@ enum {
        PORT_CS_DEV_RST         = (1 << 1), /* device reset */
        PORT_CS_INIT            = (1 << 2), /* port initialize */
        PORT_CS_IRQ_WOC         = (1 << 3), /* interrupt write one to clear */
-       PORT_CS_RESUME          = (1 << 4), /* port resume */
-       PORT_CS_32BIT_ACTV      = (1 << 5), /* 32-bit activation */
-       PORT_CS_PM_EN           = (1 << 6), /* port multiplier enable */
-       PORT_CS_RDY             = (1 << 7), /* port ready to accept commands */
+       PORT_CS_RESUME          = (1 << 6), /* port resume */
+       PORT_CS_32BIT_ACTV      = (1 << 10), /* 32-bit activation */
+       PORT_CS_PM_EN           = (1 << 13), /* port multiplier enable */
+       PORT_CS_RDY             = (1 << 31), /* port ready to accept commands */
 
        /* PORT_IRQ_STAT/ENABLE_SET/CLR */
        /* bits[11:0] are masked */
@@ -187,7 +186,7 @@ enum {
        PORT_CERR_XFR_TGTABRT   = 33, /* PSD ecode 01 - target abort */
        PORT_CERR_XFR_MSGABRT   = 34, /* PSD ecode 10 - master abort */
        PORT_CERR_XFR_PCIPERR   = 35, /* PSD ecode 11 - PCI prity err during transfer */
-       PORT_CERR_SENDSERVICE   = 36, /* FIS received whiel sending service */
+       PORT_CERR_SENDSERVICE   = 36, /* FIS received while sending service */
 
        /*
         * Other constants
@@ -198,6 +197,7 @@ enum {
        /* board id */
        BID_SIL3124             = 0,
        BID_SIL3132             = 1,
+       BID_SIL3131             = 2,
 
        IRQ_STAT_4PORTS         = 0xf,
 };
@@ -214,21 +214,21 @@ struct sil24_cmd_block {
  * here from the previous interrupt.
  */
 struct sil24_port_priv {
-       void *port;
        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);
@@ -243,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 = {
@@ -272,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,
@@ -298,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 */
@@ -315,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 */
@@ -323,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[] = {
@@ -342,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);
        }
@@ -353,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);
@@ -414,10 +449,11 @@ 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 __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);
 
-       writel((u32)paddr, pp->port + PORT_CMD_ACTIVATE);
+       writel((u32)paddr, port + PORT_CMD_ACTIVATE);
        return 0;
 }
 
@@ -426,16 +462,11 @@ static void sil24_irq_clear(struct ata_port *ap)
        /* unused */
 }
 
-static void sil24_reset_controller(struct ata_port *ap)
+static int __sil24_reset_controller(void __iomem *port)
 {
-       struct sil24_port_priv *pp = ap->private_data;
-       void *port = pp->port;
        int cnt;
        u32 tmp;
 
-       printk(KERN_NOTICE DRV_NAME
-              " ata%u: resetting controller...\n", ap->id);
-
        /* Reset controller state.  Is this correct? */
        writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
        readl(port + PORT_CTRL_STAT);   /* sync */
@@ -447,9 +478,19 @@ static void sil24_reset_controller(struct ata_port *ap)
                if (!(tmp & PORT_CS_DEV_RST))
                        break;
        }
+
        if (tmp & PORT_CS_DEV_RST)
-               printk(KERN_ERR DRV_NAME
-                      " ata%u: failed to reset controller\n", ap->id);
+               return -1;
+       return 0;
+}
+
+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 __iomem *)ap->ioaddr.cmd_addr))
+                printk(KERN_ERR DRV_NAME
+                       " ata%u: failed to reset controller\n", ap->id);
 }
 
 static void sil24_eng_timeout(struct ata_port *ap)
@@ -458,7 +499,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;
        }
@@ -472,7 +513,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);
 }
@@ -481,18 +522,24 @@ 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);
        struct sil24_port_priv *pp = ap->private_data;
-       void *port = pp->port;
+       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 */
+
+       if (!(irq_stat & PORT_IRQ_ERROR)) {
+               /* ignore non-completion, non-error irqs for now */
+               printk(KERN_WARNING DRV_NAME
+                      "ata%u: non-error exception irq (irq_stat %x)\n",
+                      ap->id, irq_stat);
+               return;
+       }
+
        cmd_err = readl(port + PORT_CMD_ERR);
        sstatus = readl(port + PORT_SSTATUS);
        serror = readl(port + PORT_SERROR);
-
-       /* Clear IRQ/errors */
-       writel(irq_stat, port + PORT_IRQ_STAT);
-       if (cmd_err)
-               writel(cmd_err, port + PORT_CMD_ERR);
        if (serror)
                writel(serror, port + PORT_SERROR);
 
@@ -500,8 +547,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);
 }
@@ -509,14 +571,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);
-       struct sil24_port_priv *pp = ap->private_data;
-       void *port = pp->port;
+       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);
 }
@@ -561,7 +633,6 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *
 static int sil24_port_start(struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
-       struct sil24_host_priv *hpriv = ap->host_set->private_data;
        struct sil24_port_priv *pp;
        struct sil24_cmd_block *cb;
        size_t cb_size = sizeof(*cb);
@@ -572,6 +643,8 @@ static int sil24_port_start(struct ata_port *ap)
                return -ENOMEM;
        memset(pp, 0, sizeof(*pp));
 
+       pp->tf.command = ATA_DRDY;
+
        cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
        if (!cb) {
                kfree(pp);
@@ -579,7 +652,6 @@ static int sil24_port_start(struct ata_port *ap)
        }
        memset(cb, 0, cb_size);
 
-       pp->port = hpriv->port_base + ap->port_no * PORT_REGS_SIZE;
        pp->cmd_block = cb;
        pp->cmd_block_dma = cb_dma;
 
@@ -611,13 +683,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)
@@ -651,12 +725,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;
@@ -677,14 +751,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;
        }
 
@@ -695,12 +769,12 @@ 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;
 
-               probe_ent->port[i].cmd_addr = portu;
+               probe_ent->port[i].cmd_addr = portu + PORT_PRB;
                probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
 
                ata_std_ports(&probe_ent->port[i]);
@@ -720,9 +794,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. */
@@ -745,6 +818,14 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                /* Clear interrupts */
                writel(0x0fff0fff, port + PORT_IRQ_STAT);
                writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+               /* Clear port multiplier enable and resume bits */
+               writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
+
+               /* Reset itself */
+               if (__sil24_reset_controller(port))
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "failed to reset controller\n");
        }
 
        /* Turn on interrupts */