]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/ata/sata_mv.c
Merge branch 'core/percpu' into percpu-cpumask-x86-for-linus-2
[mv-sheeva.git] / drivers / ata / sata_mv.c
index 7007edd2d4517fed1a5b75773622cae9da003e44..a377226b81c8954005f37cfaac9aeb69ebff1677 100644 (file)
@@ -1,10 +1,13 @@
 /*
  * sata_mv.c - Marvell SATA support
  *
- * Copyright 2008: Marvell Corporation, all rights reserved.
+ * Copyright 2008-2009: Marvell Corporation, all rights reserved.
  * Copyright 2005: EMC Corporation, all rights reserved.
  * Copyright 2005 Red Hat, Inc.  All rights reserved.
  *
+ * Originally written by Brett Russ.
+ * Extensive overhaul and enhancement by Mark Lord <mlord@pobox.com>.
+ *
  * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
  *
  * This program is free software; you can redistribute it and/or modify
 /*
  * sata_mv TODO list:
  *
- * --> Errata workaround for NCQ device errors.
- *
  * --> More errata workarounds for PCI-X.
  *
  * --> Complete a full errata audit for all chipsets to identify others.
  *
- * --> ATAPI support (Marvell claims the 60xx/70xx chips can do it).
- *
  * --> Develop a low-power-consumption strategy, and implement it.
  *
- * --> [Experiment, low priority] Investigate interrupt coalescing.
- *       Quite often, especially with PCI Message Signalled Interrupts (MSI),
- *       the overhead reduced by interrupt mitigation is quite often not
- *       worth the latency cost.
+ * --> Add sysfs attributes for per-chip / per-HC IRQ coalescing thresholds.
  *
  * --> [Experiment, Marvell value added] Is it possible to use target
  *       mode to cross-connect two Linux boxes with Marvell cards?  If so,
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_mv"
-#define DRV_VERSION    "1.25"
+#define DRV_VERSION    "1.27"
+
+/*
+ * module options
+ */
+
+static int msi;
+#ifdef CONFIG_PCI
+module_param(msi, int, S_IRUGO);
+MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
+#endif
+
+static int irq_coalescing_io_count;
+module_param(irq_coalescing_io_count, int, S_IRUGO);
+MODULE_PARM_DESC(irq_coalescing_io_count,
+                "IRQ coalescing I/O count threshold (0..255)");
+
+static int irq_coalescing_usecs;
+module_param(irq_coalescing_usecs, int, S_IRUGO);
+MODULE_PARM_DESC(irq_coalescing_usecs,
+                "IRQ coalescing time threshold in usecs");
 
 enum {
        /* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -79,13 +95,32 @@ enum {
        MV_MAJOR_REG_AREA_SZ    = 0x10000,      /* 64KB */
        MV_MINOR_REG_AREA_SZ    = 0x2000,       /* 8KB */
 
+       /* For use with both IRQ coalescing methods ("all ports" or "per-HC" */
+       COAL_CLOCKS_PER_USEC    = 150,          /* for calculating COAL_TIMEs */
+       MAX_COAL_TIME_THRESHOLD = ((1 << 24) - 1), /* internal clocks count */
+       MAX_COAL_IO_COUNT       = 255,          /* completed I/O count */
+
        MV_PCI_REG_BASE         = 0,
-       MV_IRQ_COAL_REG_BASE    = 0x18000,      /* 6xxx part only */
-       MV_IRQ_COAL_CAUSE               = (MV_IRQ_COAL_REG_BASE + 0x08),
-       MV_IRQ_COAL_CAUSE_LO            = (MV_IRQ_COAL_REG_BASE + 0x88),
-       MV_IRQ_COAL_CAUSE_HI            = (MV_IRQ_COAL_REG_BASE + 0x8c),
-       MV_IRQ_COAL_THRESHOLD           = (MV_IRQ_COAL_REG_BASE + 0xcc),
-       MV_IRQ_COAL_TIME_THRESHOLD      = (MV_IRQ_COAL_REG_BASE + 0xd0),
+
+       /*
+        * Per-chip ("all ports") interrupt coalescing feature.
+        * This is only for GEN_II / GEN_IIE hardware.
+        *
+        * Coalescing defers the interrupt until either the IO_THRESHOLD
+        * (count of completed I/Os) is met, or the TIME_THRESHOLD is met.
+        */
+       MV_COAL_REG_BASE        = 0x18000,
+       MV_IRQ_COAL_CAUSE       = (MV_COAL_REG_BASE + 0x08),
+       ALL_PORTS_COAL_IRQ      = (1 << 4),     /* all ports irq event */
+
+       MV_IRQ_COAL_IO_THRESHOLD   = (MV_COAL_REG_BASE + 0xcc),
+       MV_IRQ_COAL_TIME_THRESHOLD = (MV_COAL_REG_BASE + 0xd0),
+
+       /*
+        * Registers for the (unused here) transaction coalescing feature:
+        */
+       MV_TRAN_COAL_CAUSE_LO   = (MV_COAL_REG_BASE + 0x88),
+       MV_TRAN_COAL_CAUSE_HI   = (MV_COAL_REG_BASE + 0x8c),
 
        MV_SATAHC0_REG_BASE     = 0x20000,
        MV_FLASH_CTL_OFS        = 0x1046c,
@@ -117,17 +152,16 @@ enum {
 
        /* Host Flags */
        MV_FLAG_DUAL_HC         = (1 << 30),  /* two SATA Host Controllers */
-       MV_FLAG_IRQ_COALESCE    = (1 << 29),  /* IRQ coalescing capability */
 
        MV_COMMON_FLAGS         = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
-                                 ATA_FLAG_PIO_POLLING,
+                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
+
+       MV_GEN_I_FLAGS          = MV_COMMON_FLAGS | ATA_FLAG_NO_ATAPI,
 
-       MV_6XXX_FLAGS           = MV_FLAG_IRQ_COALESCE,
+       MV_GEN_II_FLAGS         = MV_COMMON_FLAGS | ATA_FLAG_NCQ |
+                                 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA,
 
-       MV_GENIIE_FLAGS         = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
-                                 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
-                                 ATA_FLAG_NCQ | ATA_FLAG_AN,
+       MV_GEN_IIE_FLAGS        = MV_GEN_II_FLAGS | ATA_FLAG_AN,
 
        CRQB_FLAG_READ          = (1 << 0),
        CRQB_TAG_SHIFT          = 1,
@@ -180,16 +214,18 @@ enum {
        PCI_HC_MAIN_IRQ_MASK_OFS  = 0x1d64,
        SOC_HC_MAIN_IRQ_CAUSE_OFS = 0x20020,
        SOC_HC_MAIN_IRQ_MASK_OFS  = 0x20024,
-       ERR_IRQ                 = (1 << 0),     /* shift by port # */
-       DONE_IRQ                = (1 << 1),     /* shift by port # */
+       ERR_IRQ                 = (1 << 0),     /* shift by (2 * port #) */
+       DONE_IRQ                = (1 << 1),     /* shift by (2 * port #) */
        HC0_IRQ_PEND            = 0x1ff,        /* bits 0-8 = HC0's ports */
        HC_SHIFT                = 9,            /* bits 9-17 = HC1's ports */
+       DONE_IRQ_0_3            = 0x000000aa,   /* DONE_IRQ ports 0,1,2,3 */
+       DONE_IRQ_4_7            = (DONE_IRQ_0_3 << HC_SHIFT),  /* 4,5,6,7 */
        PCI_ERR                 = (1 << 18),
-       TRAN_LO_DONE            = (1 << 19),    /* 6xxx: IRQ coalescing */
-       TRAN_HI_DONE            = (1 << 20),    /* 6xxx: IRQ coalescing */
-       PORTS_0_3_COAL_DONE     = (1 << 8),
-       PORTS_4_7_COAL_DONE     = (1 << 17),
-       PORTS_0_7_COAL_DONE     = (1 << 21),    /* 6xxx: IRQ coalescing */
+       TRAN_COAL_LO_DONE       = (1 << 19),    /* transaction coalescing */
+       TRAN_COAL_HI_DONE       = (1 << 20),    /* transaction coalescing */
+       PORTS_0_3_COAL_DONE     = (1 << 8),     /* HC0 IRQ coalescing */
+       PORTS_4_7_COAL_DONE     = (1 << 17),    /* HC1 IRQ coalescing */
+       ALL_PORTS_COAL_DONE     = (1 << 21),    /* GEN_II(E) IRQ coalescing */
        GPIO_INT                = (1 << 22),
        SELF_INT                = (1 << 23),
        TWSI_INT                = (1 << 24),
@@ -205,6 +241,21 @@ enum {
        HC_COAL_IRQ             = (1 << 4),     /* IRQ coalescing */
        DEV_IRQ                 = (1 << 8),     /* shift by port # */
 
+       /*
+        * Per-HC (Host-Controller) interrupt coalescing feature.
+        * This is present on all chip generations.
+        *
+        * Coalescing defers the interrupt until either the IO_THRESHOLD
+        * (count of completed I/Os) is met, or the TIME_THRESHOLD is met.
+        */
+       HC_IRQ_COAL_IO_THRESHOLD_OFS    = 0x000c,
+       HC_IRQ_COAL_TIME_THRESHOLD_OFS  = 0x0010,
+
+       SOC_LED_CTRL_OFS        = 0x2c,
+       SOC_LED_CTRL_BLINK      = (1 << 0),     /* Active LED blink */
+       SOC_LED_CTRL_ACT_PRESENCE = (1 << 2),   /* Multiplex dev presence */
+                                               /*  with dev activity LED */
+
        /* Shadow block registers */
        SHD_BLK_OFS             = 0x100,
        SHD_CTL_AST_OFS         = 0x20,         /* ofs from SHD_BLK_OFS */
@@ -346,6 +397,12 @@ enum {
        EDMA_ARB_CFG_OFS        = 0x38,
 
        EDMA_HALTCOND_OFS       = 0x60,         /* GenIIe halt conditions */
+       EDMA_UNKNOWN_RSVD_OFS   = 0x6C,         /* GenIIe unknown/reserved */
+
+       BMDMA_CMD_OFS           = 0x224,        /* bmdma command register */
+       BMDMA_STATUS_OFS        = 0x228,        /* bmdma status register */
+       BMDMA_PRD_LOW_OFS       = 0x22c,        /* bmdma PRD addr 31:0 */
+       BMDMA_PRD_HIGH_OFS      = 0x230,        /* bmdma PRD addr 63:32 */
 
        /* Host private flags (hp_flags) */
        MV_HP_FLAG_MSI          = (1 << 0),
@@ -359,12 +416,14 @@ enum {
        MV_HP_PCIE              = (1 << 9),     /* PCIe bus/regs: 7042 */
        MV_HP_CUT_THROUGH       = (1 << 10),    /* can use EDMA cut-through */
        MV_HP_FLAG_SOC          = (1 << 11),    /* SystemOnChip, no PCI */
+       MV_HP_QUIRK_LED_BLINK_EN = (1 << 12),   /* is led blinking enabled? */
 
        /* Port private flags (pp_flags) */
        MV_PP_FLAG_EDMA_EN      = (1 << 0),     /* is EDMA engine enabled? */
        MV_PP_FLAG_NCQ_EN       = (1 << 1),     /* is EDMA set up for NCQ? */
        MV_PP_FLAG_FBS_EN       = (1 << 2),     /* is EDMA set up for FBS? */
        MV_PP_FLAG_DELAYED_EH   = (1 << 3),     /* delayed dev err handling */
+       MV_PP_FLAG_FAKE_ATA_BUSY = (1 << 4),    /* ignore initial ATA_DRDY */
 };
 
 #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -433,6 +492,18 @@ struct mv_sg {
        __le32                  reserved;
 };
 
+/*
+ * We keep a local cache of a few frequently accessed port
+ * registers here, to avoid having to read them (very slow)
+ * when switching between EDMA and non-EDMA modes.
+ */
+struct mv_cached_regs {
+       u32                     fiscfg;
+       u32                     ltmode;
+       u32                     haltcond;
+       u32                     unknown_rsvd;
+};
+
 struct mv_port_priv {
        struct mv_crqb          *crqb;
        dma_addr_t              crqb_dma;
@@ -445,6 +516,7 @@ struct mv_port_priv {
        unsigned int            resp_idx;
 
        u32                     pp_flags;
+       struct mv_cached_regs   cached;
        unsigned int            delayed_eh_pmp_map;
 };
 
@@ -535,7 +607,7 @@ static void mv_reset_channel(struct mv_host_priv *hpriv, void __iomem *mmio,
                             unsigned int port_no);
 static int mv_stop_edma(struct ata_port *ap);
 static int mv_stop_edma_engine(void __iomem *port_mmio);
-static void mv_edma_cfg(struct ata_port *ap, int want_ncq);
+static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma);
 
 static void mv_pmp_select(struct ata_port *ap, int pmp);
 static int mv_pmp_hardreset(struct ata_link *link, unsigned int *class,
@@ -546,6 +618,14 @@ static void mv_pmp_error_handler(struct ata_port *ap);
 static void mv_process_crpb_entries(struct ata_port *ap,
                                        struct mv_port_priv *pp);
 
+static void mv_sff_irq_clear(struct ata_port *ap);
+static int mv_check_atapi_dma(struct ata_queued_cmd *qc);
+static void mv_bmdma_setup(struct ata_queued_cmd *qc);
+static void mv_bmdma_start(struct ata_queued_cmd *qc);
+static void mv_bmdma_stop(struct ata_queued_cmd *qc);
+static u8   mv_bmdma_status(struct ata_port *ap);
+static u8 mv_sff_check_status(struct ata_port *ap);
+
 /* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
  * because we have to allow room for worst case splitting of
  * PRDs for 64K boundaries in mv_fill_sg().
@@ -566,6 +646,8 @@ static struct scsi_host_template mv6_sht = {
 static struct ata_port_operations mv5_ops = {
        .inherits               = &ata_sff_port_ops,
 
+       .lost_interrupt         = ATA_OP_NULL,
+
        .qc_defer               = mv_qc_defer,
        .qc_prep                = mv_qc_prep,
        .qc_issue               = mv_qc_issue,
@@ -593,6 +675,14 @@ static struct ata_port_operations mv6_ops = {
        .pmp_softreset          = mv_softreset,
        .softreset              = mv_softreset,
        .error_handler          = mv_pmp_error_handler,
+
+       .sff_check_status       = mv_sff_check_status,
+       .sff_irq_clear          = mv_sff_irq_clear,
+       .check_atapi_dma        = mv_check_atapi_dma,
+       .bmdma_setup            = mv_bmdma_setup,
+       .bmdma_start            = mv_bmdma_start,
+       .bmdma_stop             = mv_bmdma_stop,
+       .bmdma_status           = mv_bmdma_status,
 };
 
 static struct ata_port_operations mv_iie_ops = {
@@ -603,53 +693,49 @@ static struct ata_port_operations mv_iie_ops = {
 
 static const struct ata_port_info mv_port_info[] = {
        {  /* chip_504x */
-               .flags          = MV_COMMON_FLAGS,
+               .flags          = MV_GEN_I_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv5_ops,
        },
        {  /* chip_508x */
-               .flags          = MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
+               .flags          = MV_GEN_I_FLAGS | MV_FLAG_DUAL_HC,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv5_ops,
        },
        {  /* chip_5080 */
-               .flags          = MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
+               .flags          = MV_GEN_I_FLAGS | MV_FLAG_DUAL_HC,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv5_ops,
        },
        {  /* chip_604x */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
-                                 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
-                                 ATA_FLAG_NCQ,
+               .flags          = MV_GEN_II_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv6_ops,
        },
        {  /* chip_608x */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
-                                 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
-                                 ATA_FLAG_NCQ | MV_FLAG_DUAL_HC,
+               .flags          = MV_GEN_II_FLAGS | MV_FLAG_DUAL_HC,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv6_ops,
        },
        {  /* chip_6042 */
-               .flags          = MV_GENIIE_FLAGS,
+               .flags          = MV_GEN_IIE_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
        },
        {  /* chip_7042 */
-               .flags          = MV_GENIIE_FLAGS,
+               .flags          = MV_GEN_IIE_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
        },
        {  /* chip_soc */
-               .flags          = MV_GENIIE_FLAGS,
+               .flags          = MV_GEN_IIE_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
@@ -794,6 +880,44 @@ static inline int mv_get_hc_count(unsigned long port_flags)
        return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
 }
 
+/**
+ *      mv_save_cached_regs - (re-)initialize cached port registers
+ *      @ap: the port whose registers we are caching
+ *
+ *     Initialize the local cache of port registers,
+ *     so that reading them over and over again can
+ *     be avoided on the hotter paths of this driver.
+ *     This saves a few microseconds each time we switch
+ *     to/from EDMA mode to perform (eg.) a drive cache flush.
+ */
+static void mv_save_cached_regs(struct ata_port *ap)
+{
+       void __iomem *port_mmio = mv_ap_base(ap);
+       struct mv_port_priv *pp = ap->private_data;
+
+       pp->cached.fiscfg = readl(port_mmio + FISCFG_OFS);
+       pp->cached.ltmode = readl(port_mmio + LTMODE_OFS);
+       pp->cached.haltcond = readl(port_mmio + EDMA_HALTCOND_OFS);
+       pp->cached.unknown_rsvd = readl(port_mmio + EDMA_UNKNOWN_RSVD_OFS);
+}
+
+/**
+ *      mv_write_cached_reg - write to a cached port register
+ *      @addr: hardware address of the register
+ *      @old: pointer to cached value of the register
+ *      @new: new value for the register
+ *
+ *     Write a new value to a cached register,
+ *     but only if the value is different from before.
+ */
+static inline void mv_write_cached_reg(void __iomem *addr, u32 *old, u32 new)
+{
+       if (new != *old) {
+               *old = new;
+               writel(new, addr);
+       }
+}
+
 static void mv_set_edma_ptrs(void __iomem *port_mmio,
                             struct mv_host_priv *hpriv,
                             struct mv_port_priv *pp)
@@ -825,6 +949,23 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
                 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
 }
 
+static void mv_write_main_irq_mask(u32 mask, struct mv_host_priv *hpriv)
+{
+       /*
+        * When writing to the main_irq_mask in hardware,
+        * we must ensure exclusivity between the interrupt coalescing bits
+        * and the corresponding individual port DONE_IRQ bits.
+        *
+        * Note that this register is really an "IRQ enable" register,
+        * not an "IRQ mask" register as Marvell's naming might suggest.
+        */
+       if (mask & (ALL_PORTS_COAL_DONE | PORTS_0_3_COAL_DONE))
+               mask &= ~DONE_IRQ_0_3;
+       if (mask & (ALL_PORTS_COAL_DONE | PORTS_4_7_COAL_DONE))
+               mask &= ~DONE_IRQ_4_7;
+       writelfl(mask, hpriv->main_irq_mask_addr);
+}
+
 static void mv_set_main_irq_mask(struct ata_host *host,
                                 u32 disable_bits, u32 enable_bits)
 {
@@ -835,7 +976,7 @@ static void mv_set_main_irq_mask(struct ata_host *host,
        new_mask = (old_mask & ~disable_bits) | enable_bits;
        if (new_mask != old_mask) {
                hpriv->main_irq_mask = new_mask;
-               writelfl(new_mask, hpriv->main_irq_mask_addr);
+               mv_write_main_irq_mask(new_mask, hpriv);
        }
 }
 
@@ -852,8 +993,94 @@ static void mv_enable_port_irqs(struct ata_port *ap,
        mv_set_main_irq_mask(ap->host, disable_bits, enable_bits);
 }
 
+static void mv_clear_and_enable_port_irqs(struct ata_port *ap,
+                                         void __iomem *port_mmio,
+                                         unsigned int port_irqs)
+{
+       struct mv_host_priv *hpriv = ap->host->private_data;
+       int hardport = mv_hardport_from_port(ap->port_no);
+       void __iomem *hc_mmio = mv_hc_base_from_port(
+                               mv_host_base(ap->host), ap->port_no);
+       u32 hc_irq_cause;
+
+       /* clear EDMA event indicators, if any */
+       writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+       /* clear pending irq events */
+       hc_irq_cause = ~((DEV_IRQ | DMA_IRQ) << hardport);
+       writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+
+       /* clear FIS IRQ Cause */
+       if (IS_GEN_IIE(hpriv))
+               writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+
+       mv_enable_port_irqs(ap, port_irqs);
+}
+
+static void mv_set_irq_coalescing(struct ata_host *host,
+                                 unsigned int count, unsigned int usecs)
+{
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = hpriv->base, *hc_mmio;
+       u32 coal_enable = 0;
+       unsigned long flags;
+       unsigned int clks, is_dual_hc = hpriv->n_ports > MV_PORTS_PER_HC;
+       const u32 coal_disable = PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
+                                                       ALL_PORTS_COAL_DONE;
+
+       /* Disable IRQ coalescing if either threshold is zero */
+       if (!usecs || !count) {
+               clks = count = 0;
+       } else {
+               /* Respect maximum limits of the hardware */
+               clks = usecs * COAL_CLOCKS_PER_USEC;
+               if (clks > MAX_COAL_TIME_THRESHOLD)
+                       clks = MAX_COAL_TIME_THRESHOLD;
+               if (count > MAX_COAL_IO_COUNT)
+                       count = MAX_COAL_IO_COUNT;
+       }
+
+       spin_lock_irqsave(&host->lock, flags);
+       mv_set_main_irq_mask(host, coal_disable, 0);
+
+       if (is_dual_hc && !IS_GEN_I(hpriv)) {
+               /*
+                * GEN_II/GEN_IIE with dual host controllers:
+                * one set of global thresholds for the entire chip.
+                */
+               writel(clks,  mmio + MV_IRQ_COAL_TIME_THRESHOLD);
+               writel(count, mmio + MV_IRQ_COAL_IO_THRESHOLD);
+               /* clear leftover coal IRQ bit */
+               writel(~ALL_PORTS_COAL_IRQ, mmio + MV_IRQ_COAL_CAUSE);
+               if (count)
+                       coal_enable = ALL_PORTS_COAL_DONE;
+               clks = count = 0; /* force clearing of regular regs below */
+       }
+
+       /*
+        * All chips: independent thresholds for each HC on the chip.
+        */
+       hc_mmio = mv_hc_base_from_port(mmio, 0);
+       writel(clks,  hc_mmio + HC_IRQ_COAL_TIME_THRESHOLD_OFS);
+       writel(count, hc_mmio + HC_IRQ_COAL_IO_THRESHOLD_OFS);
+       writel(~HC_COAL_IRQ, hc_mmio + HC_IRQ_CAUSE_OFS);
+       if (count)
+               coal_enable |= PORTS_0_3_COAL_DONE;
+       if (is_dual_hc) {
+               hc_mmio = mv_hc_base_from_port(mmio, MV_PORTS_PER_HC);
+               writel(clks,  hc_mmio + HC_IRQ_COAL_TIME_THRESHOLD_OFS);
+               writel(count, hc_mmio + HC_IRQ_COAL_IO_THRESHOLD_OFS);
+               writel(~HC_COAL_IRQ, hc_mmio + HC_IRQ_CAUSE_OFS);
+               if (count)
+                       coal_enable |= PORTS_4_7_COAL_DONE;
+       }
+
+       mv_set_main_irq_mask(host, 0, coal_enable);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
 /**
- *      mv_start_dma - Enable eDMA engine
+ *      mv_start_edma - Enable eDMA engine
  *      @base: port base address
  *      @pp: port private data
  *
@@ -863,7 +1090,7 @@ static void mv_enable_port_irqs(struct ata_port *ap,
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
+static void mv_start_edma(struct ata_port *ap, void __iomem *port_mmio,
                         struct mv_port_priv *pp, u8 protocol)
 {
        int want_ncq = (protocol == ATA_PROT_NCQ);
@@ -875,26 +1102,11 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
        }
        if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
                struct mv_host_priv *hpriv = ap->host->private_data;
-               int hardport = mv_hardport_from_port(ap->port_no);
-               void __iomem *hc_mmio = mv_hc_base_from_port(
-                                       mv_host_base(ap->host), ap->port_no);
-               u32 hc_irq_cause;
-
-               /* clear EDMA event indicators, if any */
-               writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
 
-               /* clear pending irq events */
-               hc_irq_cause = ~((DEV_IRQ | DMA_IRQ) << hardport);
-               writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
-
-               mv_edma_cfg(ap, want_ncq);
-
-               /* clear FIS IRQ Cause */
-               if (IS_GEN_IIE(hpriv))
-                       writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+               mv_edma_cfg(ap, want_ncq, 1);
 
                mv_set_edma_ptrs(port_mmio, hpriv, pp);
-               mv_enable_port_irqs(ap, DONE_IRQ|ERR_IRQ);
+               mv_clear_and_enable_port_irqs(ap, port_mmio, DONE_IRQ|ERR_IRQ);
 
                writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS);
                pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
@@ -952,6 +1164,7 @@ static int mv_stop_edma(struct ata_port *ap)
 {
        void __iomem *port_mmio = mv_ap_base(ap);
        struct mv_port_priv *pp = ap->private_data;
+       int err = 0;
 
        if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))
                return 0;
@@ -959,9 +1172,10 @@ static int mv_stop_edma(struct ata_port *ap)
        mv_wait_for_edma_empty_idle(ap);
        if (mv_stop_edma_engine(port_mmio)) {
                ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
-               return -EIO;
+               err = -EIO;
        }
-       return 0;
+       mv_edma_cfg(ap, 0, 0);
+       return err;
 }
 
 #ifdef ATA_DEBUG
@@ -1130,35 +1344,33 @@ static int mv_qc_defer(struct ata_queued_cmd *qc)
        return ATA_DEFER_PORT;
 }
 
-static void mv_config_fbs(void __iomem *port_mmio, int want_ncq, int want_fbs)
+static void mv_config_fbs(struct ata_port *ap, int want_ncq, int want_fbs)
 {
-       u32 new_fiscfg, old_fiscfg;
-       u32 new_ltmode, old_ltmode;
-       u32 new_haltcond, old_haltcond;
+       struct mv_port_priv *pp = ap->private_data;
+       void __iomem *port_mmio;
 
-       old_fiscfg   = readl(port_mmio + FISCFG_OFS);
-       old_ltmode   = readl(port_mmio + LTMODE_OFS);
-       old_haltcond = readl(port_mmio + EDMA_HALTCOND_OFS);
+       u32 fiscfg,   *old_fiscfg   = &pp->cached.fiscfg;
+       u32 ltmode,   *old_ltmode   = &pp->cached.ltmode;
+       u32 haltcond, *old_haltcond = &pp->cached.haltcond;
 
-       new_fiscfg   = old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR);
-       new_ltmode   = old_ltmode & ~LTMODE_BIT8;
-       new_haltcond = old_haltcond | EDMA_ERR_DEV;
+       ltmode   = *old_ltmode & ~LTMODE_BIT8;
+       haltcond = *old_haltcond | EDMA_ERR_DEV;
 
        if (want_fbs) {
-               new_fiscfg = old_fiscfg | FISCFG_SINGLE_SYNC;
-               new_ltmode = old_ltmode | LTMODE_BIT8;
+               fiscfg = *old_fiscfg | FISCFG_SINGLE_SYNC;
+               ltmode = *old_ltmode | LTMODE_BIT8;
                if (want_ncq)
-                       new_haltcond &= ~EDMA_ERR_DEV;
+                       haltcond &= ~EDMA_ERR_DEV;
                else
-                       new_fiscfg |=  FISCFG_WAIT_DEV_ERR;
+                       fiscfg |=  FISCFG_WAIT_DEV_ERR;
+       } else {
+               fiscfg = *old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR);
        }
 
