libata-sff: separate out BMDMA qc_issue
[safe/jmp/linux-2.6] / drivers / ata / sata_nv.c
index aea005d..baa8f0d 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/gfp.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
@@ -49,7 +50,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME                       "sata_nv"
-#define DRV_VERSION                    "3.3"
+#define DRV_VERSION                    "3.5"
 
 #define NV_ADMA_DMA_BOUNDARY           0xffffffffUL
 
@@ -57,9 +58,9 @@ enum {
        NV_MMIO_BAR                     = 5,
 
        NV_PORTS                        = 2,
-       NV_PIO_MASK                     = 0x1f,
-       NV_MWDMA_MASK                   = 0x07,
-       NV_UDMA_MASK                    = 0x7f,
+       NV_PIO_MASK                     = ATA_PIO4,
+       NV_MWDMA_MASK                   = ATA_MWDMA2,
+       NV_UDMA_MASK                    = ATA_UDMA6,
        NV_PORT0_SCR_REG_OFFSET         = 0x00,
        NV_PORT1_SCR_REG_OFFSET         = 0x40,
 
@@ -163,12 +164,41 @@ enum {
        NV_ADMA_STAT_STOPPED            = (1 << 10),
        NV_ADMA_STAT_DONE               = (1 << 12),
        NV_ADMA_STAT_ERR                = NV_ADMA_STAT_CPBERR |
-                                         NV_ADMA_STAT_TIMEOUT,
+                                         NV_ADMA_STAT_TIMEOUT,
 
        /* port flags */
        NV_ADMA_PORT_REGISTER_MODE      = (1 << 0),
        NV_ADMA_ATAPI_SETUP_COMPLETE    = (1 << 1),
 
+       /* MCP55 reg offset */
+       NV_CTL_MCP55                    = 0x400,
+       NV_INT_STATUS_MCP55             = 0x440,
+       NV_INT_ENABLE_MCP55             = 0x444,
+       NV_NCQ_REG_MCP55                = 0x448,
+
+       /* MCP55 */
+       NV_INT_ALL_MCP55                = 0xffff,
+       NV_INT_PORT_SHIFT_MCP55         = 16,   /* each port occupies 16 bits */
+       NV_INT_MASK_MCP55               = NV_INT_ALL_MCP55 & 0xfffd,
+
+       /* SWNCQ ENABLE BITS*/
+       NV_CTL_PRI_SWNCQ                = 0x02,
+       NV_CTL_SEC_SWNCQ                = 0x04,
+
+       /* SW NCQ status bits*/
+       NV_SWNCQ_IRQ_DEV                = (1 << 0),
+       NV_SWNCQ_IRQ_PM                 = (1 << 1),
+       NV_SWNCQ_IRQ_ADDED              = (1 << 2),
+       NV_SWNCQ_IRQ_REMOVED            = (1 << 3),
+
+       NV_SWNCQ_IRQ_BACKOUT            = (1 << 4),
+       NV_SWNCQ_IRQ_SDBFIS             = (1 << 5),
+       NV_SWNCQ_IRQ_DHREGFIS           = (1 << 6),
+       NV_SWNCQ_IRQ_DMASETUP           = (1 << 7),
+
+       NV_SWNCQ_IRQ_HOTPLUG            = NV_SWNCQ_IRQ_ADDED |
+                                         NV_SWNCQ_IRQ_REMOVED,
+
 };
 
 /* ADMA Physical Region Descriptor - one SG segment */
@@ -199,7 +229,7 @@ struct nv_adma_cpb {
        u8                      reserved1;     /* 1 */
        u8                      ctl_flags;     /* 2 */
        /* len is length of taskfile in 64 bit words */
-       u8                      len;           /* 3  */
+       u8                      len;            /* 3  */
        u8                      tag;           /* 4 */
        u8                      next_cpb_idx;  /* 5 */
        __le16                  reserved2;     /* 6-7 */
@@ -215,33 +245,73 @@ struct nv_adma_port_priv {
        dma_addr_t              cpb_dma;
        struct nv_adma_prd      *aprd;
        dma_addr_t              aprd_dma;
-       void __iomem *          ctl_block;
-       void __iomem *          gen_block;
-       void __iomem *          notifier_clear_block;
+       void __iomem            *ctl_block;
+       void __iomem            *gen_block;
+       void __iomem            *notifier_clear_block;
+       u64                     adma_dma_mask;
        u8                      flags;
+       int                     last_issue_ncq;
 };
 
 struct nv_host_priv {
        unsigned long           type;
 };
 
-#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT)))))
+struct defer_queue {
+       u32             defer_bits;
+       unsigned int    head;
+       unsigned int    tail;
+       unsigned int    tag[ATA_MAX_QUEUE];
+};
+
+enum ncq_saw_flag_list {
+       ncq_saw_d2h     = (1U << 0),
+       ncq_saw_dmas    = (1U << 1),
+       ncq_saw_sdb     = (1U << 2),
+       ncq_saw_backout = (1U << 3),
+};
+
+struct nv_swncq_port_priv {
+       struct ata_bmdma_prd *prd;       /* our SG list */
+       dma_addr_t      prd_dma; /* and its DMA mapping */
+       void __iomem    *sactive_block;
+       void __iomem    *irq_block;
+       void __iomem    *tag_block;
+       u32             qc_active;
+
+       unsigned int    last_issue_tag;
+
+       /* fifo circular queue to store deferral command */
+       struct defer_queue defer_queue;
+
+       /* for NCQ interrupt analysis */
+       u32             dhfis_bits;
+       u32             dmafis_bits;
+       u32             sdbfis_bits;
+
+       unsigned int    ncq_flags;
+};
+
 
-static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static void nv_remove_one (struct pci_dev *pdev);
+#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & (1 << (19 + (12 * (PORT)))))
+
+static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+#ifdef CONFIG_PM
 static int nv_pci_device_resume(struct pci_dev *pdev);
+#endif
 static void nv_ck804_host_stop(struct ata_host *host);
 static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
+                       unsigned long deadline);
 static void nv_nf2_freeze(struct ata_port *ap);
 static void nv_nf2_thaw(struct ata_port *ap);
 static void nv_ck804_freeze(struct ata_port *ap);
 static void nv_ck804_thaw(struct ata_port *ap);
-static void nv_error_handler(struct ata_port *ap);
 static int nv_adma_slave_config(struct scsi_device *sdev);
 static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc);
 static void nv_adma_qc_prep(struct ata_queued_cmd *qc);
@@ -250,14 +320,31 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance);
 static void nv_adma_irq_clear(struct ata_port *ap);
 static int nv_adma_port_start(struct ata_port *ap);
 static void nv_adma_port_stop(struct ata_port *ap);
+#ifdef CONFIG_PM
 static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg);
 static int nv_adma_port_resume(struct ata_port *ap);
+#endif
+static void nv_adma_freeze(struct ata_port *ap);
+static void nv_adma_thaw(struct ata_port *ap);
 static void nv_adma_error_handler(struct ata_port *ap);
 static void nv_adma_host_stop(struct ata_host *host);
-static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc);
-static void nv_adma_bmdma_start(struct ata_queued_cmd *qc);
-static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc);
-static u8 nv_adma_bmdma_status(struct ata_port *ap);
+static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+
+static void nv_mcp55_thaw(struct ata_port *ap);
+static void nv_mcp55_freeze(struct ata_port *ap);
+static void nv_swncq_error_handler(struct ata_port *ap);
+static int nv_swncq_slave_config(struct scsi_device *sdev);
+static int nv_swncq_port_start(struct ata_port *ap);
+static void nv_swncq_qc_prep(struct ata_queued_cmd *qc);
+static void nv_swncq_fill_sg(struct ata_queued_cmd *qc);
+static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc);
+static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis);
+static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance);
+#ifdef CONFIG_PM
+static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg);
+static int nv_swncq_port_resume(struct ata_port *ap);
+#endif
 
 enum nv_host_type
 {
@@ -265,7 +352,9 @@ enum nv_host_type
        NFORCE2,
        NFORCE3 = NFORCE2,      /* NF2 == NF3 as far as sata_nv is concerned */
        CK804,
-       ADMA
+       ADMA,
+       MCP5x,
+       SWNCQ,
 };
 
 static const struct pci_device_id nv_pci_tbl[] = {
@@ -276,19 +365,13 @@ static const struct pci_device_id nv_pci_tbl[] = {
        { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 },
        { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 },
        { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), MCP5x },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), MCP5x },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), MCP5x },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), MCP5x },
        { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC },
        { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC },
        { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC },
