kbuild: fix segfault in modpost
[safe/jmp/linux-2.6] / drivers / ata / ahci.c
index 436de03..c168203 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "ahci"
-#define DRV_VERSION    "2.1"
+#define DRV_VERSION    "2.3"
 
 
 enum {
@@ -54,7 +54,7 @@ enum {
        AHCI_MAX_PORTS          = 32,
        AHCI_MAX_SG             = 168, /* hardware max is 64K */
        AHCI_DMA_BOUNDARY       = 0xffffffff,
-       AHCI_USE_CLUSTERING     = 0,
+       AHCI_USE_CLUSTERING     = 1,
        AHCI_MAX_CMDS           = 32,
        AHCI_CMD_SZ             = 32,
        AHCI_CMD_SLOT_SZ        = AHCI_MAX_CMDS * AHCI_CMD_SZ,
@@ -81,6 +81,7 @@ enum {
        board_ahci_vt8251       = 2,
        board_ahci_ign_iferr    = 3,
        board_ahci_sb600        = 4,
+       board_ahci_mv           = 5,
 
        /* global controller registers */
        HOST_CAP                = 0x00, /* host capabilities */
@@ -98,6 +99,7 @@ enum {
        HOST_CAP_SSC            = (1 << 14), /* Slumber capable */
        HOST_CAP_CLO            = (1 << 24), /* Command List Override support */
        HOST_CAP_SSS            = (1 << 27), /* Staggered Spin-up */
+       HOST_CAP_SNTF           = (1 << 29), /* SNotification register */
        HOST_CAP_NCQ            = (1 << 30), /* Native Command Queueing */
        HOST_CAP_64             = (1 << 31), /* PCI DAC (64-bit DMA) support */
 
@@ -112,11 +114,11 @@ enum {
        PORT_TFDATA             = 0x20, /* taskfile data */
        PORT_SIG                = 0x24, /* device TF signature */
        PORT_CMD_ISSUE          = 0x38, /* command issue */
-       PORT_SCR                = 0x28, /* SATA phy register block */
        PORT_SCR_STAT           = 0x28, /* SATA phy register: SStatus */
        PORT_SCR_CTL            = 0x2c, /* SATA phy register: SControl */
        PORT_SCR_ERR            = 0x30, /* SATA phy register: SError */
        PORT_SCR_ACT            = 0x34, /* SATA phy register: SActive */
+       PORT_SCR_NTF            = 0x3c, /* SATA phy register: SNotification */
 
        /* PORT_IRQ_{STAT,MASK} bits */
        PORT_IRQ_COLD_PRES      = (1 << 31), /* cold presence detect */
@@ -170,6 +172,14 @@ enum {
        AHCI_FLAG_IGN_IRQ_IF_ERR        = (1 << 25), /* ignore IRQ_IF_ERR */
        AHCI_FLAG_HONOR_PI              = (1 << 26), /* honor PORTS_IMPL */
        AHCI_FLAG_IGN_SERR_INTERNAL     = (1 << 27), /* ignore SERR_INTERNAL */
+       AHCI_FLAG_32BIT_ONLY            = (1 << 28), /* force 32bit */
+       AHCI_FLAG_MV_PATA               = (1 << 29), /* PATA port */
+       AHCI_FLAG_NO_MSI                = (1 << 30), /* no PCI MSI */
+
+       AHCI_FLAG_COMMON                = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                         ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+                                         ATA_FLAG_SKIP_D2H_BSY |
+                                         ATA_FLAG_ACPI_SATA,
 };
 
 struct ahci_cmd_hdr {
@@ -207,11 +217,10 @@ struct ahci_port_priv {
        unsigned int            ncq_saw_sdb:1;
 };
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
 static void ahci_irq_clear(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
@@ -223,9 +232,12 @@ static void ahci_thaw(struct ata_port *ap);
 static void ahci_error_handler(struct ata_port *ap);
 static void ahci_vt8251_error_handler(struct ata_port *ap);
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
+static int ahci_port_resume(struct ata_port *ap);
+static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+                              u32 opts);
 #ifdef CONFIG_PM
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
-static int ahci_port_resume(struct ata_port *ap);
 static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
 static int ahci_pci_device_resume(struct pci_dev *pdev);
 #endif
@@ -247,10 +259,6 @@ static struct scsi_host_template ahci_sht = {
        .slave_configure        = ata_scsi_slave_config,
        .slave_destroy          = ata_scsi_slave_destroy,
        .bios_param             = ata_std_bios_param,
-#ifdef CONFIG_PM
-       .suspend                = ata_scsi_device_suspend,
-       .resume                 = ata_scsi_device_resume,
-#endif
 };
 
 static const struct ata_port_operations ahci_ops = {
@@ -265,7 +273,6 @@ static const struct ata_port_operations ahci_ops = {
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
 
-       .irq_handler            = ahci_interrupt,
        .irq_clear              = ahci_irq_clear,
        .irq_on                 = ata_dummy_irq_on,
        .irq_ack                = ata_dummy_irq_ack,
@@ -300,7 +307,6 @@ static const struct ata_port_operations ahci_vt8251_ops = {
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
 
-       .irq_handler            = ahci_interrupt,
        .irq_clear              = ahci_irq_clear,
        .irq_on                 = ata_dummy_irq_on,
        .irq_ack                = ata_dummy_irq_ack,
@@ -326,58 +332,54 @@ static const struct ata_port_operations ahci_vt8251_ops = {
 static const struct ata_port_info ahci_port_info[] = {
        /* board_ahci */
        {
-               .sht            = &ahci_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY,
+               .flags          = AHCI_FLAG_COMMON,
                .pio_mask       = 0x1f, /* pio0-4 */
-               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
        /* board_ahci_pi */
        {
-               .sht            = &ahci_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
+               .flags          = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
                .pio_mask       = 0x1f, /* pio0-4 */
-               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
        /* board_ahci_vt8251 */
        {
-               .sht            = &ahci_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY |
-                                 ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
+               .flags          = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
+                                 AHCI_FLAG_NO_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
-               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_vt8251_ops,
        },
        /* board_ahci_ign_iferr */
        {
-               .sht            = &ahci_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY |
-                                 AHCI_FLAG_IGN_IRQ_IF_ERR,
+               .flags          = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
                .pio_mask       = 0x1f, /* pio0-4 */
-               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
        /* board_ahci_sb600 */
        {
+               .flags          = AHCI_FLAG_COMMON |
+                                 AHCI_FLAG_IGN_SERR_INTERNAL |
+                                 AHCI_FLAG_32BIT_ONLY,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_ops,
+       },
+       /* board_ahci_mv */
+       {
                .sht            = &ahci_sht,
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY |
-                                 AHCI_FLAG_IGN_SERR_INTERNAL,
+                                 ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI |
+                                 AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
+                                 AHCI_FLAG_MV_PATA,
                .pio_mask       = 0x1f, /* pio0-4 */
-               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
-
 };
 
 static const struct pci_device_id ahci_pci_tbl[] = {
@@ -416,9 +418,16 @@ static const struct pci_device_id ahci_pci_tbl[] = {
 
        /* ATI */
        { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
+       { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */
+       { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */
+       { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */
+       { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */
+       { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */
+       { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */
 
        /* VIA */
        { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
+       { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
 
        /* NVIDIA */
        { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },            /* MCP65 */
@@ -441,12 +450,39 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },            /* MCP67 */
        { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },            /* MCP67 */
        { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },            /* MCP67 */
+       { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci },            /* MCP73 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },            /* MCP77 */
 
        /* SiS */
        { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
        { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
        { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
 
+       /* Marvell */
+       { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },        /* 6145 */
+
        /* Generic, PCI class code for AHCI */
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
          PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
@@ -472,15 +508,24 @@ static inline int ahci_nr_ports(u32 cap)
        return (cap & 0x1f) + 1;
 }
 
-static inline void __iomem *ahci_port_base(void __iomem *base,
-                                          unsigned int port)
+static inline void __iomem *__ahci_port_base(struct ata_host *host,
+                                            unsigned int port_no)
+{
+       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+
+       return mmio + 0x100 + (port_no * 0x80);
+}
+
+static inline void __iomem *ahci_port_base(struct ata_port *ap)
 {
-       return base + 0x100 + (port * 0x80);
+       return __ahci_port_base(ap->host, ap->port_no);
 }
 
 /**
  *     ahci_save_initial_config - Save and fixup initial config values
- *     @probe_ent: probe_ent of target device
+ *     @pdev: target PCI device
+ *     @pi: associated ATA port info
+ *     @hpriv: host private area to store config values
  *
  *     Some registers containing configuration info might be setup by
  *     BIOS and might be cleared on reset.  This function saves the
@@ -492,10 +537,11 @@ static inline void __iomem *ahci_port_base(void __iomem *base,
  *     LOCKING:
  *     None.
  */
-static void ahci_save_initial_config(struct ata_probe_ent *probe_ent)
+static void ahci_save_initial_config(struct pci_dev *pdev,
+                                    const struct ata_port_info *pi,
+                                    struct ahci_host_priv *hpriv)
 {
-       struct ahci_host_priv *hpriv = probe_ent->private_data;
-       void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
+       void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
        u32 cap, port_map;
        int i;
 
@@ -505,18 +551,45 @@ static void ahci_save_initial_config(struct ata_probe_ent *probe_ent)
        hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
        hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
 
+       /* some chips have errata preventing 64bit use */
+       if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
+               dev_printk(KERN_INFO, &pdev->dev,
+                          "controller can't do 64bit DMA, forcing 32bit\n");
+               cap &= ~HOST_CAP_64;
+       }
+
+       if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+               dev_printk(KERN_INFO, &pdev->dev,
+                          "controller can't do NCQ, turning off CAP_NCQ\n");
+               cap &= ~HOST_CAP_NCQ;
+       }
+
        /* fixup zero port_map */
        if (!port_map) {
-               port_map = (1 << ahci_nr_ports(hpriv->cap)) - 1;
-               dev_printk(KERN_WARNING, probe_ent->dev,
+               port_map = (1 << ahci_nr_ports(cap)) - 1;
+               dev_printk(KERN_WARNING, &pdev->dev,
                           "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
 
                /* write the fixed up value to the PI register */
                hpriv->saved_port_map = port_map;
        }
 
+       /*
+        * Temporary Marvell 6145 hack: PATA port presence
+        * is asserted through the standard AHCI port
+        * presence register, as bit 4 (counting from 0)
+        */
+       if (pi->flags & AHCI_FLAG_MV_PATA) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "MV_AHCI HACK: port_map %x -> %x\n",
+                          hpriv->port_map,
+                          hpriv->port_map & 0xf);
+
+               port_map &= 0xf;
+       }
+
        /* cross check port_map and cap.n_ports */
-       if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) {
+       if (pi->flags & AHCI_FLAG_HONOR_PI) {
                u32 tmp_port_map = port_map;
                int n_ports = ahci_nr_ports(cap);
 
@@ -531,7 +604,7 @@ static void ahci_save_initial_config(struct ata_probe_ent *probe_ent)
                 * port_map is used to determine number of ports.
                 */
                if (n_ports || tmp_port_map)
-                       dev_printk(KERN_WARNING, probe_ent->dev,
+                       dev_printk(KERN_WARNING, &pdev->dev,
                                   "nr_ports (%u) and implemented port map "
                                   "(0x%x) don't match\n",
                                   ahci_nr_ports(cap), port_map);
@@ -547,58 +620,67 @@ static void ahci_save_initial_config(struct ata_probe_ent *probe_ent)
 
 /**
  *     ahci_restore_initial_config - Restore initial config
- *     @mmio: MMIO base for the host
- *     @hpriv: host private data
+ *     @host: target ATA host
  *
  *     Restore initial config stored by ahci_save_initial_config().
  *
  *     LOCKING:
  *     None.
  */
-static void ahci_restore_initial_config(void __iomem *mmio,
-                                       struct ahci_host_priv *hpriv)
+static void ahci_restore_initial_config(struct ata_host *host)
 {
+       struct ahci_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+
        writel(hpriv->saved_cap, mmio + HOST_CAP);
        writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
        (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
 }
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
 {
-       unsigned int sc_reg;
-
-       switch (sc_reg_in) {
-       case SCR_STATUS:        sc_reg = 0; break;
-       case SCR_CONTROL:       sc_reg = 1; break;
-       case SCR_ERROR:         sc_reg = 2; break;
-       case SCR_ACTIVE:        sc_reg = 3; break;
-       default:
-               return 0xffffffffU;
-       }
+       static const int offset[] = {
+               [SCR_STATUS]            = PORT_SCR_STAT,
+               [SCR_CONTROL]           = PORT_SCR_CTL,
+               [SCR_ERROR]             = PORT_SCR_ERR,
+               [SCR_ACTIVE]            = PORT_SCR_ACT,
+               [SCR_NOTIFICATION]      = PORT_SCR_NTF,
+       };
+       struct ahci_host_priv *hpriv = ap->host->private_data;
 
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       if (sc_reg < ARRAY_SIZE(offset) &&
+           (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+               return offset[sc_reg];
+       return 0;
 }
 
-
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
-                              u32 val)
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
-       unsigned int sc_reg;
-
-       switch (sc_reg_in) {
-       case SCR_STATUS:        sc_reg = 0; break;
-       case SCR_CONTROL:       sc_reg = 1; break;
-       case SCR_ERROR:         sc_reg = 2; break;
-       case SCR_ACTIVE:        sc_reg = 3; break;
-       default:
-               return;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       int offset = ahci_scr_offset(ap, sc_reg);
+
+       if (offset) {
+               *val = readl(port_mmio + offset);
+               return 0;
        }
+       return -EINVAL;
+}
+
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+       void __iomem *port_mmio = ahci_port_base(ap);
+       int offset = ahci_scr_offset(ap, sc_reg);
 
-       writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       if (offset) {
+               writel(val, port_mmio + offset);
+               return 0;
+       }
+       return -EINVAL;
 }
 
-static void ahci_start_engine(void __iomem *port_mmio)
+static void ahci_start_engine(struct ata_port *ap)
 {
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
 
        /* start DMA */
@@ -608,8 +690,9 @@ static void ahci_start_engine(void __iomem *port_mmio)
        readl(port_mmio + PORT_CMD); /* flush */
 }
 
-static int ahci_stop_engine(void __iomem *port_mmio)
+static int ahci_stop_engine(struct ata_port *ap)
 {
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
 
        tmp = readl(port_mmio + PORT_CMD);
@@ -631,19 +714,23 @@ static int ahci_stop_engine(void __iomem *port_mmio)
        return 0;
 }
 
-static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
-                             dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_start_fis_rx(struct ata_port *ap)
 {
+       void __iomem *port_mmio = ahci_port_base(ap);
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       struct ahci_port_priv *pp = ap->private_data;
        u32 tmp;
 
        /* set FIS registers */
-       if (cap & HOST_CAP_64)
-               writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
-       writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+       if (hpriv->cap & HOST_CAP_64)
+               writel((pp->cmd_slot_dma >> 16) >> 16,
+                      port_mmio + PORT_LST_ADDR_HI);
+       writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
 
-       if (cap & HOST_CAP_64)
-               writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
-       writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+       if (hpriv->cap & HOST_CAP_64)
+               writel((pp->rx_fis_dma >> 16) >> 16,
+                      port_mmio + PORT_FIS_ADDR_HI);
+       writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
 
        /* enable FIS reception */
        tmp = readl(port_mmio + PORT_CMD);
@@ -654,8 +741,9 @@ static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
        readl(port_mmio + PORT_CMD);
 }
 
-static int ahci_stop_fis_rx(void __iomem *port_mmio)
+static int ahci_stop_fis_rx(struct ata_port *ap)
 {
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
 
        /* disable FIS reception */
@@ -672,14 +760,16 @@ static int ahci_stop_fis_rx(void __iomem *port_mmio)
        return 0;
 }
 
-static void ahci_power_up(void __iomem *port_mmio, u32 cap)
+static void ahci_power_up(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 cmd;
 
        cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
 
        /* spin up device */
-       if (cap & HOST_CAP_SSS) {
+       if (hpriv->cap & HOST_CAP_SSS) {
                cmd |= PORT_CMD_SPIN_UP;
                writel(cmd, port_mmio + PORT_CMD);
        }
@@ -689,11 +779,13 @@ static void ahci_power_up(void __iomem *port_mmio, u32 cap)
 }
 
 #ifdef CONFIG_PM
-static void ahci_power_down(void __iomem *port_mmio, u32 cap)
+static void ahci_power_down(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 cmd, scontrol;
 
-       if (!(cap & HOST_CAP_SSS))
+       if (!(hpriv->cap & HOST_CAP_SSS))
                return;
 
        /* put device into listen mode, first set PxSCTL.DET to 0 */
@@ -708,29 +800,28 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
 }
 #endif
 
-static void ahci_init_port(void __iomem *port_mmio, u32 cap,
-                          dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_start_port(struct ata_port *ap)
 {
        /* enable FIS reception */
-       ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
+       ahci_start_fis_rx(ap);
 
        /* enable DMA */
-       ahci_start_engine(port_mmio);
+       ahci_start_engine(ap);
 }
 
-static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
+static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
 {
        int rc;
 
        /* disable DMA */
-       rc = ahci_stop_engine(port_mmio);
+       rc = ahci_stop_engine(ap);
        if (rc) {
                *emsg = "failed to stop engine";
                return rc;
        }
 
        /* disable FIS reception */
-       rc = ahci_stop_fis_rx(port_mmio);
+       rc = ahci_stop_fis_rx(ap);
        if (rc) {
                *emsg = "failed stop FIS RX";
                return rc;
@@ -739,9 +830,10 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
        return 0;
 }
 
-static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev,
-                                struct ahci_host_priv *hpriv)
+static int ahci_reset_controller(struct ata_host *host)
 {
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        u32 tmp;
 
        /* global controller reset */
@@ -758,7 +850,7 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev,
 
        tmp = readl(mmio + HOST_CTL);
        if (tmp & HOST_RESET) {
-               dev_printk(KERN_ERR, &pdev->dev,
+               dev_printk(KERN_ERR, host->dev,
                           "controller reset failed (0x%x)\n", tmp);
                return -EIO;
        }
@@ -768,7 +860,7 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev,
        (void) readl(mmio + HOST_CTL);  /* flush */
 
        /* some registers might be cleared on reset.  restore initial values */
-       ahci_restore_initial_config(mmio, hpriv);
+       ahci_restore_initial_config(host);
 
        if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
                u16 tmp16;
@@ -782,39 +874,62 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev,
        return 0;
 }
 
-static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
-                                int n_ports, unsigned int port_flags,
-                                struct ahci_host_priv *hpriv)
+static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
+                          int port_no, void __iomem *mmio,
+                          void __iomem *port_mmio)
 {
-       int i, rc;
+       const char *emsg = NULL;
+       int rc;
        u32 tmp;
 
-       for (i = 0; i < n_ports; i++) {
-               void __iomem *port_mmio = ahci_port_base(mmio, i);
-               const char *emsg = NULL;
+       /* make sure port is not active */
+       rc = ahci_deinit_port(ap, &emsg);
+       if (rc)
+               dev_printk(KERN_WARNING, &pdev->dev,
+                          "%s (%d)\n", emsg, rc);
+
+       /* clear SError */
+       tmp = readl(port_mmio + PORT_SCR_ERR);
+       VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
+       writel(tmp, port_mmio + PORT_SCR_ERR);
 
-               if ((port_flags & AHCI_FLAG_HONOR_PI) &&
-                   !(hpriv->port_map & (1 << i)))
-                       continue;
+       /* clear port IRQ */
+       tmp = readl(port_mmio + PORT_IRQ_STAT);
+       VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
+       if (tmp)
+               writel(tmp, port_mmio + PORT_IRQ_STAT);
 
-               /* make sure port is not active */
-               rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
-               if (rc)
-                       dev_printk(KERN_WARNING, &pdev->dev,
-                                  "%s (%d)\n", emsg, rc);
+       writel(1 << port_no, mmio + HOST_IRQ_STAT);
+}
 
-               /* clear SError */
-               tmp = readl(port_mmio + PORT_SCR_ERR);
-               VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
-               writel(tmp, port_mmio + PORT_SCR_ERR);
+static void ahci_init_controller(struct ata_host *host)
+{
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+       int i;
+       void __iomem *port_mmio;
+       u32 tmp;
+
+       if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) {
+               port_mmio = __ahci_port_base(host, 4);
+
+               writel(0, port_mmio + PORT_IRQ_MASK);
 
                /* clear port IRQ */
                tmp = readl(port_mmio + PORT_IRQ_STAT);
                VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
                if (tmp)
                        writel(tmp, port_mmio + PORT_IRQ_STAT);
+       }
 
-               writel(1 << i, mmio + HOST_IRQ_STAT);
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               port_mmio = ahci_port_base(ap);
+               if (ata_port_is_dummy(ap))
+                       continue;
+
+               ahci_port_init(pdev, ap, i, mmio, port_mmio);
        }
 
        tmp = readl(mmio + HOST_CTL);
@@ -826,7 +941,7 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
 
 static unsigned int ahci_dev_classify(struct ata_port *ap)
 {
-       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+       void __iomem *port_mmio = ahci_port_base(ap);
        struct ata_taskfile tf;
        u32 tmp;
 
@@ -852,37 +967,87 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
        pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
 }
 
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
 {
        void __iomem *port_mmio = ap->ioaddr.cmd_addr;
        struct ahci_host_priv *hpriv = ap->host->private_data;
        u32 tmp;
+       int busy, rc;
 
-       if (!(hpriv->cap & HOST_CAP_CLO))
-               return -EOPNOTSUPP;
+       /* do we need to kick the port? */
+       busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+       if (!busy && !force_restart)
+               return 0;
+
+       /* stop engine */
+       rc = ahci_stop_engine(ap);
+       if (rc)
+               goto out_restart;
 
+       /* need to do CLO? */
+       if (!busy) {
+               rc = 0;
+               goto out_restart;
+       }
+
+       if (!(hpriv->cap & HOST_CAP_CLO)) {
+               rc = -EOPNOTSUPP;
+               goto out_restart;
+       }
+
+       /* perform CLO */
        tmp = readl(port_mmio + PORT_CMD);
        tmp |= PORT_CMD_CLO;
        writel(tmp, port_mmio + PORT_CMD);
 
+       rc = 0;
        tmp = ata_wait_register(port_mmio + PORT_CMD,
                                PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
        if (tmp & PORT_CMD_CLO)
-               return -EIO;
+               rc = -EIO;
 
-       return 0;
+       /* restart engine */
+ out_restart:
+       ahci_start_engine(ap);
+       return rc;
 }
 
-static int ahci_softreset(struct ata_port *ap, unsigned int *class)
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+                               struct ata_taskfile *tf, int is_cmd, u16 flags,
+                               unsigned long timeout_msec)
 {
-       struct ahci_port_priv *pp = ap->private_data;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        const u32 cmd_fis_len = 5; /* five dwords */
+       struct ahci_port_priv *pp = ap->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       u8 *fis = pp->cmd_tbl;
+       u32 tmp;
+
+       /* prep the command */
+       ata_tf_to_fis(tf, pmp, is_cmd, fis);
+       ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+       /* issue & wait */
+       writel(1, port_mmio + PORT_CMD_ISSUE);
+
+       if (timeout_msec) {
+               tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+                                       1, timeout_msec);
+               if (tmp & 0x1) {
+                       ahci_kick_engine(ap, 1);
+                       return -EBUSY;
+               }
+       } else
+               readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
+
+       return 0;
+}
+
+static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+                            int pmp, unsigned long deadline)
+{
        const char *reason = NULL;
+       unsigned long now, msecs;
        struct ata_taskfile tf;
-       u32 tmp;
-       u8 *fis;
        int rc;
 
        DPRINTK("ENTER\n");
@@ -894,43 +1059,22 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
        }
 
        /* prepare for SRST (AHCI-1.1 10.4.1) */
-       rc = ahci_stop_engine(port_mmio);
-       if (rc) {
-               reason = "failed to stop engine";
-               goto fail_restart;
-       }
-
-       /* check BUSY/DRQ, perform Command List Override if necessary */
-       if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
-               rc = ahci_clo(ap);
-
-               if (rc == -EOPNOTSUPP) {
-                       reason = "port busy but CLO unavailable";
-                       goto fail_restart;
-               } else if (rc) {
-                       reason = "port busy but CLO failed";
-                       goto fail_restart;
-               }
-       }
-
-       /* restart engine */
-       ahci_start_engine(port_mmio);
+       rc = ahci_kick_engine(ap, 1);
+       if (rc)
+               ata_port_printk(ap, KERN_WARNING,
+                               "failed to reset engine (errno=%d)", rc);
 
        ata_tf_init(ap->device, &tf);
-       fis = pp->cmd_tbl;
 
        /* issue the first D2H Register FIS */
-       ahci_fill_cmd_slot(pp, 0,
-                          cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+       msecs = 0;
+       now = jiffies;
+       if (time_after(now, deadline))
+               msecs = jiffies_to_msecs(deadline - now);
 
        tf.ctl |= ATA_SRST;
-       ata_tf_to_fis(&tf, fis, 0);
-       fis[1] &= ~(1 << 7);    /* turn off Command FIS bit */
-
-       writel(1, port_mmio + PORT_CMD_ISSUE);
-
-       tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
-       if (tmp & 0x1) {
+       if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
+                                AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
                rc = -EIO;
                reason = "1st FIS failed";
                goto fail;
@@ -940,14 +1084,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
        msleep(1);
 
        /* issue the second D2H Register FIS */
-       ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
        tf.ctl &= ~ATA_SRST;
-       ata_tf_to_fis(&tf, fis, 0);
-       fis[1] &= ~(1 << 7);    /* turn off Command FIS bit */
-
-       writel(1, port_mmio + PORT_CMD_ISSUE);
-       readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
+       ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
 
        /* spec mandates ">= 2ms" before checking status.
         * We wait 150ms, because that was the magic delay used for
@@ -959,47 +1097,48 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
         */
        msleep(150);
 
-       *class = ATA_DEV_NONE;
-       if (ata_port_online(ap)) {
-               if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
-                       rc = -EIO;
-                       reason = "device not ready";
-                       goto fail;
-               }
-               *class = ahci_dev_classify(ap);
+       rc = ata_wait_ready(ap, deadline);
+       /* link occupied, -ENODEV too is an error */
+       if (rc) {
+               reason = "device not ready";
+               goto fail;
        }
+       *class = ahci_dev_classify(ap);
 
        DPRINTK("EXIT, class=%u\n", *class);
        return 0;
 
- fail_restart:
-       ahci_start_engine(port_mmio);
  fail:
        ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
        return rc;
 }
 
-static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+                         unsigned long deadline)
+{
+       return ahci_do_softreset(ap, class, 0, deadline);
+}
+
+static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
+                         unsigned long deadline)
 {
        struct ahci_port_priv *pp = ap->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        int rc;
 
        DPRINTK("ENTER\n");
 
-       ahci_stop_engine(port_mmio);
+       ahci_stop_engine(ap);
 
        /* clear D2H reception area to properly wait for D2H FIS */
        ata_tf_init(ap->device, &tf);
        tf.command = 0x80;
-       ata_tf_to_fis(&tf, d2h_fis, 0);
+       ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
-       rc = sata_std_hardreset(ap, class);
+       rc = sata_std_hardreset(ap, class, deadline);
 
-       ahci_start_engine(port_mmio);
+       ahci_start_engine(ap);
 
        if (rc == 0 && ata_port_online(ap))
                *class = ahci_dev_classify(ap);
@@ -1010,22 +1149,24 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
        return rc;
 }
 
-static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
+static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
+                                unsigned long deadline)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       u32 serror;
        int rc;
 
        DPRINTK("ENTER\n");
 
-       ahci_stop_engine(port_mmio);
+       ahci_stop_engine(ap);
 
-       rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
+       rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context),
+                                deadline);
 
        /* vt8251 needs SError cleared for the port to operate */
-       ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
+       ahci_scr_read(ap, SCR_ERROR, &serror);
+       ahci_scr_write(ap, SCR_ERROR, serror);
 
-       ahci_start_engine(port_mmio);
+       ahci_start_engine(ap);
 
        DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 
@@ -1037,7 +1178,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
 
 static void ahci_postreset(struct ata_port *ap, unsigned int *class)
 {
-       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 new_tmp, tmp;
 
        ata_std_postreset(ap, class);
@@ -1112,7 +1253,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
         */
        cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
 
-       ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+       ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
        if (is_atapi) {
                memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
                memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1145,7 +1286,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        ata_ehi_clear_desc(ehi);
 
        /* AHCI needs SError cleared; otherwise, it might lock up */
-       serror = ahci_scr_read(ap, SCR_ERROR);
+       ahci_scr_read(ap, SCR_ERROR, &serror);
        ahci_scr_write(ap, SCR_ERROR, serror);
 
        /* analyze @irq_stat */
@@ -1169,12 +1310,12 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        if (irq_stat & PORT_IRQ_IF_ERR) {
                err_mask |= AC_ERR_ATA_BUS;
                action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi, "interface fatal error");
+               ata_ehi_push_desc(ehi, "interface fatal error");
        }
 
        if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
                ata_ehi_hotplugged(ehi);
-               ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
+               ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
                        "connection status changed" : "PHY RDY changed");
        }
 
@@ -1183,7 +1324,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 
                err_mask |= AC_ERR_HSM;
                action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
+               ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
                                  unk[0], unk[1], unk[2], unk[3]);
        }
 
@@ -1203,10 +1344,9 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
                ata_port_abort(ap);
 }
 
-static void ahci_host_intr(struct ata_port *ap)
+static void ahci_port_intr(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
        struct ata_eh_info *ehi = &ap->eh_info;
        struct ahci_port_priv *pp = ap->private_data;
        u32 status, qc_active;
@@ -1330,7 +1470,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 
                ap = host->ports[i];
                if (ap) {
-                       ahci_host_intr(ap);
+                       ahci_port_intr(ap);
                        VPRINTK("port %u\n", i);
                } else {
                        VPRINTK("port %u (no irq)\n", i);
@@ -1357,7 +1497,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+       void __iomem *port_mmio = ahci_port_base(ap);
 
        if (qc->tf.protocol == ATA_PROT_NCQ)
                writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1369,8 +1509,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 
 static void ahci_freeze(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *port_mmio = ahci_port_base(ap);
 
        /* turn IRQ off */
        writel(0, port_mmio + PORT_IRQ_MASK);
@@ -1379,7 +1518,7 @@ static void ahci_freeze(struct ata_port *ap)
 static void ahci_thaw(struct ata_port *ap)
 {
        void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
 
        /* clear IRQ */
@@ -1393,13 +1532,10 @@ static void ahci_thaw(struct ata_port *ap)
 
 static void ahci_error_handler(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
        if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
-               ahci_stop_engine(port_mmio);
-               ahci_start_engine(port_mmio);
+               ahci_stop_engine(ap);
+               ahci_start_engine(ap);
        }
 
        /* perform recovery */
@@ -1409,13 +1545,10 @@ static void ahci_error_handler(struct ata_port *ap)
 
 static void ahci_vt8251_error_handler(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
        if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
-               ahci_stop_engine(port_mmio);
-               ahci_start_engine(port_mmio);
+               ahci_stop_engine(ap);
+               ahci_start_engine(ap);
        }
 
        /* perform recovery */
@@ -1426,51 +1559,37 @@ static void ahci_vt8251_error_handler(struct ata_port *ap)
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 
-       if (qc->flags & ATA_QCFLAG_FAILED) {
-               /* make DMA engine forget about the failed command */
-               ahci_stop_engine(port_mmio);
-               ahci_start_engine(port_mmio);
-       }
+       /* make DMA engine forget about the failed command */
+       if (qc->flags & ATA_QCFLAG_FAILED)
+               ahci_kick_engine(ap, 1);
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+       ahci_power_up(ap);
+       ahci_start_port(ap);
+
+       return 0;
 }
 
 #ifdef CONFIG_PM
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
 {
-       struct ahci_host_priv *hpriv = ap->host->private_data;
-       struct ahci_port_priv *pp = ap->private_data;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        const char *emsg = NULL;
        int rc;
 
-       rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+       rc = ahci_deinit_port(ap, &emsg);
        if (rc == 0)
-               ahci_power_down(port_mmio, hpriv->cap);
+               ahci_power_down(ap);
        else {
                ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
-               ahci_init_port(port_mmio, hpriv->cap,
-                              pp->cmd_slot_dma, pp->rx_fis_dma);
+               ahci_start_port(ap);
        }
 
        return rc;
 }
 
-static int ahci_port_resume(struct ata_port *ap)
-{
-       struct ahci_port_priv *pp = ap->private_data;
-       struct ahci_host_priv *hpriv = ap->host->private_data;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
-       ahci_power_up(port_mmio, hpriv->cap);
-       ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
-
-       return 0;
-}
-
 static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -1494,8 +1613,6 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 static int ahci_pci_device_resume(struct pci_dev *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
-       struct ahci_host_priv *hpriv = host->private_data;
-       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
@@ -1503,12 +1620,11 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
                return rc;
 
        if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
-               rc = ahci_reset_controller(mmio, pdev, hpriv);
+               rc = ahci_reset_controller(host);
                if (rc)
                        return rc;
 
-               ahci_init_controller(mmio, pdev, host->n_ports,
-                                    host->ports[0]->flags, hpriv);
+               ahci_init_controller(host);
        }
 
        ata_host_resume(host);
@@ -1520,10 +1636,7 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
 static int ahci_port_start(struct ata_port *ap)
 {
        struct device *dev = ap->host->dev;
-       struct ahci_host_priv *hpriv = ap->host->private_data;
        struct ahci_port_priv *pp;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        void *mem;
        dma_addr_t mem_dma;
        int rc;
@@ -1570,61 +1683,25 @@ static int ahci_port_start(struct ata_port *ap)
 
        ap->private_data = pp;
 
-       /* power up port */
-       ahci_power_up(port_mmio, hpriv->cap);
-
-       /* initialize port */
-       ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
-
-       return 0;
+       /* engage engines, captain */
+       return ahci_port_resume(ap);
 }
 
 static void ahci_port_stop(struct ata_port *ap)
 {
-       struct ahci_host_priv *hpriv = ap->host->private_data;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        const char *emsg = NULL;
        int rc;
 
        /* de-initialize port */
-       rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+       rc = ahci_deinit_port(ap, &emsg);
        if (rc)
                ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
 }
 
-static void ahci_setup_port(struct ata_ioports *port, void __iomem *base,
-                           unsigned int port_idx)
+static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
 {
-       VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
-       base = ahci_port_base(base, port_idx);
-       VPRINTK("base now==0x%lx\n", base);
-
-       port->cmd_addr          = base;
-       port->scr_addr          = base + PORT_SCR;
-
-       VPRINTK("EXIT\n");
-}
-
-static int ahci_host_init(struct ata_probe_ent *probe_ent)
-{
-       struct ahci_host_priv *hpriv = probe_ent->private_data;
-       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-       void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
-       unsigned int i, using_dac;
        int rc;
 
-       rc = ahci_reset_controller(mmio, pdev, hpriv);
-       if (rc)
-               return rc;
-
-       probe_ent->n_ports = fls(hpriv->port_map);
-       probe_ent->dummy_port_mask = ~hpriv->port_map;
-
-       VPRINTK("cap 0x%x  port_map 0x%x  n_ports %d\n",
-               hpriv->cap, hpriv->port_map, probe_ent->n_ports);
-
-       using_dac = hpriv->cap & HOST_CAP_64;
        if (using_dac &&
            !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
                rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
@@ -1650,23 +1727,14 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
                        return rc;
                }
        }
-
-       for (i = 0; i < probe_ent->n_ports; i++)
-               ahci_setup_port(&probe_ent->port[i], mmio, i);
-
-       ahci_init_controller(mmio, pdev, probe_ent->n_ports,
-                            probe_ent->port_flags, hpriv);
-
-       pci_set_master(pdev);
-
        return 0;
 }
 
-static void ahci_print_info(struct ata_probe_ent *probe_ent)
+static void ahci_print_info(struct ata_host *host)
 {
-       struct ahci_host_priv *hpriv = probe_ent->private_data;
-       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-       void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
+       struct ahci_host_priv *hpriv = host->private_data;
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        u32 vers, cap, impl, speed;
        const char *speed_s;
        u16 cc;
@@ -1712,12 +1780,13 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
 
        dev_printk(KERN_INFO, &pdev->dev,
                "flags: "
-               "%s%s%s%s%s%s"
-               "%s%s%s%s%s%s%s\n"
+               "%s%s%s%s%s%s%s"
+               "%s%s%s%s%s%s%s\n"
                ,
 
                cap & (1 << 31) ? "64bit " : "",
                cap & (1 << 30) ? "ncq " : "",
+               cap & (1 << 29) ? "sntf " : "",
                cap & (1 << 28) ? "ilck " : "",
                cap & (1 << 27) ? "stag " : "",
                cap & (1 << 26) ? "pm " : "",
@@ -1736,11 +1805,12 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       unsigned int board_idx = (unsigned int) ent->driver_data;
+       struct ata_port_info pi = ahci_port_info[ent->driver_data];
+       const struct ata_port_info *ppi[] = { &pi, NULL };
        struct device *dev = &pdev->dev;
-       struct ata_probe_ent *probe_ent;
        struct ahci_host_priv *hpriv;
-       int rc;
+       struct ata_host *host;
+       int i, rc;
 
        VPRINTK("ENTER\n");
 
@@ -1749,6 +1819,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* acquire resources */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -1759,49 +1830,54 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       if (pci_enable_msi(pdev))
+       if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev))
                pci_intx(pdev, 1);
 
-       probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
+       hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+       if (!hpriv)
                return -ENOMEM;
 
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
+       /* save initial config */
+       ahci_save_initial_config(pdev, &pi, hpriv);
 
-       hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
-       if (!hpriv)
+       /* prepare host */
+       if (hpriv->cap & HOST_CAP_NCQ)
+               pi.flags |= ATA_FLAG_NCQ;
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
+       if (!host)
                return -ENOMEM;
+       host->iomap = pcim_iomap_table(pdev);
+       host->private_data = hpriv;
 
-       probe_ent->sht          = ahci_port_info[board_idx].sht;
-       probe_ent->port_flags   = ahci_port_info[board_idx].flags;
-       probe_ent->pio_mask     = ahci_port_info[board_idx].pio_mask;
-       probe_ent->udma_mask    = ahci_port_info[board_idx].udma_mask;
-       probe_ent->port_ops     = ahci_port_info[board_idx].port_ops;
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+               void __iomem *port_mmio = ahci_port_base(ap);
 
-               probe_ent->irq = pdev->irq;
-               probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->iomap = pcim_iomap_table(pdev);
-       probe_ent->private_data = hpriv;
+               /* standard SATA port setup */
+               if (hpriv->port_map & (1 << i))
+                       ap->ioaddr.cmd_addr = port_mmio;
 
-       /* initialize adapter */
-       ahci_save_initial_config(probe_ent);
+               /* disabled/not-implemented port */
+               else
+                       ap->ops = &ata_dummy_port_ops;
+       }
 
-       rc = ahci_host_init(probe_ent);
+       /* initialize adapter */
+       rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
        if (rc)
                return rc;
 
-       if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
-           (hpriv->cap & HOST_CAP_NCQ))
-               probe_ent->port_flags |= ATA_FLAG_NCQ;
-
-       ahci_print_info(probe_ent);
+       rc = ahci_reset_controller(host);
+       if (rc)
+               return rc;
 
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
+       ahci_init_controller(host);
+       ahci_print_info(host);
 
-       devm_kfree(dev, probe_ent);
-       return 0;
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+                                &ahci_sht);
 }
 
 static int __init ahci_init(void)