-       if (new_fiscfg != old_fiscfg)
-               writelfl(new_fiscfg, port_mmio + FISCFG_OFS);
-       if (new_ltmode != old_ltmode)
-               writelfl(new_ltmode, port_mmio + LTMODE_OFS);
-       if (new_haltcond != old_haltcond)
-               writelfl(new_haltcond, port_mmio + EDMA_HALTCOND_OFS);
+       port_mmio = mv_ap_base(ap);
+       mv_write_cached_reg(port_mmio + FISCFG_OFS, old_fiscfg, fiscfg);
+       mv_write_cached_reg(port_mmio + LTMODE_OFS, old_ltmode, ltmode);
+       mv_write_cached_reg(port_mmio + EDMA_HALTCOND_OFS, old_haltcond, haltcond);
 }
 
 static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq)
@@ -1176,7 +1388,86 @@ static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq)
                writel(new, hpriv->base + MV_GPIO_PORT_CTL_OFS);
 }
 
-static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
+/**
+ *     mv_bmdma_enable - set a magic bit on GEN_IIE to allow bmdma
+ *     @ap: Port being initialized
+ *
+ *     There are two DMA modes on these chips:  basic DMA, and EDMA.
+ *
+ *     Bit-0 of the "EDMA RESERVED" register enables/disables use
+ *     of basic DMA on the GEN_IIE versions of the chips.
+ *
+ *     This bit survives EDMA resets, and must be set for basic DMA
+ *     to function, and should be cleared when EDMA is active.
+ */
+static void mv_bmdma_enable_iie(struct ata_port *ap, int enable_bmdma)
+{
+       struct mv_port_priv *pp = ap->private_data;
+       u32 new, *old = &pp->cached.unknown_rsvd;
+
+       if (enable_bmdma)
+               new = *old | 1;
+       else
+               new = *old & ~1;
+       mv_write_cached_reg(mv_ap_base(ap) + EDMA_UNKNOWN_RSVD_OFS, old, new);
+}
+
+/*
+ * SOC chips have an issue whereby the HDD LEDs don't always blink
+ * during I/O when NCQ is enabled. Enabling a special "LED blink" mode
+ * of the SOC takes care of it, generating a steady blink rate when
+ * any drive on the chip is active.
+ *
+ * Unfortunately, the blink mode is a global hardware setting for the SOC,
+ * so we must use it whenever at least one port on the SOC has NCQ enabled.
+ *
+ * We turn "LED blink" off when NCQ is not in use anywhere, because the normal
+ * LED operation works then, and provides better (more accurate) feedback.
+ *
+ * Note that this code assumes that an SOC never has more than one HC onboard.
+ */
+static void mv_soc_led_blink_enable(struct ata_port *ap)
+{
+       struct ata_host *host = ap->host;
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *hc_mmio;
+       u32 led_ctrl;
+
+       if (hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN)
+               return;
+       hpriv->hp_flags |= MV_HP_QUIRK_LED_BLINK_EN;
+       hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no);
+       led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS);
+       writel(led_ctrl | SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS);
+}
+
+static void mv_soc_led_blink_disable(struct ata_port *ap)
+{
+       struct ata_host *host = ap->host;
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *hc_mmio;
+       u32 led_ctrl;
+       unsigned int port;
+
+       if (!(hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN))
+               return;
+
+       /* disable led-blink only if no ports are using NCQ */
+       for (port = 0; port < hpriv->n_ports; port++) {
+               struct ata_port *this_ap = host->ports[port];
+               struct mv_port_priv *pp = this_ap->private_data;
+
+               if (pp->pp_flags & MV_PP_FLAG_NCQ_EN)
+                       return;
+       }
+
+       hpriv->hp_flags &= ~MV_HP_QUIRK_LED_BLINK_EN;
+       hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no);
+       led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS);
+       writel(led_ctrl & ~SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS);
+}
+
+static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma)
 {
        u32 cfg;
        struct mv_port_priv *pp    = ap->private_data;
@@ -1185,7 +1476,8 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
 
        /* set up non-NCQ EDMA configuration */
        cfg = EDMA_CFG_Q_DEPTH;         /* always 0x1f for *all* chips */
-       pp->pp_flags &= ~MV_PP_FLAG_FBS_EN;
+       pp->pp_flags &=
+         ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN | MV_PP_FLAG_FAKE_ATA_BUSY);
 
        if (IS_GEN_I(hpriv))
                cfg |= (1 << 8);        /* enab config burst size mask */