-       { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
-               PCI_ANY_ID, PCI_ANY_ID,
-               PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
-       { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
-               PCI_ANY_ID, PCI_ANY_ID,
-               PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
 
        { } /* terminate list */
 };
@@ -297,206 +380,218 @@ static struct pci_driver nv_pci_driver = {
        .name                   = DRV_NAME,
        .id_table               = nv_pci_tbl,
        .probe                  = nv_init_one,
+#ifdef CONFIG_PM
        .suspend                = ata_pci_device_suspend,
        .resume                 = nv_pci_device_resume,
-       .remove                 = nv_remove_one,
+#endif
+       .remove                 = ata_pci_remove_one,
 };
 
 static struct scsi_host_template nv_sht = {
-       .module                 = THIS_MODULE,
-       .name                   = DRV_NAME,
-       .ioctl                  = ata_scsi_ioctl,
-       .queuecommand           = ata_scsi_queuecmd,
-       .can_queue              = ATA_DEF_QUEUE,
-       .this_id                = ATA_SHT_THIS_ID,
-       .sg_tablesize           = LIBATA_MAX_PRD,
-       .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
-       .emulated               = ATA_SHT_EMULATED,
-       .use_clustering         = ATA_SHT_USE_CLUSTERING,
-       .proc_name              = DRV_NAME,
-       .dma_boundary           = ATA_DMA_BOUNDARY,
-       .slave_configure        = ata_scsi_slave_config,
-       .slave_destroy          = ata_scsi_slave_destroy,
-       .bios_param             = ata_std_bios_param,
-       .suspend                = ata_scsi_device_suspend,
-       .resume                 = ata_scsi_device_resume,
+       ATA_BMDMA_SHT(DRV_NAME),
 };
 
 static struct scsi_host_template nv_adma_sht = {
-       .module                 = THIS_MODULE,
-       .name                   = DRV_NAME,
-       .ioctl                  = ata_scsi_ioctl,
-       .queuecommand           = ata_scsi_queuecmd,
+       ATA_NCQ_SHT(DRV_NAME),
        .can_queue              = NV_ADMA_MAX_CPBS,
-       .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = NV_ADMA_SGTBL_TOTAL_LEN,
-       .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
-       .emulated               = ATA_SHT_EMULATED,
-       .use_clustering         = ATA_SHT_USE_CLUSTERING,
-       .proc_name              = DRV_NAME,
        .dma_boundary           = NV_ADMA_DMA_BOUNDARY,
        .slave_configure        = nv_adma_slave_config,
-       .slave_destroy          = ata_scsi_slave_destroy,
-       .bios_param             = ata_std_bios_param,
-       .suspend                = ata_scsi_device_suspend,
-       .resume                 = ata_scsi_device_resume,
 };
 
-static const struct ata_port_operations nv_generic_ops = {
-       .port_disable           = ata_port_disable,
-       .tf_load                = ata_tf_load,
-       .tf_read                = ata_tf_read,
-       .exec_command           = ata_exec_command,
-       .check_status           = ata_check_status,
-       .dev_select             = ata_std_dev_select,
-       .bmdma_setup            = ata_bmdma_setup,
-       .bmdma_start            = ata_bmdma_start,
-       .bmdma_stop             = ata_bmdma_stop,
-       .bmdma_status           = ata_bmdma_status,
-       .qc_prep                = ata_qc_prep,
-       .qc_issue               = ata_qc_issue_prot,
-       .freeze                 = ata_bmdma_freeze,
-       .thaw                   = ata_bmdma_thaw,
-       .error_handler          = nv_error_handler,
-       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-       .data_xfer              = ata_data_xfer,
-       .irq_handler            = nv_generic_interrupt,
-       .irq_clear              = ata_bmdma_irq_clear,
-       .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
+static struct scsi_host_template nv_swncq_sht = {
+       ATA_NCQ_SHT(DRV_NAME),
+       .can_queue              = ATA_MAX_QUEUE,
+       .sg_tablesize           = LIBATA_MAX_PRD,
+       .dma_boundary           = ATA_DMA_BOUNDARY,
+       .slave_configure        = nv_swncq_slave_config,
+};
+
+/*
+ * NV SATA controllers have various different problems with hardreset
+ * protocol depending on the specific controller and device.
+ *
+ * GENERIC:
+ *
+ *  bko11195 reports that link doesn't come online after hardreset on
+ *  generic nv's and there have been several other similar reports on
+ *  linux-ide.
+ *
+ *  bko12351#c23 reports that warmplug on MCP61 doesn't work with
+ *  softreset.
+ *
+ * NF2/3:
+ *
+ *  bko3352 reports nf2/3 controllers can't determine device signature
+ *  reliably after hardreset.  The following thread reports detection
+ *  failure on cold boot with the standard debouncing timing.
+ *
+ *  http://thread.gmane.org/gmane.linux.ide/34098
+ *
+ *  bko12176 reports that hardreset fails to bring up the link during
+ *  boot on nf2.
+ *
+ * CK804:
+ *
+ *  For initial probing after boot and hot plugging, hardreset mostly
+ *  works fine on CK804 but curiously, reprobing on the initial port
+ *  by rescanning or rmmod/insmod fails to acquire the initial D2H Reg
+ *  FIS in somewhat undeterministic way.
+ *
+ * SWNCQ:
+ *
+ *  bko12351 reports that when SWNCQ is enabled, for hotplug to work,
+ *  hardreset should be used and hardreset can't report proper
+ *  signature, which suggests that mcp5x is closer to nf2 as long as
+ *  reset quirkiness is concerned.
+ *
+ *  bko12703 reports that boot probing fails for intel SSD with
+ *  hardreset.  Link fails to come online.  Softreset works fine.
+ *
+ * The failures are varied but the following patterns seem true for
+ * all flavors.
+ *
+ * - Softreset during boot always works.
+ *
+ * - Hardreset during boot sometimes fails to bring up the link on
+ *   certain comibnations and device signature acquisition is
+ *   unreliable.
+ *
+ * - Hardreset is often necessary after hotplug.
+ *
+ * So, preferring softreset for boot probing and error handling (as
+ * hardreset might bring down the link) but using hardreset for
+ * post-boot probing should work around the above issues in most
+ * cases.  Define nv_hardreset() which only kicks in for post-boot
+ * probing and use it for all variants.
+ */
+static struct ata_port_operations nv_generic_ops = {
+       .inherits               = &ata_bmdma_port_ops,
+       .lost_interrupt         = ATA_OP_NULL,
        .scr_read               = nv_scr_read,
        .scr_write              = nv_scr_write,
-       .port_start             = ata_port_start,
+       .hardreset              = nv_hardreset,
 };
 
-static const struct ata_port_operations nv_nf2_ops = {
-       .port_disable           = ata_port_disable,
-       .tf_load                = ata_tf_load,
-       .tf_read                = ata_tf_read,
-       .exec_command           = ata_exec_command,
-       .check_status           = ata_check_status,
-       .dev_select             = ata_std_dev_select,
-       .bmdma_setup            = ata_bmdma_setup,
-       .bmdma_start            = ata_bmdma_start,
-       .bmdma_stop             = ata_bmdma_stop,
-       .bmdma_status           = ata_bmdma_status,
-       .qc_prep                = ata_qc_prep,
-       .qc_issue               = ata_qc_issue_prot,
+static struct ata_port_operations nv_nf2_ops = {
+       .inherits               = &nv_generic_ops,
        .freeze                 = nv_nf2_freeze,
        .thaw                   = nv_nf2_thaw,
-       .error_handler          = nv_error_handler,
-       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-       .data_xfer              = ata_data_xfer,
-       .irq_handler            = nv_nf2_interrupt,
-       .irq_clear              = ata_bmdma_irq_clear,
-       .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
-       .scr_read               = nv_scr_read,
-       .scr_write              = nv_scr_write,
-       .port_start             = ata_port_start,
 };
 
-static const struct ata_port_operations nv_ck804_ops = {
-       .port_disable           = ata_port_disable,
-       .tf_load                = ata_tf_load,
-       .tf_read                = ata_tf_read,
-       .exec_command           = ata_exec_command,
-       .check_status           = ata_check_status,
-       .dev_select             = ata_std_dev_select,
-       .bmdma_setup            = ata_bmdma_setup,
-       .bmdma_start            = ata_bmdma_start,
-       .bmdma_stop             = ata_bmdma_stop,
-       .bmdma_status           = ata_bmdma_status,
-       .qc_prep                = ata_qc_prep,
-       .qc_issue               = ata_qc_issue_prot,
+static struct ata_port_operations nv_ck804_ops = {
+       .inherits               = &nv_generic_ops,
        .freeze                 = nv_ck804_freeze,
        .thaw                   = nv_ck804_thaw,
-       .error_handler          = nv_error_handler,
-       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-       .data_xfer              = ata_data_xfer,
-       .irq_handler            = nv_ck804_interrupt,
-       .irq_clear              = ata_bmdma_irq_clear,
-       .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
-       .scr_read               = nv_scr_read,
-       .scr_write              = nv_scr_write,
-       .port_start             = ata_port_start,
        .host_stop              = nv_ck804_host_stop,
 };
 
-static const struct ata_port_operations nv_adma_ops = {
-       .port_disable           = ata_port_disable,
-       .tf_load                = ata_tf_load,
-       .tf_read                = ata_tf_read,
+static struct ata_port_operations nv_adma_ops = {
+       .inherits               = &nv_ck804_ops,
+
        .check_atapi_dma        = nv_adma_check_atapi_dma,
-       .exec_command           = ata_exec_command,
-       .check_status           = ata_check_status,
-       .dev_select             = ata_std_dev_select,
-       .bmdma_setup            = nv_adma_bmdma_setup,
-       .bmdma_start            = nv_adma_bmdma_start,
-       .bmdma_stop             = nv_adma_bmdma_stop,
-       .bmdma_status           = nv_adma_bmdma_status,
+       .sff_tf_read            = nv_adma_tf_read,
+       .qc_defer               = ata_std_qc_defer,
        .qc_prep                = nv_adma_qc_prep,
        .qc_issue               = nv_adma_qc_issue,
-       .freeze                 = nv_ck804_freeze,
-       .thaw                   = nv_ck804_thaw,
+       .sff_irq_clear          = nv_adma_irq_clear,
+
+       .freeze                 = nv_adma_freeze,
+       .thaw                   = nv_adma_thaw,
        .error_handler          = nv_adma_error_handler,
-       .post_internal_cmd      = nv_adma_bmdma_stop,
-       .data_xfer              = ata_data_xfer,
-       .irq_handler            = nv_adma_interrupt,
-       .irq_clear              = nv_adma_irq_clear,
-       .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
-       .scr_read               = nv_scr_read,
-       .scr_write              = nv_scr_write,
+       .post_internal_cmd      = nv_adma_post_internal_cmd,
+
        .port_start             = nv_adma_port_start,
        .port_stop              = nv_adma_port_stop,
+#ifdef CONFIG_PM
        .port_suspend           = nv_adma_port_suspend,
        .port_resume            = nv_adma_port_resume,
+#endif
        .host_stop              = nv_adma_host_stop,
 };
 
-static struct ata_port_info nv_port_info[] = {
+static struct ata_port_operations nv_swncq_ops = {
+       .inherits               = &nv_generic_ops,
+
+       .qc_defer               = ata_std_qc_defer,
+       .qc_prep                = nv_swncq_qc_prep,
+       .qc_issue               = nv_swncq_qc_issue,
+
+       .freeze                 = nv_mcp55_freeze,
+       .thaw                   = nv_mcp55_thaw,
+       .error_handler          = nv_swncq_error_handler,
+
+#ifdef CONFIG_PM
+       .port_suspend           = nv_swncq_port_suspend,
+       .port_resume            = nv_swncq_port_resume,
+#endif
+       .port_start             = nv_swncq_port_start,
+};
+
+struct nv_pi_priv {
+       irq_handler_t                   irq_handler;
+       struct scsi_host_template       *sht;
+};
+
+#define NV_PI_PRIV(_irq_handler, _sht) \
+       &(struct nv_pi_priv){ .irq_handler = _irq_handler, .sht = _sht }
+
+static const struct ata_port_info nv_port_info[] = {
        /* generic */
        {
-               .sht            = &nv_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_HRST_TO_RESUME,
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
                .pio_mask       = NV_PIO_MASK,
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
                .port_ops       = &nv_generic_ops,
+               .private_data   = NV_PI_PRIV(nv_generic_interrupt, &nv_sht),
        },
        /* nforce2/3 */
        {
-               .sht            = &nv_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_HRST_TO_RESUME,
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
                .pio_mask       = NV_PIO_MASK,
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
                .port_ops       = &nv_nf2_ops,
+               .private_data   = NV_PI_PRIV(nv_nf2_interrupt, &nv_sht),
        },
        /* ck804 */
        {
-               .sht            = &nv_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_HRST_TO_RESUME,
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
                .pio_mask       = NV_PIO_MASK,
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
                .port_ops       = &nv_ck804_ops,
+               .private_data   = NV_PI_PRIV(nv_ck804_interrupt, &nv_sht),
        },
        /* ADMA */
        {
-               .sht            = &nv_adma_sht,
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_HRST_TO_RESUME |
                                  ATA_FLAG_MMIO | ATA_FLAG_NCQ,
                .pio_mask       = NV_PIO_MASK,
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
                .port_ops       = &nv_adma_ops,
+               .private_data   = NV_PI_PRIV(nv_adma_interrupt, &nv_adma_sht),
+       },
+       /* MCP5x */
+       {
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+               .pio_mask       = NV_PIO_MASK,
+               .mwdma_mask     = NV_MWDMA_MASK,
+               .udma_mask      = NV_UDMA_MASK,
+               .port_ops       = &nv_generic_ops,
+               .private_data   = NV_PI_PRIV(nv_generic_interrupt, &nv_sht),
+       },
+       /* SWNCQ */
+       {
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_NCQ,
+               .pio_mask       = NV_PIO_MASK,
+               .mwdma_mask     = NV_MWDMA_MASK,
+               .udma_mask      = NV_UDMA_MASK,
+               .port_ops       = &nv_swncq_ops,
+               .private_data   = NV_PI_PRIV(nv_swncq_interrupt, &nv_swncq_sht),
        },
 };
 
@@ -506,7 +601,9 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static int adma_enabled = 1;
+static int adma_enabled;
+static int swncq_enabled = 1;
+static int msi_enabled;
 
 static void nv_adma_register_mode(struct ata_port *ap)
 {
@@ -519,12 +616,12 @@ static void nv_adma_register_mode(struct ata_port *ap)
                return;
 
        status = readw(mmio + NV_ADMA_STAT);
-       while(!(status & NV_ADMA_STAT_IDLE) && count < 20) {
+       while (!(status & NV_ADMA_STAT_IDLE) && count < 20) {
                ndelay(50);
                status = readw(mmio + NV_ADMA_STAT);
                count++;
        }
-       if(count == 20)
+       if (count == 20)
                ata_port_printk(ap, KERN_WARNING,
                        "timeout waiting for ADMA IDLE, stat=0x%hx\n",
                        status);
@@ -534,12 +631,12 @@ static void nv_adma_register_mode(struct ata_port *ap)
 
        count = 0;
        status = readw(mmio + NV_ADMA_STAT);
-       while(!(status & NV_ADMA_STAT_LEGACY) && count < 20) {
+       while (!(status & NV_ADMA_STAT_LEGACY) && count < 20) {
                ndelay(50);
                status = readw(mmio + NV_ADMA_STAT);
                count++;
        }
-       if(count == 20)
+       if (count == 20)
                ata_port_printk(ap, KERN_WARNING,
                         "timeout waiting for ADMA LEGACY, stat=0x%hx\n",
                         status);
@@ -563,13 +660,13 @@ static void nv_adma_mode(struct ata_port *ap)
        writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
 
        status = readw(mmio + NV_ADMA_STAT);
-       while(((status & NV_ADMA_STAT_LEGACY) ||
+       while (((status & NV_ADMA_STAT_LEGACY) ||
              !(status & NV_ADMA_STAT_IDLE)) && count < 20) {
                ndelay(50);
                status = readw(mmio + NV_ADMA_STAT);
                count++;
        }
-       if(count == 20)
+       if (count == 20)
                ata_port_printk(ap, KERN_WARNING,
                        "timeout waiting for ADMA LEGACY clear and IDLE, stat=0x%hx\n",
                        status);
@@ -581,9 +678,10 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
 {
        struct ata_port *ap = ata_shost_to_port(sdev->host);
        struct nv_adma_port_priv *pp = ap->private_data;
+       struct nv_adma_port_priv *port0, *port1;
+       struct scsi_device *sdev0, *sdev1;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u64 bounce_limit;
-       unsigned long segment_boundary;
+       unsigned long segment_boundary, flags;
        unsigned short sg_tablesize;
        int rc;
        int adma_enable;
@@ -595,7 +693,9 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                /* Not a proper libata device, ignore */
                return rc;
 
-       if (ap->device[sdev->id].class == ATA_DEV_ATAPI) {
+       spin_lock_irqsave(ap->lock, flags);
+
+       if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) {
                /*
                 * NVIDIA reports that ADMA mode does not support ATAPI commands.
                 * Therefore ATAPI commands are sent through the legacy interface.
@@ -603,7 +703,6 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                 * Restrict DMA parameters as required by the legacy interface
                 * when an ATAPI device is connected.
                 */
-               bounce_limit = ATA_DMA_MASK;
                segment_boundary = ATA_DMA_BOUNDARY;
                /* Subtract 1 since an extra entry may be needed for padding, see
                   libata-scsi.c */
@@ -613,9 +712,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                   on the port. */
                adma_enable = 0;
                nv_adma_register_mode(ap);
-       }
-       else {
-               bounce_limit = *ap->dev->dma_mask;
+       } else {
                segment_boundary = NV_ADMA_DMA_BOUNDARY;
                sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN;
                adma_enable = 1;
@@ -623,31 +720,67 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
 
        pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &current_reg);
 
-       if(ap->port_no == 1)
+       if (ap->port_no == 1)
                config_mask = NV_MCP_SATA_CFG_20_PORT1_EN |
                              NV_MCP_SATA_CFG_20_PORT1_PWB_EN;
        else
                config_mask = NV_MCP_SATA_CFG_20_PORT0_EN |
                              NV_MCP_SATA_CFG_20_PORT0_PWB_EN;
 
-       if(adma_enable) {
+       if (adma_enable) {
                new_reg = current_reg | config_mask;
                pp->flags &= ~NV_ADMA_ATAPI_SETUP_COMPLETE;
-       }
-       else {
+       } else {
                new_reg = current_reg & ~config_mask;
                pp->flags |= NV_ADMA_ATAPI_SETUP_COMPLETE;
        }
 
-       if(current_reg != new_reg)
+       if (current_reg != new_reg)
                pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg);
 
-       blk_queue_bounce_limit(sdev->request_queue, bounce_limit);
+       port0 = ap->host->ports[0]->private_data;
+       port1 = ap->host->ports[1]->private_data;
+       sdev0 = ap->host->ports[0]->link.device[0].sdev;
+       sdev1 = ap->host->ports[1]->link.device[0].sdev;
+       if ((port0->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
+           (port1->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
+               /** We have to set the DMA mask to 32-bit if either port is in
+                   ATAPI mode, since they are on the same PCI device which is
+                   used for DMA mapping. If we set the mask we also need to set
+                   the bounce limit on both ports to ensure that the block
+                   layer doesn't feed addresses that cause DMA mapping to
+                   choke. If either SCSI device is not allocated yet, it's OK
+                   since that port will discover its correct setting when it
+                   does get allocated.
+                   Note: Setting 32-bit mask should not fail. */
+               if (sdev0)
+                       blk_queue_bounce_limit(sdev0->request_queue,
+                                              ATA_DMA_MASK);
+               if (sdev1)
+                       blk_queue_bounce_limit(sdev1->request_queue,
+                                              ATA_DMA_MASK);
+
+               pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       } else {
+               /** This shouldn't fail as it was set to this value before */
+               pci_set_dma_mask(pdev, pp->adma_dma_mask);
+               if (sdev0)
+                       blk_queue_bounce_limit(sdev0->request_queue,
+                                              pp->adma_dma_mask);
+               if (sdev1)
+                       blk_queue_bounce_limit(sdev1->request_queue,
+                                              pp->adma_dma_mask);
+       }
+
        blk_queue_segment_boundary(sdev->request_queue, segment_boundary);
-       blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize);
+       blk_queue_max_segments(sdev->request_queue, sg_tablesize);
        ata_port_printk(ap, KERN_INFO,
-               "bounce limit 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
-               (unsigned long long)bounce_limit, segment_boundary, sg_tablesize);
+               "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
+               (unsigned long long)*ap->host->dev->dma_mask,
+               segment_boundary, sg_tablesize);
+
+       spin_unlock_irqrestore(ap->lock, flags);
+
        return rc;
 }
 
@@ -657,34 +790,49 @@ static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc)
        return !(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE);
 }
 
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+       /* Other than when internal or pass-through commands are executed,
+          the only time this function will be called in ADMA mode will be
+          if a command fails. In the failure case we don't care about going
+          into register mode with ADMA commands pending, as the commands will
+          all shortly be aborted anyway. We assume that NCQ commands are not
+          issued via passthrough, which is the only way that switching into
+          ADMA mode could abort outstanding commands. */
+       nv_adma_register_mode(ap);
+
+       ata_sff_tf_read(ap, tf);
+}
+
 static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
 {
        unsigned int idx = 0;
 
-       cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device | WNB);
-
-       if ((tf->flags & ATA_TFLAG_LBA48) == 0) {
-               cpb[idx++] = cpu_to_le16(IGN);
-               cpb[idx++] = cpu_to_le16(IGN);
-               cpb[idx++] = cpu_to_le16(IGN);
-               cpb[idx++] = cpu_to_le16(IGN);
-               cpb[idx++] = cpu_to_le16(IGN);
-       }
-       else {
-               cpb[idx++] = cpu_to_le16((ATA_REG_ERR   << 8) | tf->hob_feature);
-               cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect);
-               cpb[idx++] = cpu_to_le16((ATA_REG_LBAL  << 8) | tf->hob_lbal);
-               cpb[idx++] = cpu_to_le16((ATA_REG_LBAM  << 8) | tf->hob_lbam);
-               cpb[idx++] = cpu_to_le16((ATA_REG_LBAH  << 8) | tf->hob_lbah);
+       if (tf->flags & ATA_TFLAG_ISADDR) {
+               if (tf->flags & ATA_TFLAG_LBA48) {
+                       cpb[idx++] = cpu_to_le16((ATA_REG_ERR   << 8) | tf->hob_feature | WNB);
+                       cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect);
+                       cpb[idx++] = cpu_to_le16((ATA_REG_LBAL  << 8) | tf->hob_lbal);
+                       cpb[idx++] = cpu_to_le16((ATA_REG_LBAM  << 8) | tf->hob_lbam);
+                       cpb[idx++] = cpu_to_le16((ATA_REG_LBAH  << 8) | tf->hob_lbah);
+                       cpb[idx++] = cpu_to_le16((ATA_REG_ERR    << 8) | tf->feature);
+               } else
+                       cpb[idx++] = cpu_to_le16((ATA_REG_ERR    << 8) | tf->feature | WNB);
+
+               cpb[idx++] = cpu_to_le16((ATA_REG_NSECT  << 8) | tf->nsect);
+               cpb[idx++] = cpu_to_le16((ATA_REG_LBAL   << 8) | tf->lbal);
+               cpb[idx++] = cpu_to_le16((ATA_REG_LBAM   << 8) | tf->lbam);
+               cpb[idx++] = cpu_to_le16((ATA_REG_LBAH   << 8) | tf->lbah);
        }
-       cpb[idx++] = cpu_to_le16((ATA_REG_ERR    << 8) | tf->feature);
-       cpb[idx++] = cpu_to_le16((ATA_REG_NSECT  << 8) | tf->nsect);
-       cpb[idx++] = cpu_to_le16((ATA_REG_LBAL   << 8) | tf->lbal);
-       cpb[idx++] = cpu_to_le16((ATA_REG_LBAM   << 8) | tf->lbam);
-       cpb[idx++] = cpu_to_le16((ATA_REG_LBAH   << 8) | tf->lbah);
+
+       if (tf->flags & ATA_TFLAG_DEVICE)
+               cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device);
 
        cpb[idx++] = cpu_to_le16((ATA_REG_CMD    << 8) | tf->command | CMDEND);
 
+       while (idx < 12)
+               cpb[idx++] = cpu_to_le16(IGN);
+
        return idx;
 }
 
@@ -699,23 +847,24 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
                     flags & (NV_CPB_RESP_ATA_ERR |
                              NV_CPB_RESP_CMD_ERR |
                              NV_CPB_RESP_CPB_ERR)))) {
-               struct ata_eh_info *ehi = &ap->eh_info;
+               struct ata_eh_info *ehi = &ap->link.eh_info;
                int freeze = 0;
 
                ata_ehi_clear_desc(ehi);
-               ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+               __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags);
                if (flags & NV_CPB_RESP_ATA_ERR) {
-                       ata_ehi_push_desc(ehi, "ATA error");
+                       ata_ehi_push_desc(ehi, "ATA error");
                        ehi->err_mask |= AC_ERR_DEV;
                } else if (flags & NV_CPB_RESP_CMD_ERR) {
-                       ata_ehi_push_desc(ehi, "CMD error");
+                       ata_ehi_push_desc(ehi, "CMD error");
                        ehi->err_mask |= AC_ERR_DEV;
                } else if (flags & NV_CPB_RESP_CPB_ERR) {
-                       ata_ehi_push_desc(ehi, "CPB error");
+                       ata_ehi_push_desc(ehi, "CPB error");
                        ehi->err_mask |= AC_ERR_SYSTEM;
                        freeze = 1;
                } else {
                        /* notifier error, but no error in CPB flags? */
+                       ata_ehi_push_desc(ehi, "unknown");
                        ehi->err_mask |= AC_ERR_OTHER;
                        freeze = 1;
                }
@@ -727,20 +876,24 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
                return 1;
        }
 
-       if (flags & NV_CPB_RESP_DONE) {
+       if (likely(flags & NV_CPB_RESP_DONE)) {
                struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
                VPRINTK("CPB flags done, flags=0x%x\n", flags);
                if (likely(qc)) {
-                       /* Grab the ATA port status for non-NCQ commands.
-                          For NCQ commands the current status may have nothing to do with
-                          the command just completed. */
-                       if (qc->tf.protocol != ATA_PROT_NCQ) {
-                               u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
-                               qc->err_mask |= ac_err_mask(ata_status);
-                       }
-                       DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num,
-                               qc->err_mask);
+                       DPRINTK("Completing qc from tag %d\n", cpb_num);
                        ata_qc_complete(qc);
+               } else {
+                       struct ata_eh_info *ehi = &ap->link.eh_info;
+                       /* Notifier bits set without a command may indicate the drive
+                          is misbehaving. Raise host state machine violation on this
+                          condition. */
+                       ata_port_printk(ap, KERN_ERR,
+                                       "notifier for tag %d with no cmd?\n",
+                                       cpb_num);
+                       ehi->err_mask |= AC_ERR_HSM;
+                       ehi->action |= ATA_EH_RESET;
+                       ata_port_freeze(ap);
+                       return 1;
                }
        }
        return 0;
@@ -748,7 +901,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
 
 static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
 {
-       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
 
        /* freeze if hotplugged */
        if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
@@ -762,12 +915,12 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
 
        /* DEV interrupt w/ no active qc? */
        if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
-               ata_check_status(ap);
+               ata_sff_check_status(ap);
                return 1;
        }
 
        /* handle interrupt */
-       return ata_host_intr(ap, qc);
+       return ata_sff_host_intr(ap, qc);
 }
 
 static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
