]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ata/sata_mv.c
Pull now into release branch
[linux-2.6-omap-h63xx.git] / drivers / ata / sata_mv.c
index 5d576435fcccddd5fe0498c57c90c058e436de65..11bf6c7ac12260d4ba40551b5eef854022ab8eb3 100644 (file)
@@ -35,8 +35,6 @@
 
   6) Add port multiplier support (intermediate)
 
-  7) Test and verify 3.0 Gbps support
-
   8) Develop a low-power-consumption strategy, and implement it.
 
   9) [Experiment, low priority] See if ATAPI can be supported using
@@ -74,7 +72,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_mv"
-#define DRV_VERSION    "0.81"
+#define DRV_VERSION    "1.0"
 
 enum {
        /* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -227,26 +225,26 @@ enum {
 
        EDMA_ERR_IRQ_CAUSE_OFS  = 0x8,
        EDMA_ERR_IRQ_MASK_OFS   = 0xc,
-       EDMA_ERR_D_PAR          = (1 << 0),
-       EDMA_ERR_PRD_PAR        = (1 << 1),
-       EDMA_ERR_DEV            = (1 << 2),
-       EDMA_ERR_DEV_DCON       = (1 << 3),
-       EDMA_ERR_DEV_CON        = (1 << 4),
-       EDMA_ERR_SERR           = (1 << 5),
+       EDMA_ERR_D_PAR          = (1 << 0),     /* UDMA data parity err */
+       EDMA_ERR_PRD_PAR        = (1 << 1),     /* UDMA PRD parity err */
+       EDMA_ERR_DEV            = (1 << 2),     /* device error */
+       EDMA_ERR_DEV_DCON       = (1 << 3),     /* device disconnect */
+       EDMA_ERR_DEV_CON        = (1 << 4),     /* device connected */
+       EDMA_ERR_SERR           = (1 << 5),     /* SError bits [WBDST] raised */
        EDMA_ERR_SELF_DIS       = (1 << 7),     /* Gen II/IIE self-disable */
        EDMA_ERR_SELF_DIS_5     = (1 << 8),     /* Gen I self-disable */
-       EDMA_ERR_BIST_ASYNC     = (1 << 8),
+       EDMA_ERR_BIST_ASYNC     = (1 << 8),     /* BIST FIS or Async Notify */
        EDMA_ERR_TRANS_IRQ_7    = (1 << 8),     /* Gen IIE transprt layer irq */
-       EDMA_ERR_CRBQ_PAR       = (1 << 9),
-       EDMA_ERR_CRPB_PAR       = (1 << 10),
-       EDMA_ERR_INTRL_PAR      = (1 << 11),
-       EDMA_ERR_IORDY          = (1 << 12),
-       EDMA_ERR_LNK_CTRL_RX    = (0xf << 13),
+       EDMA_ERR_CRQB_PAR       = (1 << 9),     /* CRQB parity error */
+       EDMA_ERR_CRPB_PAR       = (1 << 10),    /* CRPB parity error */
+       EDMA_ERR_INTRL_PAR      = (1 << 11),    /* internal parity error */
+       EDMA_ERR_IORDY          = (1 << 12),    /* IORdy timeout */
+       EDMA_ERR_LNK_CTRL_RX    = (0xf << 13),  /* link ctrl rx error */
        EDMA_ERR_LNK_CTRL_RX_2  = (1 << 15),
-       EDMA_ERR_LNK_DATA_RX    = (0xf << 17),
-       EDMA_ERR_LNK_CTRL_TX    = (0x1f << 21),
-       EDMA_ERR_LNK_DATA_TX    = (0x1f << 26),
-       EDMA_ERR_TRANS_PROTO    = (1 << 31),
+       EDMA_ERR_LNK_DATA_RX    = (0xf << 17),  /* link data rx error */
+       EDMA_ERR_LNK_CTRL_TX    = (0x1f << 21), /* link ctrl tx error */
+       EDMA_ERR_LNK_DATA_TX    = (0x1f << 26), /* link data tx error */
+       EDMA_ERR_TRANS_PROTO    = (1 << 31),    /* transport protocol error */
        EDMA_ERR_OVERRUN_5      = (1 << 5),
        EDMA_ERR_UNDERRUN_5     = (1 << 6),
        EDMA_EH_FREEZE          = EDMA_ERR_D_PAR |
@@ -255,7 +253,7 @@ enum {
                                  EDMA_ERR_DEV_CON |
                                  EDMA_ERR_SERR |
                                  EDMA_ERR_SELF_DIS |
-                                 EDMA_ERR_CRBQ_PAR |
+                                 EDMA_ERR_CRQB_PAR |
                                  EDMA_ERR_CRPB_PAR |
                                  EDMA_ERR_INTRL_PAR |
                                  EDMA_ERR_IORDY |
@@ -270,7 +268,7 @@ enum {
                                  EDMA_ERR_OVERRUN_5 |
                                  EDMA_ERR_UNDERRUN_5 |
                                  EDMA_ERR_SELF_DIS_5 |
-                                 EDMA_ERR_CRBQ_PAR |
+                                 EDMA_ERR_CRQB_PAR |
                                  EDMA_ERR_CRPB_PAR |
                                  EDMA_ERR_INTRL_PAR |
                                  EDMA_ERR_IORDY,
@@ -286,10 +284,10 @@ enum {
        EDMA_RSP_Q_OUT_PTR_OFS  = 0x24,         /* also contains BASE_LO */
        EDMA_RSP_Q_PTR_SHIFT    = 3,
 
-       EDMA_CMD_OFS            = 0x28,
-       EDMA_EN                 = (1 << 0),
-       EDMA_DS                 = (1 << 1),
-       ATA_RST                 = (1 << 2),
+       EDMA_CMD_OFS            = 0x28,         /* EDMA command register */
+       EDMA_EN                 = (1 << 0),     /* enable EDMA */
+       EDMA_DS                 = (1 << 1),     /* disable EDMA; self-negated */
+       ATA_RST                 = (1 << 2),     /* reset trans/link/phy */
 
        EDMA_IORDY_TMOUT        = 0x34,
        EDMA_ARB_CFG            = 0x38,
@@ -301,14 +299,13 @@ enum {
        MV_HP_ERRATA_60X1B2     = (1 << 3),
        MV_HP_ERRATA_60X1C0     = (1 << 4),
        MV_HP_ERRATA_XX42A0     = (1 << 5),
-       MV_HP_GEN_I             = (1 << 6),
-       MV_HP_GEN_II            = (1 << 7),
-       MV_HP_GEN_IIE           = (1 << 8),
+       MV_HP_GEN_I             = (1 << 6),     /* Generation I: 50xx */
+       MV_HP_GEN_II            = (1 << 7),     /* Generation II: 60xx */
+       MV_HP_GEN_IIE           = (1 << 8),     /* Generation IIE: 6042/7042 */
 
        /* Port private flags (pp_flags) */
-       MV_PP_FLAG_EDMA_EN      = (1 << 0),
-       MV_PP_FLAG_EDMA_DS_ACT  = (1 << 1),
-       MV_PP_FLAG_HAD_A_RESET  = (1 << 2),
+       MV_PP_FLAG_EDMA_EN      = (1 << 0),     /* is EDMA engine enabled? */
+       MV_PP_FLAG_HAD_A_RESET  = (1 << 2),     /* 1st hard reset complete? */
 };
 
 #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -318,8 +315,12 @@ enum {
 enum {
        MV_DMA_BOUNDARY         = 0xffffffffU,
 
+       /* mask of register bits containing lower 32 bits
+        * of EDMA request queue DMA address
+        */
        EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
 
+       /* ditto, for response queue */
        EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
 };
 
@@ -403,10 +404,10 @@ struct mv_host_priv {
 };
 
 static void mv_irq_clear(struct ata_port *ap);
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
 static int mv_port_start(struct ata_port *ap);
 static void mv_port_stop(struct ata_port *ap);
 static void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -620,6 +621,9 @@ static const struct pci_device_id mv_pci_tbl[] = {
        { PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
        { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
        { PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
+       /* RocketRAID 1740/174x have different identifiers */
+       { PCI_VDEVICE(TTI, 0x1740), chip_508x },
+       { PCI_VDEVICE(TTI, 0x1742), chip_508x },
 
        { PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
        { PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
@@ -823,7 +827,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
 }
 
 /**
- *      mv_stop_dma - Disable eDMA engine
+ *      __mv_stop_dma - Disable eDMA engine
  *      @ap: ATA channel to manipulate
  *
  *      Verify the local cache of the eDMA state is accurate with a
@@ -832,7 +836,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_stop_dma(struct ata_port *ap)
+static int __mv_stop_dma(struct ata_port *ap)
 {
        void __iomem *port_mmio = mv_ap_base(ap);
        struct mv_port_priv *pp = ap->private_data;
@@ -865,6 +869,18 @@ static int mv_stop_dma(struct ata_port *ap)
        return err;
 }
 
+static int mv_stop_dma(struct ata_port *ap)
+{
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&ap->host->lock, flags);
+       rc = __mv_stop_dma(ap);
+       spin_unlock_irqrestore(&ap->host->lock, flags);
+
+       return rc;
+}
+
 #ifdef ATA_DEBUG
 static void mv_dump_mem(void __iomem *start, unsigned bytes)
 {
@@ -961,22 +977,26 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
        return ofs;
 }
 
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
        unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-       if (0xffffffffU != ofs)
-               return readl(mv_ap_base(ap) + ofs);
-       else
-               return (u32) ofs;
+       if (ofs != 0xffffffffU) {
+               *val = readl(mv_ap_base(ap) + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
        unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-       if (0xffffffffU != ofs)
+       if (ofs != 0xffffffffU) {
                writelfl(val, mv_ap_base(ap) + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
 static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
@@ -1029,6 +1049,7 @@ static int mv_port_start(struct ata_port *ap)
        void __iomem *port_mmio = mv_ap_base(ap);
        void *mem;
        dma_addr_t mem_dma;
+       unsigned long flags;
        int rc;
 
        pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
@@ -1067,10 +1088,14 @@ static int mv_port_start(struct ata_port *ap)
        pp->sg_tbl = mem;
        pp->sg_tbl_dma = mem_dma;
 
+       spin_lock_irqsave(&ap->host->lock, flags);
+
        mv_edma_cfg(ap, hpriv, port_mmio);
 
        mv_set_edma_ptrs(port_mmio, hpriv, pp);
 
+       spin_unlock_irqrestore(&ap->host->lock, flags);
+
        /* Don't turn on EDMA here...do it before DMA commands only.  Else
         * we'll be unable to send non-data, PIO, etc due to restricted access
         * to shadow regs.
@@ -1090,11 +1115,7 @@ static int mv_port_start(struct ata_port *ap)
  */
 static void mv_port_stop(struct ata_port *ap)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ap->host->lock, flags);
        mv_stop_dma(ap);
-       spin_unlock_irqrestore(&ap->host->lock, flags);
 }
 
 /**
@@ -1325,7 +1346,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
                 * port.  Turn off EDMA so there won't be problems accessing
                 * shadow block, etc registers.
                 */
-               mv_stop_dma(ap);
+               __mv_stop_dma(ap);
                return ata_qc_issue_prot(qc);
        }
 
@@ -1393,16 +1414,16 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
        if (edma_err_cause & EDMA_ERR_DEV)
                err_mask |= AC_ERR_DEV;
        if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
-                       EDMA_ERR_CRBQ_PAR | EDMA_ERR_CRPB_PAR |
+                       EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
                        EDMA_ERR_INTRL_PAR)) {
                err_mask |= AC_ERR_ATA_BUS;
                action |= ATA_EH_HARDRESET;
-               ata_ehi_push_desc(ehi, "parity error");
+               ata_ehi_push_desc(ehi, "parity error");
        }
        if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
                ata_ehi_hotplugged(ehi);
                ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
-                       ", dev disconnect" : ", dev connect");
+                       "dev disconnect" : "dev connect");
        }
 
        if (IS_GEN_I(hpriv)) {
@@ -1411,7 +1432,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
                        struct mv_port_priv *pp = ap->private_data;
                        pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-                       ata_ehi_push_desc(ehi, "EDMA self-disable");
+                       ata_ehi_push_desc(ehi, "EDMA self-disable");
                }
        } else {
                eh_freeze_mask = EDMA_EH_FREEZE;
@@ -1419,7 +1440,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                if (edma_err_cause & EDMA_ERR_SELF_DIS) {
                        struct mv_port_priv *pp = ap->private_data;
                        pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-                       ata_ehi_push_desc(ehi, "EDMA self-disable");
+                       ata_ehi_push_desc(ehi, "EDMA self-disable");
                }
 
                if (edma_err_cause & EDMA_ERR_SERR) {
@@ -1489,33 +1510,30 @@ static void mv_intr_edma(struct ata_port *ap)
 
        while (1) {
                u16 status;
+               unsigned int tag;
 
                /* get s/w response queue last-read pointer, and compare */
                out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
                if (in_index == out_index)
                        break;
 
-                
                /* 50xx: get active ATA command */
-               if (IS_GEN_I(hpriv)) 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+               if (IS_GEN_I(hpriv))
+                       tag = ap->active_tag;
 
-               /* 60xx: get active ATA command via tag, to enable support
-                * for queueing.  this works transparently for queued and
-                * non-queued modes.
+               /* Gen II/IIE: get active ATA command via tag, to enable
+                * support for queueing.  this works transparently for
+                * queued and non-queued modes.
                 */
-               else {
-                       unsigned int tag;
+               else if (IS_GEN_II(hpriv))
+                       tag = (le16_to_cpu(pp->crpb[out_index].id)
+                               >> CRPB_IOID_SHIFT_6) & 0x3f;
 
-                       if (IS_GEN_II(hpriv))
-                               tag = (le16_to_cpu(pp->crpb[out_index].id)
-                                       >> CRPB_IOID_SHIFT_6) & 0x3f;
-                       else
-                               tag = (le16_to_cpu(pp->crpb[out_index].id)
-                                       >> CRPB_IOID_SHIFT_7) & 0x3f;
+               else /* IS_GEN_IIE */
+                       tag = (le16_to_cpu(pp->crpb[out_index].id)
+                               >> CRPB_IOID_SHIFT_7) & 0x3f;
 
-                       qc = ata_qc_from_tag(ap, tag);
-               }
+               qc = ata_qc_from_tag(ap, tag);
 
                /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
                 * bits (WARNING: might not necessarily be associated
@@ -1535,7 +1553,7 @@ static void mv_intr_edma(struct ata_port *ap)
                        ata_qc_complete(qc);
                }
 
-               /* advance software response queue pointer, to 
+               /* advance software response queue pointer, to
                 * indicate (after the loop completes) to hardware
                 * that we have consumed a response queue entry.
                 */
@@ -1741,26 +1759,30 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
        return ofs;
 }
 
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
        void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-       if (ofs != 0xffffffffU)
-               return readl(addr + ofs);
-       else
-               return (u32) ofs;
+       if (ofs != 0xffffffffU) {
+               *val = readl(addr + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
        void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-       if (ofs != 0xffffffffU)
+       if (ofs != 0xffffffffU) {
                writelfl(val, addr + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
 static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
@@ -2138,9 +2160,17 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
 
        VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
 
-       DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
-               "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-               mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+       {
+               u32 sstatus, serror, scontrol;
+
+               mv_scr_read(ap, SCR_STATUS, &sstatus);
+               mv_scr_read(ap, SCR_ERROR, &serror);
+               mv_scr_read(ap, SCR_CONTROL, &scontrol);
+               DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+                       "SCtrl 0x%08x\n", status, serror, scontrol);
+       }
+#endif
 
        /* Issue COMRESET via SControl */
 comreset_retry:
@@ -2164,9 +2194,17 @@ comreset_retry:
            (retry-- > 0))
                goto comreset_retry;
 
-       DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
-               "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-               mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+       {
+               u32 sstatus, serror, scontrol;
+
+               mv_scr_read(ap, SCR_STATUS, &sstatus);
+               mv_scr_read(ap, SCR_ERROR, &serror);
+               mv_scr_read(ap, SCR_CONTROL, &scontrol);
+               DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+                       "SCtrl 0x%08x\n", sstatus, serror, scontrol);
+       }
+#endif
 
        if (ata_port_offline(ap)) {
                *class = ATA_DEV_NONE;
@@ -2209,7 +2247,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
        struct mv_port_priv *pp = ap->private_data;
        struct ata_eh_context *ehc = &ap->eh_context;
        int rc;
-       
+
        rc = mv_stop_dma(ap);
        if (rc)
                ehc->i.action |= ATA_EH_HARDRESET;
@@ -2666,7 +2704,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        mv_print_info(host);
 
        pci_set_master(pdev);
-       pci_set_mwi(pdev);
+       pci_try_set_mwi(pdev);
        return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
                                 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
 }