@@ -1206,7 +1498,7 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
                 */
                want_fbs &= want_ncq;
 
-               mv_config_fbs(port_mmio, want_ncq, want_fbs);
+               mv_config_fbs(ap, want_ncq, want_fbs);
 
                if (want_fbs) {
                        pp->pp_flags |= MV_PP_FLAG_FBS_EN;
@@ -1214,18 +1506,27 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
                }
 
                cfg |= (1 << 23);       /* do not mask PM field in rx'd FIS */
-               cfg |= (1 << 22);       /* enab 4-entry host queue cache */
-               if (!IS_SOC(hpriv))
-                       cfg |= (1 << 18);       /* enab early completion */
+               if (want_edma) {
+                       cfg |= (1 << 22); /* enab 4-entry host queue cache */
+                       if (!IS_SOC(hpriv))
+                               cfg |= (1 << 18); /* enab early completion */
+               }
                if (hpriv->hp_flags & MV_HP_CUT_THROUGH)
                        cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */
+               mv_bmdma_enable_iie(ap, !want_edma);
+
+               if (IS_SOC(hpriv)) {
+                       if (want_ncq)
+                               mv_soc_led_blink_enable(ap);
+                       else
+                               mv_soc_led_blink_disable(ap);
+               }
        }
 
        if (want_ncq) {
                cfg |= EDMA_CFG_NCQ;
                pp->pp_flags |=  MV_PP_FLAG_NCQ_EN;
-       } else
-               pp->pp_flags &= ~MV_PP_FLAG_NCQ_EN;
+       }
 
        writelfl(cfg, port_mmio + EDMA_CFG_OFS);
 }