@@ -780,96 +933,113 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
 
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
+               struct nv_adma_port_priv *pp = ap->private_data;
+               void __iomem *mmio = pp->ctl_block;
+               u16 status;
+               u32 gen_ctl;
+               u32 notifier, notifier_error;
+
                notifier_clears[i] = 0;
 
-               if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
-                       struct nv_adma_port_priv *pp = ap->private_data;
-                       void __iomem *mmio = pp->ctl_block;
-                       u16 status;
-                       u32 gen_ctl;
-                       u32 notifier, notifier_error;
-
-                       /* if in ATA register mode, use standard ata interrupt handler */
-                       if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
-                               u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
-                                       >> (NV_INT_PORT_SHIFT * i);
-                               if(ata_tag_valid(ap->active_tag))
-                                       /** NV_INT_DEV indication seems unreliable at times
-                                           at least in ADMA mode. Force it on always when a
-                                           command is active, to prevent losing interrupts. */
-                                       irq_stat |= NV_INT_DEV;
-                               handled += nv_host_intr(ap, irq_stat);
-                               continue;
-                       }
+               /* if ADMA is disabled, use standard ata interrupt handler */
+               if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
+                       u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
+                               >> (NV_INT_PORT_SHIFT * i);
+                       handled += nv_host_intr(ap, irq_stat);
+                       continue;
+               }
 
-                       notifier = readl(mmio + NV_ADMA_NOTIFIER);
-                       notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
-                       notifier_clears[i] = notifier | notifier_error;
-
-                       gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
-
-                       if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
-                           !notifier_error)
-                               /* Nothing to do */
-                               continue;
-
-                       status = readw(mmio + NV_ADMA_STAT);
-
-                       /* Clear status. Ensure the controller sees the clearing before we start
-                          looking at any of the CPB statuses, so that any CPB completions after
-                          this point in the handler will raise another interrupt. */
-                       writew(status, mmio + NV_ADMA_STAT);
-                       readw(mmio + NV_ADMA_STAT); /* flush posted write */
-                       rmb();
-
-                       handled++; /* irq handled if we got here */
-
-                       /* freeze if hotplugged or controller error */
-                       if (unlikely(status & (NV_ADMA_STAT_HOTPLUG |
-                                              NV_ADMA_STAT_HOTUNPLUG |
-                                              NV_ADMA_STAT_TIMEOUT))) {
-                               struct ata_eh_info *ehi = &ap->eh_info;
-
-                               ata_ehi_clear_desc(ehi);
-                               ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
-                               if (status & NV_ADMA_STAT_TIMEOUT) {
-                                       ehi->err_mask |= AC_ERR_SYSTEM;
-                                       ata_ehi_push_desc(ehi, ": timeout");
-                               } else if (status & NV_ADMA_STAT_HOTPLUG) {
-                                       ata_ehi_hotplugged(ehi);
-                                       ata_ehi_push_desc(ehi, ": hotplug");
-                               } else if (status & NV_ADMA_STAT_HOTUNPLUG) {
-                                       ata_ehi_hotplugged(ehi);
-                                       ata_ehi_push_desc(ehi, ": hot unplug");
-                               }
-                               ata_port_freeze(ap);
-                               continue;
+               /* if in ATA register mode, check for standard interrupts */
+               if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
+                       u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
+                               >> (NV_INT_PORT_SHIFT * i);
+                       if (ata_tag_valid(ap->link.active_tag))
+                               /** NV_INT_DEV indication seems unreliable
+                                   at times at least in ADMA mode. Force it
+                                   on always when a command is active, to
+                                   prevent losing interrupts. */
+                               irq_stat |= NV_INT_DEV;
+                       handled += nv_host_intr(ap, irq_stat);
+               }
+
+               notifier = readl(mmio + NV_ADMA_NOTIFIER);
+               notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
+               notifier_clears[i] = notifier | notifier_error;
+
+               gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
+
+               if (!NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
+                   !notifier_error)
+                       /* Nothing to do */
+                       continue;
+
+               status = readw(mmio + NV_ADMA_STAT);
+
+               /*
+                * Clear status. Ensure the controller sees the
+                * clearing before we start looking at any of the CPB
+                * statuses, so that any CPB completions after this
+                * point in the handler will raise another interrupt.
+                */
+               writew(status, mmio + NV_ADMA_STAT);
+               readw(mmio + NV_ADMA_STAT); /* flush posted write */
+               rmb();
+
+               handled++; /* irq handled if we got here */
+
+               /* freeze if hotplugged or controller error */
+               if (unlikely(status & (NV_ADMA_STAT_HOTPLUG |
+                                      NV_ADMA_STAT_HOTUNPLUG |
+                                      NV_ADMA_STAT_TIMEOUT |
+                                      NV_ADMA_STAT_SERROR))) {
+                       struct ata_eh_info *ehi = &ap->link.eh_info;
+
+                       ata_ehi_clear_desc(ehi);
+                       __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status);
+                       if (status & NV_ADMA_STAT_TIMEOUT) {
+                               ehi->err_mask |= AC_ERR_SYSTEM;
+                               ata_ehi_push_desc(ehi, "timeout");
+                       } else if (status & NV_ADMA_STAT_HOTPLUG) {
+                               ata_ehi_hotplugged(ehi);
+                               ata_ehi_push_desc(ehi, "hotplug");
+                       } else if (status & NV_ADMA_STAT_HOTUNPLUG) {
+                               ata_ehi_hotplugged(ehi);
+                               ata_ehi_push_desc(ehi, "hot unplug");
+                       } else if (status & NV_ADMA_STAT_SERROR) {
+                               /* let EH analyze SError and figure out cause */
+                               ata_ehi_push_desc(ehi, "SError");
+                       } else
+                               ata_ehi_push_desc(ehi, "unknown");
+                       ata_port_freeze(ap);
+                       continue;
+               }
+
+               if (status & (NV_ADMA_STAT_DONE |
+                             NV_ADMA_STAT_CPBERR |
+                             NV_ADMA_STAT_CMD_COMPLETE)) {
+                       u32 check_commands = notifier_clears[i];
+                       int pos, error = 0;
+
+                       if (status & NV_ADMA_STAT_CPBERR) {
+                               /* check all active commands */
+                               if (ata_tag_valid(ap->link.active_tag))
+                                       check_commands = 1 <<
+                                               ap->link.active_tag;
+                               else
+                                       check_commands = ap->link.sactive;
                        }
 
-                       if (status & (NV_ADMA_STAT_DONE |
-                                     NV_ADMA_STAT_CPBERR)) {
-                               /** Check CPBs for completed commands */
-
-                               if (ata_tag_valid(ap->active_tag)) {
-                                       /* Non-NCQ command */
-                                       nv_adma_check_cpb(ap, ap->active_tag,
-                                               notifier_error & (1 << ap->active_tag));
-                               } else {
-                                       int pos, error = 0;
-                                       u32 active = ap->sactive;
-
-                                       while ((pos = ffs(active)) && !error) {
-                                               pos--;
-                                               error = nv_adma_check_cpb(ap, pos,
-                                                       notifier_error & (1 << pos) );
-                                               active &= ~(1 << pos );
-                                       }
-                               }
+                       /* check CPBs for completed commands */
+                       while ((pos = ffs(check_commands)) && !error) {
+                               pos--;
+                               error = nv_adma_check_cpb(ap, pos,
+                                               notifier_error & (1 << pos));
+                               check_commands &= ~(1 << pos);
                        }
                }
        }
 
-       if(notifier_clears[0] || notifier_clears[1]) {
+       if (notifier_clears[0] || notifier_clears[1]) {
                /* Note: Both notifier clear registers must be written
                   if either is set, even if one is zero, according to NVIDIA. */
                struct nv_adma_port_priv *pp = host->ports[0]->private_data;
@@ -883,91 +1053,85 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
        return IRQ_RETVAL(handled);
 }
 
-static void nv_adma_irq_clear(struct ata_port *ap)
+static void nv_adma_freeze(struct ata_port *ap)
 {
        struct nv_adma_port_priv *pp = ap->private_data;
        void __iomem *mmio = pp->ctl_block;
-       u16 status = readw(mmio + NV_ADMA_STAT);
-       u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
-       u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
-       void __iomem *dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
-
-       /* clear ADMA status */
-       writew(status, mmio + NV_ADMA_STAT);
-       writel(notifier | notifier_error,
-              pp->notifier_clear_block);
-
-       /** clear legacy status */
-       iowrite8(ioread8(dma_stat_addr), dma_stat_addr);
-}
+       u16 tmp;
 
-static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc)
-{
-       struct ata_port *ap = qc->ap;
-       unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
-       struct nv_adma_port_priv *pp = ap->private_data;
-       u8 dmactl;
+       nv_ck804_freeze(ap);
 
-       if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
-               WARN_ON(1);
+       if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
                return;
-       }
-
-       /* load PRD table addr. */
-       iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
-
-       /* specify data direction, triple-check start bit is clear */
-       dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-       dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
-       if (!rw)
-               dmactl |= ATA_DMA_WR;
 