@@ -1309,6 +1610,8 @@ static int mv_port_start(struct ata_port *ap)
                        pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0];
                }
        }
+       mv_save_cached_regs(ap);
+       mv_edma_cfg(ap, 0, 0);
        return 0;
 
 out_port_free_dma_mem:
@@ -1357,12 +1660,13 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
                        u32 offset = addr & 0xffff;
                        u32 len = sg_len;
 
-                       if ((offset + sg_len > 0x10000))
+                       if (offset + len > 0x10000)
                                len = 0x10000 - offset;
 
                        mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
                        mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
                        mv_sg->flags_size = cpu_to_le32(len & 0xffff);
+                       mv_sg->reserved = 0;
 
                        sg_len -= len;
                        addr += len;
@@ -1374,6 +1678,7 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
 
        if (likely(last_sg))
                last_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
+       mb(); /* ensure data structure is visible to the chipset */
 }
 
 static void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
@@ -1383,6 +1688,147 @@ static void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
        *cmdw = cpu_to_le16(tmp);
 }
 
+/**
+ *     mv_sff_irq_clear - Clear hardware interrupt after DMA.
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     We need this only for ATAPI bmdma transactions,
+ *     as otherwise we experience spurious interrupts
+ *     after libata-sff handles the bmdma interrupts.
+ */
+static void mv_sff_irq_clear(struct ata_port *ap)
+{
+       mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), ERR_IRQ);
+}
+
+/**
+ *     mv_check_atapi_dma - Filter ATAPI cmds which are unsuitable for DMA.
+ *     @qc: queued command to check for chipset/DMA compatibility.
+ *
+ *     The bmdma engines cannot handle speculative data sizes
+ *     (bytecount under/over flow).  So only allow DMA for
+ *     data transfer commands with known data sizes.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+static int mv_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+       struct scsi_cmnd *scmd = qc->scsicmd;
+
+       if (scmd) {
+               switch (scmd->cmnd[0]) {
+               case READ_6:
+               case READ_10:
+               case READ_12:
+               case WRITE_6:
+               case WRITE_10:
+               case WRITE_12:
+               case GPCMD_READ_CD:
+               case GPCMD_SEND_DVD_STRUCTURE:
+               case GPCMD_SEND_CUE_SHEET:
+                       return 0; /* DMA is safe */
+               }
+       }
+       return -EOPNOTSUPP; /* use PIO instead */
+}
+
+/**
+ *     mv_bmdma_setup - Set up BMDMA transaction
+ *     @qc: queued command to prepare DMA for.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+static void mv_bmdma_setup(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       void __iomem *port_mmio = mv_ap_base(ap);
+       struct mv_port_priv *pp = ap->private_data;
+
+       mv_fill_sg(qc);
+
+       /* clear all DMA cmd bits */
+       writel(0, port_mmio + BMDMA_CMD_OFS);
+
+       /* load PRD table addr. */
+       writel((pp->sg_tbl_dma[qc->tag] >> 16) >> 16,
+               port_mmio + BMDMA_PRD_HIGH_OFS);
+       writelfl(pp->sg_tbl_dma[qc->tag],
+               port_mmio + BMDMA_PRD_LOW_OFS);
+
+       /* issue r/w command */
+       ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+/**
+ *     mv_bmdma_start - Start a BMDMA transaction
+ *     @qc: queued command to start DMA on.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+static void mv_bmdma_start(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       void __iomem *port_mmio = mv_ap_base(ap);
+       unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+       u32 cmd = (rw ? 0 : ATA_DMA_WR) | ATA_DMA_START;
+
+       /* start host DMA transaction */
+       writelfl(cmd, port_mmio + BMDMA_CMD_OFS);
+}
+
+/**
+ *     mv_bmdma_stop - Stop BMDMA transfer
+ *     @qc: queued command to stop DMA on.
+ *
+ *     Clears the ATA_DMA_START flag in the bmdma control register
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+static void mv_bmdma_stop(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       void __iomem *port_mmio = mv_ap_base(ap);
+       u32 cmd;
+
+       /* clear start/stop bit */
+       cmd = readl(port_mmio + BMDMA_CMD_OFS);
+       cmd &= ~ATA_DMA_START;
+       writelfl(cmd, port_mmio + BMDMA_CMD_OFS);
+
+       /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+       ata_sff_dma_pause(ap);
+}
+
+/**
+ *     mv_bmdma_status - Read BMDMA status
+ *     @ap: port for which to retrieve DMA status.
+ *
+ *     Read and return equivalent of the sff BMDMA status register.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+static u8 mv_bmdma_status(struct ata_port *ap)
+{
+       void __iomem *port_mmio = mv_ap_base(ap);
+       u32 reg, status;
+
+       /*
+        * Other bits are valid only if ATA_DMA_ACTIVE==0,
+        * and the ATA_DMA_INTR bit doesn't exist.
+        */
+       reg = readl(port_mmio + BMDMA_STATUS_OFS);
+       if (reg & ATA_DMA_ACTIVE)
+               status = ATA_DMA_ACTIVE;
+       else
+               status = (reg & ATA_DMA_ERR) | ATA_DMA_INTR;
+       return status;
+}
+
 /**
  *      mv_qc_prep - Host specific command preparation.
  *      @qc: queued command to prepare
@@ -1544,6 +1990,132 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
        mv_fill_sg(qc);
 }
 
+/**
+ *     mv_sff_check_status - fetch device status, if valid
+ *     @ap: ATA port to fetch status from
+ *
+ *     When using command issue via mv_qc_issue_fis(),
+ *     the initial ATA_BUSY state does not show up in the
+ *     ATA status (shadow) register.  This can confuse libata!
+ *
+ *     So we have a hook here to fake ATA_BUSY for that situation,
+ *     until the first time a BUSY, DRQ, or ERR bit is seen.
+ *
+ *     The rest of the time, it simply returns the ATA status register.
+ */
+static u8 mv_sff_check_status(struct ata_port *ap)
+{
+       u8 stat = ioread8(ap->ioaddr.status_addr);
+       struct mv_port_priv *pp = ap->private_data;
+
+       if (pp->pp_flags & MV_PP_FLAG_FAKE_ATA_BUSY) {
+               if (stat & (ATA_BUSY | ATA_DRQ | ATA_ERR))
+                       pp->pp_flags &= ~MV_PP_FLAG_FAKE_ATA_BUSY;
+               else
+                       stat = ATA_BUSY;
+       }
+       return stat;
+}
+
+/**
+ *     mv_send_fis - Send a FIS, using the "Vendor-Unique FIS" register
+ *     @fis: fis to be sent
+ *     @nwords: number of 32-bit words in the fis
+ */
+static unsigned int mv_send_fis(struct ata_port *ap, u32 *fis, int nwords)
+{
+       void __iomem *port_mmio = mv_ap_base(ap);
+       u32 ifctl, old_ifctl, ifstat;
+       int i, timeout = 200, final_word = nwords - 1;
+
+       /* Initiate FIS transmission mode */
+       old_ifctl = readl(port_mmio + SATA_IFCTL_OFS);
+       ifctl = 0x100 | (old_ifctl & 0xf);
+       writelfl(ifctl, port_mmio + SATA_IFCTL_OFS);
+
+       /* Send all words of the FIS except for the final word */
+       for (i = 0; i < final_word; ++i)
+               writel(fis[i], port_mmio + VENDOR_UNIQUE_FIS_OFS);
+
+       /* Flag end-of-transmission, and then send the final word */
+       writelfl(ifctl | 0x200, port_mmio + SATA_IFCTL_OFS);
+       writelfl(fis[final_word], port_mmio + VENDOR_UNIQUE_FIS_OFS);
+
+       /*
+        * Wait for FIS transmission to complete.
+        * This typically takes just a single iteration.
+        */
+       do {
+               ifstat = readl(port_mmio + SATA_IFSTAT_OFS);
+       } while (!(ifstat & 0x1000) && --timeout);
+
+       /* Restore original port configuration */
+       writelfl(old_ifctl, port_mmio + SATA_IFCTL_OFS);
+
+       /* See if it worked */
+       if ((ifstat & 0x3000) != 0x1000) {
+               ata_port_printk(ap, KERN_WARNING,
+                               "%s transmission error, ifstat=%08x\n",
+                               __func__, ifstat);
+               return AC_ERR_OTHER;
+       }
+       return 0;
+}
+
+/**
+ *     mv_qc_issue_fis - Issue a command directly as a FIS
+ *     @qc: queued command to start
+ *
+ *     Note that the ATA shadow registers are not updated
+ *     after command issue, so the device will appear "READY"
+ *     if polled, even while it is BUSY processing the command.
+ *
+ *     So we use a status hook to fake ATA_BUSY until the drive changes state.
+ *
+ *     Note: we don't get updated shadow regs on *completion*
+ *     of non-data commands. So avoid sending them via this function,
+ *     as they will appear to have completed immediately.
+ *
+ *     GEN_IIE has special registers that we could get the result tf from,
+ *     but earlier chipsets do not.  For now, we ignore those registers.
+ */
+static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct mv_port_priv *pp = ap->private_data;
+       struct ata_link *link = qc->dev->link;
+       u32 fis[5];
+       int err = 0;
+
+       ata_tf_to_fis(&qc->tf, link->pmp, 1, (void *)fis);
+       err = mv_send_fis(ap, fis, sizeof(fis) / sizeof(fis[0]));
+       if (err)
+               return err;
+
+       switch (qc->tf.protocol) {
+       case ATAPI_PROT_PIO:
+               pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
+               /* fall through */
+       case ATAPI_PROT_NODATA:
+               ap->hsm_task_state = HSM_ST_FIRST;
+               break;
+       case ATA_PROT_PIO:
+               pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
+               if (qc->tf.flags & ATA_TFLAG_WRITE)
+                       ap->hsm_task_state = HSM_ST_FIRST;
+               else
+                       ap->hsm_task_state = HSM_ST;
+               break;
+       default:
+               ap->hsm_task_state = HSM_ST_LAST;
+               break;
+       }
+
+       if (qc->tf.flags & ATA_TFLAG_POLLING)
+               ata_pio_queue_task(ap, qc, 0);
+       return 0;
+}
+
 /**
  *      mv_qc_issue - Initiate a command to the host
  *      @qc: queued command to start
@@ -1558,14 +2130,28 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
  */
 static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
 {
+       static int limit_warnings = 10;
        struct ata_port *ap = qc->ap;
        void __iomem *port_mmio = mv_ap_base(ap);
        struct mv_port_priv *pp = ap->private_data;
        u32 in_index;
+       unsigned int port_irqs;
 
-       if ((qc->tf.protocol != ATA_PROT_DMA) &&
-           (qc->tf.protocol != ATA_PROT_NCQ)) {
-               static int limit_warnings = 10;
+       pp->pp_flags &= ~MV_PP_FLAG_FAKE_ATA_BUSY; /* paranoia */
+
+       switch (qc->tf.protocol) {
+       case ATA_PROT_DMA:
+       case ATA_PROT_NCQ:
+               mv_start_edma(ap, port_mmio, pp, qc->tf.protocol);
+               pp->req_idx = (pp->req_idx + 1) & MV_MAX_Q_DEPTH_MASK;
+               in_index = pp->req_idx << EDMA_REQ_Q_PTR_SHIFT;
+
+               /* Write the request in pointer to kick the EDMA to life */
+               writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
+                                       port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+               return 0;
+
+       case ATA_PROT_PIO:
                /*
                 * Errata SATA#16, SATA#24: warn if multiple DRQs expected.
                 *
@@ -1583,27 +2169,46 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
                                        ": attempting PIO w/multiple DRQ: "
                                        "this may fail due to h/w errata\n");
                }
-               /*
-                * We're about to send a non-EDMA capable command to the
-                * port.  Turn off EDMA so there won't be problems accessing
-                * shadow block, etc registers.
-                */
-               mv_stop_edma(ap);
-               mv_enable_port_irqs(ap, ERR_IRQ);
-               mv_pmp_select(ap, qc->dev->link->pmp);
-               return ata_sff_qc_issue(qc);
+               /* drop through */
+       case ATA_PROT_NODATA:
+       case ATAPI_PROT_PIO:
+       case ATAPI_PROT_NODATA:
+               if (ap->flags & ATA_FLAG_PIO_POLLING)
+                       qc->tf.flags |= ATA_TFLAG_POLLING;
+               break;
        }
 
-       mv_start_dma(ap, port_mmio, pp, qc->tf.protocol);
-
-       pp->req_idx = (pp->req_idx + 1) & MV_MAX_Q_DEPTH_MASK;
-       in_index = pp->req_idx << EDMA_REQ_Q_PTR_SHIFT;
+       if (qc->tf.flags & ATA_TFLAG_POLLING)
+               port_irqs = ERR_IRQ;    /* mask device interrupt when polling */
+       else
+               port_irqs = ERR_IRQ | DONE_IRQ; /* unmask all interrupts */
 
-       /* and write the request in pointer to kick the EDMA to life */
-       writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
-                port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+       /*
+        * We're about to send a non-EDMA capable command to the
+        * port.  Turn off EDMA so there won't be problems accessing
+        * shadow block, etc registers.
+        */
+       mv_stop_edma(ap);
+       mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs);
+       mv_pmp_select(ap, qc->dev->link->pmp);
 
-       return 0;
+       if (qc->tf.command == ATA_CMD_READ_LOG_EXT) {
+               struct mv_host_priv *hpriv = ap->host->private_data;
+               /*
+                * Workaround for 88SX60x1 FEr SATA#25 (part 2).
+                *
+                * After any NCQ error, the READ_LOG_EXT command
+                * from libata-eh *must* use mv_qc_issue_fis().
+                * Otherwise it might fail, due to chip errata.
+                *
+                * Rather than special-case it, we'll just *always*
+                * use this method here for READ_LOG_EXT, making for
+                * easier testing.
+                */
+               if (IS_GEN_II(hpriv))
+                       return mv_qc_issue_fis(qc);
+       }
+       return ata_sff_qc_issue(qc);
 }
 
 static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