-       iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+       /* clear any outstanding CK804 notifications */
+       writeb(NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
+               ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
 
-       /* issue r/w command */
-       ata_exec_command(ap, &qc->tf);
+       /* Disable interrupt */
+       tmp = readw(mmio + NV_ADMA_CTL);
+       writew(tmp & ~(NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
+               mmio + NV_ADMA_CTL);
+       readw(mmio + NV_ADMA_CTL);      /* flush posted write */
 }
 
-static void nv_adma_bmdma_start(struct ata_queued_cmd *qc)
+static void nv_adma_thaw(struct ata_port *ap)
 {
-       struct ata_port *ap = qc->ap;
        struct nv_adma_port_priv *pp = ap->private_data;
-       u8 dmactl;
+       void __iomem *mmio = pp->ctl_block;
+       u16 tmp;
+
+       nv_ck804_thaw(ap);
 
-       if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
-               WARN_ON(1);
+       if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
                return;
-       }
 
-       /* start host DMA transaction */
-       dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-       iowrite8(dmactl | ATA_DMA_START,
-                ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+       /* Enable interrupt */
+       tmp = readw(mmio + NV_ADMA_CTL);
+       writew(tmp | (NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
+               mmio + NV_ADMA_CTL);
+       readw(mmio + NV_ADMA_CTL);      /* flush posted write */
 }
 
-static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc)
+static void nv_adma_irq_clear(struct ata_port *ap)
 {
-       struct ata_port *ap = qc->ap;
        struct nv_adma_port_priv *pp = ap->private_data;
+       void __iomem *mmio = pp->ctl_block;
+       u32 notifier_clears[2];
 
-       if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE))
+       if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
+               ata_sff_irq_clear(ap);
                return;
+       }
 
-       /* clear start/stop bit */
-       iowrite8(ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
-                ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+       /* clear any outstanding CK804 notifications */
+       writeb(NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
+               ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
 
-       /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
-       ata_altstatus(ap);        /* dummy read */
+       /* clear ADMA status */
+       writew(0xffff, mmio + NV_ADMA_STAT);
+
+       /* clear notifiers - note both ports need to be written with
+          something even though we are only clearing on one */
+       if (ap->port_no == 0) {
+               notifier_clears[0] = 0xFFFFFFFF;
+               notifier_clears[1] = 0;
+       } else {
+               notifier_clears[0] = 0;
+               notifier_clears[1] = 0xFFFFFFFF;
+       }
+       pp = ap->host->ports[0]->private_data;
+       writel(notifier_clears[0], pp->notifier_clear_block);
+       pp = ap->host->ports[1]->private_data;
+       writel(notifier_clears[1], pp->notifier_clear_block);
 }
 
-static u8 nv_adma_bmdma_status(struct ata_port *ap)
+static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc)
 {
-       struct nv_adma_port_priv *pp = ap->private_data;
-
-       WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE));
+       struct nv_adma_port_priv *pp = qc->ap->private_data;
 
-       return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+       if (pp->flags & NV_ADMA_PORT_REGISTER_MODE)
+               ata_bmdma_post_internal_cmd(qc);
 }
 
 static int nv_adma_port_start(struct ata_port *ap)
@@ -978,11 +1142,22 @@ static int nv_adma_port_start(struct ata_port *ap)
        void *mem;
        dma_addr_t mem_dma;
        void __iomem *mmio;
+       struct pci_dev *pdev = to_pci_dev(dev);
        u16 tmp;
 
        VPRINTK("ENTER\n");
 
-       rc = ata_port_start(ap);
+       /* Ensure DMA mask is set to 32-bit before allocating legacy PRD and
+          pad buffers */
+       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (rc)
+               return rc;
+       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (rc)
+               return rc;
+
+       /* we might fallback to bmdma, allocate bmdma resources */
+       rc = ata_bmdma_port_start(ap);
        if (rc)
                return rc;
 
@@ -997,6 +1172,15 @@ static int nv_adma_port_start(struct ata_port *ap)
        pp->notifier_clear_block = pp->gen_block +
               NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no);
 
+       /* Now that the legacy PRD and padding buffer are allocated we can
+          safely raise the DMA mask to allocate the CPB/APRD table.
+          These are allowed to fail since we store the value that ends up
+          being used to set as the bounce limit in slave_config later if
+          needed. */
+       pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+       pp->adma_dma_mask = *dev->dma_mask;
+
        mem = dmam_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
                                  &mem_dma, GFP_KERNEL);
        if (!mem)
@@ -1012,7 +1196,7 @@ static int nv_adma_port_start(struct ata_port *ap)
        pp->cpb_dma = mem_dma;
 
        writel(mem_dma & 0xFFFFFFFF,    mmio + NV_ADMA_CPB_BASE_LOW);
-       writel((mem_dma >> 16 ) >> 16,  mmio + NV_ADMA_CPB_BASE_HIGH);
+       writel((mem_dma >> 16) >> 16,   mmio + NV_ADMA_CPB_BASE_HIGH);
 
        mem     += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ;
        mem_dma += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ;
@@ -1036,14 +1220,15 @@ static int nv_adma_port_start(struct ata_port *ap)
 
        /* clear GO for register mode, enable interrupt */
        tmp = readw(mmio + NV_ADMA_CTL);
-       writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
+       writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN |
+               NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
 
        tmp = readw(mmio + NV_ADMA_CTL);
        writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
-       readl( mmio + NV_ADMA_CTL );    /* flush posted write */
+       readw(mmio + NV_ADMA_CTL);      /* flush posted write */
        udelay(1);
        writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
-       readl( mmio + NV_ADMA_CTL );    /* flush posted write */
+       readw(mmio + NV_ADMA_CTL);      /* flush posted write */
 
        return 0;
 }
@@ -1057,6 +1242,7 @@ static void nv_adma_port_stop(struct ata_port *ap)
        writew(0, mmio + NV_ADMA_CTL);
 }
 
+#ifdef CONFIG_PM
 static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg)
 {
        struct nv_adma_port_priv *pp = ap->private_data;
@@ -1082,7 +1268,7 @@ static int nv_adma_port_resume(struct ata_port *ap)
 
        /* set CPB block location */
        writel(pp->cpb_dma & 0xFFFFFFFF,        mmio + NV_ADMA_CPB_BASE_LOW);
-       writel((pp->cpb_dma >> 16 ) >> 16,      mmio + NV_ADMA_CPB_BASE_HIGH);
+       writel((pp->cpb_dma >> 16) >> 16,       mmio + NV_ADMA_CPB_BASE_HIGH);
 
        /* clear any outstanding interrupt conditions */
        writew(0xffff, mmio + NV_ADMA_STAT);
@@ -1095,26 +1281,28 @@ static int nv_adma_port_resume(struct ata_port *ap)
 
        /* clear GO for register mode, enable interrupt */
        tmp = readw(mmio + NV_ADMA_CTL);
-       writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
+       writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN |
+               NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
 
        tmp = readw(mmio + NV_ADMA_CTL);
        writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
-       readl( mmio + NV_ADMA_CTL );    /* flush posted write */
+       readw(mmio + NV_ADMA_CTL);      /* flush posted write */
        udelay(1);
        writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
-       readl( mmio + NV_ADMA_CTL );    /* flush posted write */
+       readw(mmio + NV_ADMA_CTL);      /* flush posted write */
 
        return 0;
 }
+#endif
 
-static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
+static void nv_adma_setup_port(struct ata_port *ap)
 {
-       void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR];
-       struct ata_ioports *ioport = &probe_ent->port[port];
+       void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+       struct ata_ioports *ioport = &ap->ioaddr;
 
        VPRINTK("ENTER\n");
 
-       mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;
+       mmio += NV_ADMA_PORT + ap->port_no * NV_ADMA_PORT_SIZE;
 
        ioport->cmd_addr        = mmio;
        ioport->data_addr       = mmio + (ATA_REG_DATA * 4);
@@ -1131,9 +1319,9 @@ static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int por
        ioport->ctl_addr        = mmio + 0x20;
 }
 
-static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
+static int nv_adma_host_init(struct ata_host *host)
 {
-       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+       struct pci_dev *pdev = to_pci_dev(host->dev);
        unsigned int i;
        u32 tmp32;
 
@@ -1148,8 +1336,8 @@ static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
 
        pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
 
-       for (i = 0; i < probe_ent->n_ports; i++)
-               nv_adma_setup_port(probe_ent, i);
+       for (i = 0; i < host->n_ports; i++)
+               nv_adma_setup_port(host->ports[i]);
 
        return 0;
 }
@@ -1159,11 +1347,7 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
                              int idx,
                              struct nv_adma_prd *aprd)
 {
-       u8 flags;
-
-       memset(aprd, 0, sizeof(struct nv_adma_prd));
-
-       flags = 0;
+       u8 flags = 0;
        if (qc->tf.flags & ATA_TFLAG_WRITE)
                flags |= NV_APRD_WRITE;
        if (idx == qc->n_elem - 1)
@@ -1174,26 +1358,27 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
        aprd->addr  = cpu_to_le64(((u64)sg_dma_address(sg)));
        aprd->len   = cpu_to_le32(((u32)sg_dma_len(sg))); /* len in bytes */
        aprd->flags = flags;
+       aprd->packet_len = 0;
 }
 
 static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
 {
        struct nv_adma_port_priv *pp = qc->ap->private_data;
-       unsigned int idx;
        struct nv_adma_prd *aprd;
        struct scatterlist *sg;
+       unsigned int si;
 
        VPRINTK("ENTER\n");
 
-       idx = 0;
-
-       ata_for_each_sg(sg, qc) {
-               aprd = (idx < 5) ? &cpb->aprd[idx] : &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)];
-               nv_adma_fill_aprd(qc, sg, idx, aprd);
-               idx++;
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
+               aprd = (si < 5) ? &cpb->aprd[si] :
+                              &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (si-5)];
+               nv_adma_fill_aprd(qc, sg, si, aprd);
        }
-       if (idx > 5)
+       if (si > 5)
                cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
+       else
+               cpb->next_aprd = cpu_to_le64(0);
 }
 
 static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
@@ -1202,11 +1387,11 @@ static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
 
        /* ADMA engine can only be used for non-ATAPI DMA commands,
           or interrupt-driven no-data commands. */
-       if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
+       if ((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
           (qc->tf.flags & ATA_TFLAG_POLLING))
                return 1;
 
-       if((qc->flags & ATA_QCFLAG_DMAMAP) ||
+       if ((qc->flags & ATA_QCFLAG_DMAMAP) ||
           (qc->tf.protocol == ATA_PROT_NODATA))
                return 0;
 
@@ -1221,12 +1406,17 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
                       NV_CPB_CTL_IEN;
 
        if (nv_adma_use_reg_mode(qc)) {
+               BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) &&
+                       (qc->flags & ATA_QCFLAG_DMAMAP));
                nv_adma_register_mode(qc->ap);
-               ata_qc_prep(qc);
+               ata_bmdma_qc_prep(qc);
                return;
        }
 
-       memset(cpb, 0, sizeof(struct nv_adma_cpb));
+       cpb->resp_flags = NV_CPB_RESP_DONE;
+       wmb();
+       cpb->ctl_flags = 0;
+       wmb();
 
        cpb->len                = 3;
        cpb->tag                = qc->tag;
@@ -1240,39 +1430,62 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
 
        nv_adma_tf_to_cpb(&qc->tf, cpb->tf);
 
-       if(qc->flags & ATA_QCFLAG_DMAMAP) {
+       if (qc->flags & ATA_QCFLAG_DMAMAP) {
                nv_adma_fill_sg(qc, cpb);
                ctl_flags |= NV_CPB_CTL_APRD_VALID;
        } else
                memset(&cpb->aprd[0], 0, sizeof(struct nv_adma_prd) * 5);
 
-       /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are
-          finished filling in all of the contents */
+       /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID
+          until we are finished filling in all of the contents */
        wmb();
        cpb->ctl_flags = ctl_flags;
+       wmb();
+       cpb->resp_flags = 0;
 }
 
 static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
 {
        struct nv_adma_port_priv *pp = qc->ap->private_data;
        void __iomem *mmio = pp->ctl_block;
+       int curr_ncq = (qc->tf.protocol == ATA_PROT_NCQ);
 
        VPRINTK("ENTER\n");
 
+       /* We can't handle result taskfile with NCQ commands, since
+          retrieving the taskfile switches us out of ADMA mode and would abort
+          existing commands. */
+       if (unlikely(qc->tf.protocol == ATA_PROT_NCQ &&
+                    (qc->flags & ATA_QCFLAG_RESULT_TF))) {
+               ata_dev_printk(qc->dev, KERN_ERR,
+                       "NCQ w/ RESULT_TF not allowed\n");
+               return AC_ERR_SYSTEM;
+       }
+
        if (nv_adma_use_reg_mode(qc)) {
                /* use ATA register mode */
                VPRINTK("using ATA register mode: 0x%lx\n", qc->flags);
+               BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) &&
+                       (qc->flags & ATA_QCFLAG_DMAMAP));
                nv_adma_register_mode(qc->ap);
-               return ata_qc_issue_prot(qc);
+               return ata_bmdma_qc_issue(qc);
        } else
                nv_adma_mode(qc->ap);
 
        /* write append register, command tag in lower 8 bits
           and (number of cpbs to append -1) in top 8 bits */
        wmb();
+
+       if (curr_ncq != pp->last_issue_ncq) {
+               /* Seems to need some delay before switching between NCQ and
+                  non-NCQ commands, else we get command timeouts and such. */
+               udelay(20);
+               pp->last_issue_ncq = curr_ncq;
+       }
+
        writew(qc->tag, mmio + NV_ADMA_APPEND);
 
-       DPRINTK("Issued tag %u\n",qc->tag);
+       DPRINTK("Issued tag %u\n", qc->tag);
 
        return 0;
 }
@@ -1287,22 +1500,19 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
        spin_lock_irqsave(&host->lock, flags);
 
        for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap;
-
-               ap = host->ports[i];
-               if (ap &&
-                   !(ap->flags & ATA_FLAG_DISABLED)) {
-                       struct ata_queued_cmd *qc;
+               struct ata_port *ap = host->ports[i];
+               struct ata_queued_cmd *qc;
 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
-                       if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
-                               handled += ata_host_intr(ap, qc);
-                       else
-                               // No request pending?  Clear interrupt status
-                               // anyway, in case there's one pending.
-                               ap->ops->check_status(ap);
+               qc = ata_qc_from_tag(ap, ap->link.active_tag);
+               if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+                       handled += ata_sff_host_intr(ap, qc);
+               } else {
+                       /*
+                        * No request pending?  Clear interrupt status
+                        * anyway, in case there's one pending.
+                        */
+                       ap->ops->sff_check_status(ap);
                }
-
        }
 
        spin_unlock_irqrestore(&host->lock, flags);
@@ -1315,11 +1525,7 @@ static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat)
        int i, handled = 0;
 
        for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap = host->ports[i];
-
-               if (ap && !(ap->flags & ATA_FLAG_DISABLED))
-                       handled += nv_host_intr(ap, irq_stat);
-
+               handled += nv_host_intr(host->ports[i], irq_stat);
                irq_stat >>= NV_INT_PORT_SHIFT;
        }
 
@@ -1354,20 +1560,54 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
        return ret;
 }
 
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
+               return -EINVAL;
 
-       return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+       *val = ioread32(link->ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
+
+       iowrite32(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
+}
+
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
+                       unsigned long deadline)
+{
+       struct ata_eh_context *ehc = &link->eh_context;
 
-       iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       /* Do hardreset iff it's post-boot probing, please read the
+        * comment above port ops for details.
+        */
+       if (!(link->ap->pflags & ATA_PFLAG_LOADING) &&
+           !ata_dev_enabled(link->device))
+               sata_link_hardreset(link, sata_deb_timing_hotplug, deadline,
+                                   NULL, NULL);
+       else {
+               const unsigned long *timing = sata_ehc_deb_timing(ehc);
+               int rc;
+
+               if (!(ehc->i.flags & ATA_EHI_QUIET))
+                       ata_link_printk(link, KERN_INFO, "nv: skipping "
+                                       "hardreset on occupied port\n");
+
+               /* make sure the link is online */
+               rc = sata_link_resume(link, timing, deadline);
+               /* whine about phy resume failure but proceed */
+               if (rc && rc != -EOPNOTSUPP)
+                       ata_link_printk(link, KERN_WARNING, "failed to resume "
+                                       "link (errno=%d)\n", rc);
+       }
+
+       /* device signature acquisition is unreliable */
+       return -EAGAIN;
 }
 
 static void nv_nf2_freeze(struct ata_port *ap)
@@ -1418,36 +1658,73 @@ static void nv_ck804_thaw(struct ata_port *ap)
        writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
 }
 
-static int nv_hardreset(struct ata_port *ap, unsigned int *class)
+static void nv_mcp55_freeze(struct ata_port *ap)
 {
-       unsigned int dummy;
+       void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
+       int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55;
+       u32 mask;
 
-       /* SATA hardreset fails to retrieve proper device signature on
-        * some controllers.  Don't classify on hardreset.  For more
-        * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
-        */
-       return sata_std_hardreset(ap, &dummy);
+       writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55);
+
+       mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
+       mask &= ~(NV_INT_ALL_MCP55 << shift);
+       writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
+       ata_sff_freeze(ap);
 }
 