@@ -1614,8 +2219,12 @@ static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
        if (pp->pp_flags & MV_PP_FLAG_NCQ_EN)
                return NULL;
        qc = ata_qc_from_tag(ap, ap->link.active_tag);
-       if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
-               qc = NULL;
+       if (qc) {
+               if (qc->tf.flags & ATA_TFLAG_POLLING)
+                       qc = NULL;
+               else if (!(qc->flags & ATA_QCFLAG_ACTIVE))
+                       qc = NULL;
+       }
        return qc;
 }
 
@@ -2084,6 +2693,10 @@ static int mv_host_intr(struct ata_host *host, u32 main_irq_cause)
        void __iomem *mmio = hpriv->base, *hc_mmio;
        unsigned int handled = 0, port;
 
+       /* If asserted, clear the "all ports" IRQ coalescing bit */
+       if (main_irq_cause & ALL_PORTS_COAL_DONE)
+               writel(~ALL_PORTS_COAL_IRQ, mmio + MV_IRQ_COAL_CAUSE);
+
        for (port = 0; port < hpriv->n_ports; port++) {
                struct ata_port *ap = host->ports[port];
                unsigned int p, shift, hardport, port_cause;
@@ -2116,6 +2729,8 @@ static int mv_host_intr(struct ata_host *host, u32 main_irq_cause)
                         * to ack (only) those ports via hc_irq_cause.
                         */
                        ack_irqs = 0;
+                       if (hc_cause & PORTS_0_3_COAL_DONE)
+                               ack_irqs = HC_COAL_IRQ;
                        for (p = 0; p < MV_PORTS_PER_HC; ++p) {
                                if ((port + p) >= hpriv->n_ports)
                                        break;
@@ -2204,7 +2819,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
 
        /* for MSI:  block new interrupts while in here */
        if (using_msi)
-               writel(0, hpriv->main_irq_mask_addr);
+               mv_write_main_irq_mask(0, hpriv);
 
        main_irq_cause = readl(hpriv->main_irq_cause_addr);
        pending_irqs   = main_irq_cause & hpriv->main_irq_mask;
@@ -2218,11 +2833,12 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
                else
                        handled = mv_host_intr(host, pending_irqs);
        }
-       spin_unlock(&host->lock);
 
        /* for MSI: unmask; interrupt cause bits will retrigger now */
        if (using_msi)
-               writel(hpriv->main_irq_mask, hpriv->main_irq_mask_addr);
+               mv_write_main_irq_mask(hpriv->main_irq_mask, hpriv);
+
+       spin_unlock(&host->lock);
 
        return IRQ_RETVAL(handled);
 }