-static void nv_error_handler(struct ata_port *ap)
+static void nv_mcp55_thaw(struct ata_port *ap)
 {
-       ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
-                          nv_hardreset, ata_std_postreset);
+       void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
+       int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55;
+       u32 mask;
+
+       writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55);
+
+       mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
+       mask |= (NV_INT_MASK_MCP55 << shift);
+       writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
+       ata_sff_thaw(ap);
 }
 
 static void nv_adma_error_handler(struct ata_port *ap)
 {
        struct nv_adma_port_priv *pp = ap->private_data;
-       if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
+       if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
                void __iomem *mmio = pp->ctl_block;
                int i;
                u16 tmp;
 
+               if (ata_tag_valid(ap->link.active_tag) || ap->link.sactive) {
+                       u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
+                       u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
+                       u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
+                       u32 status = readw(mmio + NV_ADMA_STAT);
+                       u8 cpb_count = readb(mmio + NV_ADMA_CPB_COUNT);
+                       u8 next_cpb_idx = readb(mmio + NV_ADMA_NEXT_CPB_IDX);
+
+                       ata_port_printk(ap, KERN_ERR,
+                               "EH in ADMA mode, notifier 0x%X "
+                               "notifier_error 0x%X gen_ctl 0x%X status 0x%X "
+                               "next cpb count 0x%X next cpb idx 0x%x\n",
+                               notifier, notifier_error, gen_ctl, status,
+                               cpb_count, next_cpb_idx);
+
+                       for (i = 0; i < NV_ADMA_MAX_CPBS; i++) {
+                               struct nv_adma_cpb *cpb = &pp->cpb[i];
+                               if ((ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) ||
+                                   ap->link.sactive & (1 << i))
+                                       ata_port_printk(ap, KERN_ERR,
+                                               "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
+                                               i, cpb->ctl_flags, cpb->resp_flags);
+                       }
+               }
+
                /* Push us back into port register mode for error handling. */
                nv_adma_register_mode(ap);
 
-               /* Mark all of the CPBs as invalid to prevent them from being executed */
-               for( i=0;i<NV_ADMA_MAX_CPBS;i++)
+               /* Mark all of the CPBs as invalid to prevent them from
+                  being executed */
+               for (i = 0; i < NV_ADMA_MAX_CPBS; i++)
                        pp->cpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID;
 
                /* clear CPB fetch count */
@@ -1456,32 +1733,682 @@ static void nv_adma_error_handler(struct ata_port *ap)
                /* Reset channel */
                tmp = readw(mmio + NV_ADMA_CTL);
                writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
-               readl( mmio + NV_ADMA_CTL );    /* flush posted write */
+               readw(mmio + NV_ADMA_CTL);      /* flush posted write */
                udelay(1);
                writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
-               readl( mmio + NV_ADMA_CTL );    /* flush posted write */
+               readw(mmio + NV_ADMA_CTL);      /* flush posted write */
+       }
+
+       ata_bmdma_error_handler(ap);
+}
+
+static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct defer_queue *dq = &pp->defer_queue;
+
+       /* queue is full */
+       WARN_ON(dq->tail - dq->head == ATA_MAX_QUEUE);
+       dq->defer_bits |= (1 << qc->tag);
+       dq->tag[dq->tail++ & (ATA_MAX_QUEUE - 1)] = qc->tag;
+}
+
+static struct ata_queued_cmd *nv_swncq_qc_from_dq(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct defer_queue *dq = &pp->defer_queue;
+       unsigned int tag;
+
+       if (dq->head == dq->tail)       /* null queue */
+               return NULL;
+
+       tag = dq->tag[dq->head & (ATA_MAX_QUEUE - 1)];
+       dq->tag[dq->head++ & (ATA_MAX_QUEUE - 1)] = ATA_TAG_POISON;
+       WARN_ON(!(dq->defer_bits & (1 << tag)));
+       dq->defer_bits &= ~(1 << tag);
+
+       return ata_qc_from_tag(ap, tag);
+}
+
+static void nv_swncq_fis_reinit(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       pp->dhfis_bits = 0;
+       pp->dmafis_bits = 0;
+       pp->sdbfis_bits = 0;
+       pp->ncq_flags = 0;
+}
+
+static void nv_swncq_pp_reinit(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct defer_queue *dq = &pp->defer_queue;
+
+       dq->head = 0;
+       dq->tail = 0;
+       dq->defer_bits = 0;
+       pp->qc_active = 0;
+       pp->last_issue_tag = ATA_TAG_POISON;
+       nv_swncq_fis_reinit(ap);
+}
+
+static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       writew(fis, pp->irq_block);
+}
+
+static void __ata_bmdma_stop(struct ata_port *ap)
+{
+       struct ata_queued_cmd qc;
+
+       qc.ap = ap;
+       ata_bmdma_stop(&qc);
+}
+
+static void nv_swncq_ncq_stop(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       unsigned int i;
+       u32 sactive;
+       u32 done_mask;
+
+       ata_port_printk(ap, KERN_ERR,
+                       "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n",
+                       ap->qc_active, ap->link.sactive);
+       ata_port_printk(ap, KERN_ERR,
+               "SWNCQ:qc_active 0x%X defer_bits 0x%X last_issue_tag 0x%x\n  "
+               "dhfis 0x%X dmafis 0x%X sdbfis 0x%X\n",
+               pp->qc_active, pp->defer_queue.defer_bits, pp->last_issue_tag,
+               pp->dhfis_bits, pp->dmafis_bits, pp->sdbfis_bits);
+
+       ata_port_printk(ap, KERN_ERR, "ATA_REG 0x%X ERR_REG 0x%X\n",
+                       ap->ops->sff_check_status(ap),
+                       ioread8(ap->ioaddr.error_addr));
+
+       sactive = readl(pp->sactive_block);
+       done_mask = pp->qc_active ^ sactive;
+
+       ata_port_printk(ap, KERN_ERR, "tag : dhfis dmafis sdbfis sacitve\n");
+       for (i = 0; i < ATA_MAX_QUEUE; i++) {
+               u8 err = 0;
+               if (pp->qc_active & (1 << i))
+                       err = 0;
+               else if (done_mask & (1 << i))
+                       err = 1;
+               else
+                       continue;
+
+               ata_port_printk(ap, KERN_ERR,
+                               "tag 0x%x: %01x %01x %01x %01x %s\n", i,
+                               (pp->dhfis_bits >> i) & 0x1,
+                               (pp->dmafis_bits >> i) & 0x1,
+                               (pp->sdbfis_bits >> i) & 0x1,
+                               (sactive >> i) & 0x1,
+                               (err ? "error! tag doesn't exit" : " "));
+       }
+
+       nv_swncq_pp_reinit(ap);
+       ap->ops->sff_irq_clear(ap);
+       __ata_bmdma_stop(ap);
+       nv_swncq_irq_clear(ap, 0xffff);
+}
+
+static void nv_swncq_error_handler(struct ata_port *ap)
+{
+       struct ata_eh_context *ehc = &ap->link.eh_context;
+
+       if (ap->link.sactive) {
+               nv_swncq_ncq_stop(ap);
+               ehc->i.action |= ATA_EH_RESET;
+       }
+
+       ata_bmdma_error_handler(ap);
+}
+
+#ifdef CONFIG_PM
+static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+       void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+       u32 tmp;
+
+       /* clear irq */
+       writel(~0, mmio + NV_INT_STATUS_MCP55);
+
+       /* disable irq */
+       writel(0, mmio + NV_INT_ENABLE_MCP55);
+
+       /* disable swncq */
+       tmp = readl(mmio + NV_CTL_MCP55);
+       tmp &= ~(NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ);
+       writel(tmp, mmio + NV_CTL_MCP55);
+
+       return 0;
+}
+
+static int nv_swncq_port_resume(struct ata_port *ap)
+{
+       void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+       u32 tmp;
+
+       /* clear irq */
+       writel(~0, mmio + NV_INT_STATUS_MCP55);
+
+       /* enable irq */
+       writel(0x00fd00fd, mmio + NV_INT_ENABLE_MCP55);
+
+       /* enable swncq */
+       tmp = readl(mmio + NV_CTL_MCP55);
+       writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55);
+
+       return 0;
+}
+#endif
+
+static void nv_swncq_host_init(struct ata_host *host)
+{
+       u32 tmp;
+       void __iomem *mmio = host->iomap[NV_MMIO_BAR];
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       u8 regval;
+
+       /* disable  ECO 398 */
+       pci_read_config_byte(pdev, 0x7f, &regval);
+       regval &= ~(1 << 7);
+       pci_write_config_byte(pdev, 0x7f, regval);
+
+       /* enable swncq */
+       tmp = readl(mmio + NV_CTL_MCP55);
+       VPRINTK("HOST_CTL:0x%X\n", tmp);
+       writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55);
+
+       /* enable irq intr */
+       tmp = readl(mmio + NV_INT_ENABLE_MCP55);
+       VPRINTK("HOST_ENABLE:0x%X\n", tmp);
+       writel(tmp | 0x00fd00fd, mmio + NV_INT_ENABLE_MCP55);
+
+       /*  clear port irq */
+       writel(~0x0, mmio + NV_INT_STATUS_MCP55);
+}
+
+static int nv_swncq_slave_config(struct scsi_device *sdev)
+{
+       struct ata_port *ap = ata_shost_to_port(sdev->host);
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       struct ata_device *dev;
+       int rc;
+       u8 rev;
+       u8 check_maxtor = 0;
+       unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+       rc = ata_scsi_slave_config(sdev);
+       if (sdev->id >= ATA_MAX_DEVICES || sdev->channel || sdev->lun)
+               /* Not a proper libata device, ignore */
+               return rc;
+
+       dev = &ap->link.device[sdev->id];
+       if (!(ap->flags & ATA_FLAG_NCQ) || dev->class == ATA_DEV_ATAPI)
+               return rc;
+
+       /* if MCP51 and Maxtor, then disable ncq */
+       if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA ||
+               pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2)
+               check_maxtor = 1;
+
+       /* if MCP55 and rev <= a2 and Maxtor, then disable ncq */
+       if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA ||
+               pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2) {
+               pci_read_config_byte(pdev, 0x8, &rev);
+               if (rev <= 0xa2)
+                       check_maxtor = 1;
+       }
+
+       if (!check_maxtor)
+               return rc;
+
+       ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+
+       if (strncmp(model_num, "Maxtor", 6) == 0) {
+               ata_scsi_change_queue_depth(sdev, 1, SCSI_QDEPTH_DEFAULT);
+               ata_dev_printk(dev, KERN_NOTICE,
+                       "Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth);
+       }
+
+       return rc;
+}
+
+static int nv_swncq_port_start(struct ata_port *ap)
+{
+       struct device *dev = ap->host->dev;
+       void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+       struct nv_swncq_port_priv *pp;
+       int rc;
+
+       /* we might fallback to bmdma, allocate bmdma resources */
+       rc = ata_bmdma_port_start(ap);
+       if (rc)
+               return rc;
+
+       pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+       if (!pp)
+               return -ENOMEM;
+
+       pp->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE,
+                                     &pp->prd_dma, GFP_KERNEL);
+       if (!pp->prd)
+               return -ENOMEM;
+       memset(pp->prd, 0, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE);
+
+       ap->private_data = pp;
+       pp->sactive_block = ap->ioaddr.scr_addr + 4 * SCR_ACTIVE;
+       pp->irq_block = mmio + NV_INT_STATUS_MCP55 + ap->port_no * 2;
+       pp->tag_block = mmio + NV_NCQ_REG_MCP55 + ap->port_no * 2;
+
+       return 0;
+}
+
+static void nv_swncq_qc_prep(struct ata_queued_cmd *qc)
+{
+       if (qc->tf.protocol != ATA_PROT_NCQ) {
+               ata_bmdma_qc_prep(qc);
+               return;
+       }
+
+       if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+               return;
+
+       nv_swncq_fill_sg(qc);
+}
+
+static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct scatterlist *sg;
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct ata_bmdma_prd *prd;
+       unsigned int si, idx;
+
+       prd = pp->prd + ATA_MAX_PRD * qc->tag;
+
+       idx = 0;
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
+               u32 addr, offset;
+               u32 sg_len, len;
+
+               addr = (u32)sg_dma_address(sg);
+               sg_len = sg_dma_len(sg);
+
+               while (sg_len) {
+                       offset = addr & 0xffff;
+                       len = sg_len;
+                       if ((offset + sg_len) > 0x10000)
+                               len = 0x10000 - offset;
+
+                       prd[idx].addr = cpu_to_le32(addr);
+                       prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+
+                       idx++;
+                       sg_len -= len;
+                       addr += len;
+               }
+       }
+
+       prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+
+static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap,
+                                         struct ata_queued_cmd *qc)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       if (qc == NULL)
+               return 0;
+
+       DPRINTK("Enter\n");
+
+       writel((1 << qc->tag), pp->sactive_block);
+       pp->last_issue_tag = qc->tag;
+       pp->dhfis_bits &= ~(1 << qc->tag);
+       pp->dmafis_bits &= ~(1 << qc->tag);
+       pp->qc_active |= (0x1 << qc->tag);
+
+       ap->ops->sff_tf_load(ap, &qc->tf);       /* load tf registers */
+       ap->ops->sff_exec_command(ap, &qc->tf);
+
+       DPRINTK("Issued tag %u\n", qc->tag);
+
+       return 0;
+}
+
+static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       if (qc->tf.protocol != ATA_PROT_NCQ)
+               return ata_bmdma_qc_issue(qc);
+
+       DPRINTK("Enter\n");
+
+       if (!pp->qc_active)
+               nv_swncq_issue_atacmd(ap, qc);
+       else
+               nv_swncq_qc_to_dq(ap, qc);      /* add qc to defer queue */
+
+       return 0;
+}
+
+static void nv_swncq_hotplug(struct ata_port *ap, u32 fis)
+{
+       u32 serror;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+
+       ata_ehi_clear_desc(ehi);
+
+       /* AHCI needs SError cleared; otherwise, it might lock up */
+       sata_scr_read(&ap->link, SCR_ERROR, &serror);
+       sata_scr_write(&ap->link, SCR_ERROR, serror);
+
+       /* analyze @irq_stat */
+       if (fis & NV_SWNCQ_IRQ_ADDED)
+               ata_ehi_push_desc(ehi, "hot plug");
+       else if (fis & NV_SWNCQ_IRQ_REMOVED)
+               ata_ehi_push_desc(ehi, "hot unplug");
+
+       ata_ehi_hotplugged(ehi);
+
+       /* okay, let's hand over to EH */
+       ehi->serror |= serror;
+
+       ata_port_freeze(ap);
+}
+
+static int nv_swncq_sdbfis(struct ata_port *ap)
+{
+       struct ata_queued_cmd *qc;
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+       u32 sactive;
+       int nr_done = 0;
+       u32 done_mask;
+       int i;
+       u8 host_stat;
+       u8 lack_dhfis = 0;
+
+       host_stat = ap->ops->bmdma_status(ap);
+       if (unlikely(host_stat & ATA_DMA_ERR)) {
+               /* error when transfering data to/from memory */
+               ata_ehi_clear_desc(ehi);
+               ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+               ehi->err_mask |= AC_ERR_HOST_BUS;
+               ehi->action |= ATA_EH_RESET;
+               return -EINVAL;
+       }
+
+       ap->ops->sff_irq_clear(ap);
+       __ata_bmdma_stop(ap);
+
+       sactive = readl(pp->sactive_block);
+       done_mask = pp->qc_active ^ sactive;
+
+       if (unlikely(done_mask & sactive)) {
+               ata_ehi_clear_desc(ehi);
+               ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition"
+                                 "(%08x->%08x)", pp->qc_active, sactive);
+               ehi->err_mask |= AC_ERR_HSM;
+               ehi->action |= ATA_EH_RESET;
+               return -EINVAL;
+       }
+       for (i = 0; i < ATA_MAX_QUEUE; i++) {
+               if (!(done_mask & (1 << i)))
+                       continue;
+
+               qc = ata_qc_from_tag(ap, i);
+               if (qc) {
+                       ata_qc_complete(qc);
+                       pp->qc_active &= ~(1 << i);
+                       pp->dhfis_bits &= ~(1 << i);
+                       pp->dmafis_bits &= ~(1 << i);
+                       pp->sdbfis_bits |= (1 << i);
+                       nr_done++;
+               }
+       }
+
+       if (!ap->qc_active) {
+               DPRINTK("over\n");
+               nv_swncq_pp_reinit(ap);
+               return nr_done;
+       }
+
+       if (pp->qc_active & pp->dhfis_bits)
+               return nr_done;
+
+       if ((pp->ncq_flags & ncq_saw_backout) ||
+           (pp->qc_active ^ pp->dhfis_bits))
+               /* if the controller cann't get a device to host register FIS,
+                * The driver needs to reissue the new command.
+                */
+               lack_dhfis = 1;
+
+       DPRINTK("id 0x%x QC: qc_active 0x%x,"
+               "SWNCQ:qc_active 0x%X defer_bits %X "
+               "dhfis 0x%X dmafis 0x%X last_issue_tag %x\n",
+               ap->print_id, ap->qc_active, pp->qc_active,
+               pp->defer_queue.defer_bits, pp->dhfis_bits,
+               pp->dmafis_bits, pp->last_issue_tag);
+
+       nv_swncq_fis_reinit(ap);
+
+       if (lack_dhfis) {
+               qc = ata_qc_from_tag(ap, pp->last_issue_tag);
+               nv_swncq_issue_atacmd(ap, qc);
+               return nr_done;
+       }
+
+       if (pp->defer_queue.defer_bits) {
+               /* send deferral queue command */
+               qc = nv_swncq_qc_from_dq(ap);
+               WARN_ON(qc == NULL);
+               nv_swncq_issue_atacmd(ap, qc);
        }
 