@@ -2773,6 +3389,8 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
 
        mv_reset_channel(hpriv, mmio, ap->port_no);
        pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+       pp->pp_flags &=
+         ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN | MV_PP_FLAG_FAKE_ATA_BUSY);
 
        /* Workaround for errata FEr SATA#10 (part 2) */
        do {
@@ -2792,6 +3410,8 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
                                extra = HZ; /* only extend it once, max */
                }
        } while (sstatus != 0x0 && sstatus != 0x113 && sstatus != 0x123);
+       mv_save_cached_regs(ap);
+       mv_edma_cfg(ap, 0, 0);
 
        return rc;
 }
@@ -3125,6 +3745,8 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
         * The per-port interrupts get done later as ports are set up.
         */
        mv_set_main_irq_mask(host, 0, PCI_ERR);
+       mv_set_irq_coalescing(host, irq_coalescing_io_count,
+                                   irq_coalescing_usecs);
 done:
        return rc;
 }
@@ -3286,12 +3908,6 @@ static struct pci_driver mv_pci_driver = {
        .remove                 = ata_pci_remove_one,
 };
 
-/*
- * module options
- */
-static int msi;              /* Use PCI msi; either zero (off, default) or non-zero */
-
-
 /* move to PCI layer or libata core? */
 static int pci_go_64(struct pci_dev *pdev)
 {
@@ -3473,10 +4089,5 @@ MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 MODULE_ALIAS("platform:" DRV_NAME);
 
-#ifdef CONFIG_PCI
-module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
-#endif
-
 module_init(mv_init);
 module_exit(mv_exit);