-       ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
-                          nv_hardreset, ata_std_postreset);
+       return nr_done;
+}
+
+static inline u32 nv_swncq_tag(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       u32 tag;
+
+       tag = readb(pp->tag_block) >> 2;
+       return (tag & 0x1f);
+}
+
+static int nv_swncq_dmafis(struct ata_port *ap)
+{
+       struct ata_queued_cmd *qc;
+       unsigned int rw;
+       u8 dmactl;
+       u32 tag;
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       __ata_bmdma_stop(ap);
+       tag = nv_swncq_tag(ap);
+
+       DPRINTK("dma setup tag 0x%x\n", tag);
+       qc = ata_qc_from_tag(ap, tag);
+
+       if (unlikely(!qc))
+               return 0;
+
+       rw = qc->tf.flags & ATA_TFLAG_WRITE;
+
+       /* load PRD table addr. */
+       iowrite32(pp->prd_dma + ATA_PRD_TBL_SZ * qc->tag,
+                 ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+       /* specify data direction, triple-check start bit is clear */
+       dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+       dmactl &= ~ATA_DMA_WR;
+       if (!rw)
+               dmactl |= ATA_DMA_WR;
+
+       iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+       return 1;
 }
 
-static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
 {
-       static int printed_version = 0;
-       struct ata_port_info *ppi[2];
-       struct ata_probe_ent *probe_ent;
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct ata_queued_cmd *qc;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+       u32 serror;
+       u8 ata_stat;
+       int rc = 0;
+
+       ata_stat = ap->ops->sff_check_status(ap);
+       nv_swncq_irq_clear(ap, fis);
+       if (!fis)
+               return;
+
+       if (ap->pflags & ATA_PFLAG_FROZEN)
+               return;
+
+       if (fis & NV_SWNCQ_IRQ_HOTPLUG) {
+               nv_swncq_hotplug(ap, fis);
+               return;
+       }
+
+       if (!pp->qc_active)
+               return;
+
+       if (ap->ops->scr_read(&ap->link, SCR_ERROR, &serror))
+               return;
+       ap->ops->scr_write(&ap->link, SCR_ERROR, serror);
+
+       if (ata_stat & ATA_ERR) {
+               ata_ehi_clear_desc(ehi);
+               ata_ehi_push_desc(ehi, "Ata error. fis:0x%X", fis);
+               ehi->err_mask |= AC_ERR_DEV;
+               ehi->serror |= serror;
+               ehi->action |= ATA_EH_RESET;
+               ata_port_freeze(ap);
+               return;
+       }
+
+       if (fis & NV_SWNCQ_IRQ_BACKOUT) {
+               /* If the IRQ is backout, driver must issue
+                * the new command again some time later.
+                */
+               pp->ncq_flags |= ncq_saw_backout;
+       }
+
+       if (fis & NV_SWNCQ_IRQ_SDBFIS) {
+               pp->ncq_flags |= ncq_saw_sdb;
+               DPRINTK("id 0x%x SWNCQ: qc_active 0x%X "
+                       "dhfis 0x%X dmafis 0x%X sactive 0x%X\n",
+                       ap->print_id, pp->qc_active, pp->dhfis_bits,
+                       pp->dmafis_bits, readl(pp->sactive_block));
+               rc = nv_swncq_sdbfis(ap);
+               if (rc < 0)
+                       goto irq_error;
+       }
+
+       if (fis & NV_SWNCQ_IRQ_DHREGFIS) {
+               /* The interrupt indicates the new command
+                * was transmitted correctly to the drive.
+                */
+               pp->dhfis_bits |= (0x1 << pp->last_issue_tag);
+               pp->ncq_flags |= ncq_saw_d2h;
+               if (pp->ncq_flags & (ncq_saw_sdb | ncq_saw_backout)) {
+                       ata_ehi_push_desc(ehi, "illegal fis transaction");
+                       ehi->err_mask |= AC_ERR_HSM;
+                       ehi->action |= ATA_EH_RESET;
+                       goto irq_error;
+               }
+
+               if (!(fis & NV_SWNCQ_IRQ_DMASETUP) &&
+                   !(pp->ncq_flags & ncq_saw_dmas)) {
+                       ata_stat = ap->ops->sff_check_status(ap);
+                       if (ata_stat & ATA_BUSY)
+                               goto irq_exit;
+
+                       if (pp->defer_queue.defer_bits) {
+                               DPRINTK("send next command\n");
+                               qc = nv_swncq_qc_from_dq(ap);
+                               nv_swncq_issue_atacmd(ap, qc);
+                       }
+               }
+       }
+
+       if (fis & NV_SWNCQ_IRQ_DMASETUP) {
+               /* program the dma controller with appropriate PRD buffers
+                * and start the DMA transfer for requested command.
+                */
+               pp->dmafis_bits |= (0x1 << nv_swncq_tag(ap));
+               pp->ncq_flags |= ncq_saw_dmas;
+               rc = nv_swncq_dmafis(ap);
+       }
+
+irq_exit:
+       return;
+irq_error:
+       ata_ehi_push_desc(ehi, "fis:0x%x", fis);
+       ata_port_freeze(ap);
+       return;
+}
+
+static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance)
+{
+       struct ata_host *host = dev_instance;
+       unsigned int i;
+       unsigned int handled = 0;
+       unsigned long flags;
+       u32 irq_stat;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       irq_stat = readl(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_MCP55);
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               if (ap->link.sactive) {
+                       nv_swncq_host_interrupt(ap, (u16)irq_stat);
+                       handled = 1;
+               } else {
+                       if (irq_stat)   /* reserve Hotplug */
+                               nv_swncq_irq_clear(ap, 0xfff0);
+
+                       handled += nv_host_intr(ap, (u8)irq_stat);
+               }
+               irq_stat >>= NV_INT_PORT_SHIFT_MCP55;
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       return IRQ_RETVAL(handled);
+}
+
+static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       static int printed_version;
+       const struct ata_port_info *ppi[] = { NULL, NULL };
+       struct nv_pi_priv *ipriv;
+       struct ata_host *host;
        struct nv_host_priv *hpriv;
        int rc;
        u32 bar;
        void __iomem *base;
        unsigned long type = ent->driver_data;
-       int mask_set = 0;
 
         // Make sure this is a SATA controller by counting the number of bars
         // (NVIDIA SATA controllers will always have six bars).  Otherwise,
         // it's an IDE controller and we ignore it.
-       for (bar=0; bar<6; bar++)
+       for (bar = 0; bar < 6; bar++)
                if (pci_resource_start(pdev, bar) == 0)
                        return -ENODEV;
 
@@ -1492,50 +2419,36 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc) {
-               pcim_pin_device(pdev);
-               return rc;
-       }
-
-       if(type >= CK804 && adma_enabled) {
+       /* determine type and allocate host */
+       if (type == CK804 && adma_enabled) {
                dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n");
                type = ADMA;
-               if(!pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
-                  !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
-                       mask_set = 1;
+       } else if (type == MCP5x && swncq_enabled) {
+               dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n");
+               type = SWNCQ;
        }
 
-       if(!mask_set) {
-               rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-               if (rc)
-                       return rc;
-               rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-               if (rc)
-                       return rc;
-       }
-
-       rc = -ENOMEM;
+       ppi[0] = &nv_port_info[type];
+       ipriv = ppi[0]->private_data;
+       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       if (rc)
+               return rc;
 
        hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
        if (!hpriv)
                return -ENOMEM;
-
-       ppi[0] = ppi[1] = &nv_port_info[type];
-       probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-       if (!probe_ent)
-               return -ENOMEM;
-
-       if (!pcim_iomap(pdev, NV_MMIO_BAR, 0))
-               return -EIO;
-       probe_ent->iomap = pcim_iomap_table(pdev);
-
-       probe_ent->private_data = hpriv;
        hpriv->type = type;
+       host->private_data = hpriv;
 
-       base = probe_ent->iomap[NV_MMIO_BAR];
-       probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
-       probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
+       /* request and iomap NV_MMIO_BAR */
+       rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME);
+       if (rc)
+               return rc;
+
+       /* configure SCR access */
+       base = host->iomap[NV_MMIO_BAR];
+       host->ports[0]->ioaddr.scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
+       host->ports[1]->ioaddr.scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
 
        /* enable SATA space for CK804 */
        if (type >= CK804) {
@@ -1546,66 +2459,62 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
        }
 
-       pci_set_master(pdev);
-
+       /* init ADMA */
        if (type == ADMA) {
-               rc = nv_adma_host_init(probe_ent);
+               rc = nv_adma_host_init(host);
                if (rc)
                        return rc;
-       }
-
-       rc = ata_device_add(probe_ent);
-       if (rc != NV_PORTS)
-               return -ENODEV;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
-}
+       } else if (type == SWNCQ)
+               nv_swncq_host_init(host);
 
-static void nv_remove_one (struct pci_dev *pdev)
-{
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
-       struct nv_host_priv *hpriv = host->private_data;
+       if (msi_enabled) {
+               dev_printk(KERN_NOTICE, &pdev->dev, "Using MSI\n");
+               pci_enable_msi(pdev);
+       }
 
-       ata_pci_remove_one(pdev);
-       kfree(hpriv);
+       pci_set_master(pdev);
+       return ata_pci_sff_activate_host(host, ipriv->irq_handler, ipriv->sht);
 }
 
+#ifdef CONFIG_PM
 static int nv_pci_device_resume(struct pci_dev *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
        struct nv_host_priv *hpriv = host->private_data;
+       int rc;
 
-       ata_pci_device_do_resume(pdev);
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
 
        if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
-               if(hpriv->type >= CK804) {
+               if (hpriv->type >= CK804) {
                        u8 regval;
 
                        pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
                        regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
                        pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
                }
-               if(hpriv->type == ADMA) {
+               if (hpriv->type == ADMA) {
                        u32 tmp32;
                        struct nv_adma_port_priv *pp;
                        /* enable/disable ADMA on the ports appropriately */
                        pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
 
                        pp = host->ports[0]->private_data;
-                       if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+                       if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
                                tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN |
-                                          NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
+                                          NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
                        else
                                tmp32 |=  (NV_MCP_SATA_CFG_20_PORT0_EN |
-                                          NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
+                                          NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
                        pp = host->ports[1]->private_data;
-                       if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+                       if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
                                tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT1_EN |
-                                          NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
+                                          NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
                        else
                                tmp32 |=  (NV_MCP_SATA_CFG_20_PORT1_EN |
-                                          NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
+                                          NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
 
                        pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
                }
@@ -1615,6 +2524,7 @@ static int nv_pci_device_resume(struct pci_dev *pdev)
 
        return 0;
 }
+#endif
 
 static void nv_ck804_host_stop(struct ata_host *host)
 {
@@ -1657,4 +2567,9 @@ static void __exit nv_exit(void)
 module_init(nv_init);
 module_exit(nv_exit);
 module_param_named(adma, adma_enabled, bool, 0444);
-MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)");
+MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)");
+module_param_named(swncq, swncq_enabled, bool, 0444);
+MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: true)");
+module_param_named(msi, msi_enabled, bool, 0444);
+MODULE_PARM_DESC(msi, "Enable use of MSI (Default: false)");
+