Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / scsi / ahci.c
index fc5263c..7f54d5d 100644 (file)
@@ -1,26 +1,34 @@
 /*
  *  ahci.c - AHCI SATA support
  *
- *  Copyright 2004 Red Hat, Inc.
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *                 Please ALWAYS copy linux-ide@vger.kernel.org
+ *                 on emails.
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
+ *  Copyright 2004-2005 Red Hat, Inc.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
  *
- * Version 1.0 of the AHCI specification:
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * AHCI hardware documentation:
  * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+ * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
  *
  */
 
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/dma-mapping.h>
-#include "scsi.h"
+#include <linux/device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
 #include <linux/libata.h>
 #include <asm/io.h>
 
 #define DRV_NAME       "ahci"
-#define DRV_VERSION    "1.00"
+#define DRV_VERSION    "1.2"
 
 
 enum {
@@ -50,12 +60,16 @@ enum {
        AHCI_CMD_SLOT_SZ        = 32 * 32,
        AHCI_RX_FIS_SZ          = 256,
        AHCI_CMD_TBL_HDR        = 0x80,
+       AHCI_CMD_TBL_CDB        = 0x40,
        AHCI_CMD_TBL_SZ         = AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16),
        AHCI_PORT_PRIV_DMA_SZ   = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ +
                                  AHCI_RX_FIS_SZ,
        AHCI_IRQ_ON_SG          = (1 << 31),
        AHCI_CMD_ATAPI          = (1 << 5),
        AHCI_CMD_WRITE          = (1 << 6),
+       AHCI_CMD_PREFETCH       = (1 << 7),
+       AHCI_CMD_RESET          = (1 << 8),
+       AHCI_CMD_CLR_BUSY       = (1 << 10),
 
        RX_FIS_D2H_REG          = 0x40, /* offset of D2H Register FIS data */
 
@@ -75,6 +89,9 @@ enum {
 
        /* HOST_CAP bits */
        HOST_CAP_64             = (1 << 31), /* PCI DAC (64-bit DMA) support */
+       HOST_CAP_SSS            = (1 << 27), /* Staggered Spin-up */
+       HOST_CAP_CLO            = (1 << 24), /* Command List Override support */
+       HOST_CAP_SSC            = (1 << 14), /* Slumber capable */
 
        /* registers for each SATA port */
        PORT_LST_ADDR           = 0x00, /* command list DMA addr */
@@ -124,16 +141,23 @@ enum {
                                  PORT_IRQ_D2H_REG_FIS,
 
        /* PORT_CMD bits */
+       PORT_CMD_ATAPI          = (1 << 24), /* Device is ATAPI */
+       PORT_CMD_CPD            = (1 << 20), /* Cold presence detection */
        PORT_CMD_LIST_ON        = (1 << 15), /* cmd list DMA engine running */
        PORT_CMD_FIS_ON         = (1 << 14), /* FIS DMA engine running */
        PORT_CMD_FIS_RX         = (1 << 4), /* Enable FIS receive DMA engine */
+       PORT_CMD_CLO            = (1 << 3), /* Command list override */
        PORT_CMD_POWER_ON       = (1 << 2), /* Power up device */
        PORT_CMD_SPIN_UP        = (1 << 1), /* Spin up device */
        PORT_CMD_START          = (1 << 0), /* Enable port DMA engine */
 
+       PORT_CMD_ICC_MASK       = (0xf << 28), /* i/f ICC state mask */
        PORT_CMD_ICC_ACTIVE     = (0x1 << 28), /* Put i/f in active state */
        PORT_CMD_ICC_PARTIAL    = (0x2 << 28), /* Put i/f in partial state */
        PORT_CMD_ICC_SLUMBER    = (0x6 << 28), /* Put i/f in slumber state */
+
+       /* hpriv->flags bits */
+       AHCI_FLAG_MSI           = (1 << 0),
 };
 
 struct ahci_cmd_hdr {
@@ -155,6 +179,7 @@ struct ahci_host_priv {
        unsigned long           flags;
        u32                     cap;    /* cache of HOST_CAP register */
        u32                     port_map; /* cache of HOST_PORTS_IMPL reg */
+       u32                     dev_map; /* connected devices */
 };
 
 struct ahci_port_priv {
@@ -170,30 +195,42 @@ struct ahci_port_priv {
 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_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static int ahci_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static void ahci_phy_reset(struct ata_port *ap);
+static int ahci_start_engine(void __iomem *port_mmio);
+static int ahci_stop_engine(void __iomem *port_mmio);
+static int ahci_stop_fis_rx(void __iomem *port_mmio);
+static void ahci_start_fis_rx(void __iomem *port_mmio,
+                            struct ahci_port_priv *pp,
+                            struct ahci_host_priv *hpriv);
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void ahci_irq_clear(struct ata_port *ap);
 static void ahci_eng_timeout(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
-static void ahci_host_stop(struct ata_host_set *host_set);
+static int ahci_port_suspend(struct ata_port *ap, pm_message_t state);
+static int ahci_port_resume(struct ata_port *ap);
+static int ahci_port_standby(void __iomem *port_mmio, u32 cap);
+static int ahci_port_spinup(void __iomem *port_mmio, u32 cap);
+static void ahci_port_disable(struct ata_port *ap);
 static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void ahci_qc_prep(struct ata_queued_cmd *qc);
 static u8 ahci_check_status(struct ata_port *ap);
-static u8 ahci_check_err(struct ata_port *ap);
 static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+static int ahci_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state);
+static int ahci_scsi_device_resume(struct scsi_device *sdev);
+static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t state);
+static int ahci_pci_device_resume(struct pci_dev *pdev);
+static void ahci_remove_one (struct pci_dev *pdev);
 
-static Scsi_Host_Template ahci_sht = {
+static struct scsi_host_template ahci_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
-       .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = AHCI_MAX_SG,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = AHCI_USE_CLUSTERING,
@@ -201,20 +238,20 @@ static Scsi_Host_Template ahci_sht = {
        .dma_boundary           = AHCI_DMA_BOUNDARY,
        .slave_configure        = ata_scsi_slave_config,
        .bios_param             = ata_std_bios_param,
-       .ordered_flush          = 1,
+       .resume                 = ahci_scsi_device_resume,
+       .suspend                = ahci_scsi_device_suspend,
 };
 
-static struct ata_port_operations ahci_ops = {
-       .port_disable           = ata_port_disable,
+static const struct ata_port_operations ahci_ops = {
+       .port_disable           = ahci_port_disable,
 
        .check_status           = ahci_check_status,
        .check_altstatus        = ahci_check_status,
-       .check_err              = ahci_check_err,
        .dev_select             = ata_noop_dev_select,
 
        .tf_read                = ahci_tf_read,
 
-       .phy_reset              = ahci_phy_reset,
+       .probe_reset            = ahci_probe_reset,
 
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
@@ -229,23 +266,21 @@ static struct ata_port_operations ahci_ops = {
 
        .port_start             = ahci_port_start,
        .port_stop              = ahci_port_stop,
-       .host_stop              = ahci_host_stop,
 };
 
-static struct ata_port_info ahci_port_info[] = {
+static const struct ata_port_info ahci_port_info[] = {
        /* board_ahci */
        {
                .sht            = &ahci_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
-                                 ATA_FLAG_PIO_DMA,
-               .pio_mask       = 0x03, /* pio3-4 */
+                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+               .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
        },
 };
 
-static struct pci_device_id ahci_pci_tbl[] = {
+static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_ahci }, /* ICH6 */
        { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
@@ -264,6 +299,26 @@ static struct pci_device_id ahci_pci_tbl[] = {
          board_ahci }, /* ESB2 */
        { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_ahci }, /* ESB2 */
+       { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ICH7-M DH */
+       { PCI_VENDOR_ID_INTEL, 0x2821, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ICH8 */
+       { PCI_VENDOR_ID_INTEL, 0x2822, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ICH8 */
+       { PCI_VENDOR_ID_INTEL, 0x2824, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ICH8 */
+       { PCI_VENDOR_ID_INTEL, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ICH8M */
+       { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ICH8M */
+       { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* JMicron JMB360 */
+       { 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* JMicron JMB363 */
+       { PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ATI SB600 non-raid */
+       { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ATI SB600 raid */
        { }     /* terminate list */
 };
 
@@ -272,7 +327,9 @@ static struct pci_driver ahci_pci_driver = {
        .name                   = DRV_NAME,
        .id_table               = ahci_pci_tbl,
        .probe                  = ahci_init_one,
-       .remove                 = ata_pci_remove_one,
+       .remove                 = ahci_remove_one,
+       .suspend                = ahci_pci_device_suspend,
+       .resume                 = ahci_pci_device_resume,
 };
 
 
@@ -281,17 +338,9 @@ static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int
        return base + 0x100 + (port * 0x80);
 }
 
-static inline void *ahci_port_base (void *base, unsigned int port)
+static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
 {
-       return (void *) ahci_port_base_ul((unsigned long)base, port);
-}
-
-static void ahci_host_stop(struct ata_host_set *host_set)
-{
-       struct ahci_host_priv *hpriv = host_set->private_data;
-       kfree(hpriv);
-
-       ata_host_stop(host_set);
+       return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
 }
 
 static int ahci_port_start(struct ata_port *ap)
@@ -299,26 +348,28 @@ static int ahci_port_start(struct ata_port *ap)
        struct device *dev = ap->host_set->dev;
        struct ahci_host_priv *hpriv = ap->host_set->private_data;
        struct ahci_port_priv *pp;
-       int rc;
-       void *mem, *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void *mem;
        dma_addr_t mem_dma;
-
-       rc = ata_port_start(ap);
-       if (rc)
-               return rc;
+       int rc;
 
        pp = kmalloc(sizeof(*pp), GFP_KERNEL);
-       if (!pp) {
-               rc = -ENOMEM;
-               goto err_out;
-       }
+       if (!pp)
+               return -ENOMEM;
        memset(pp, 0, sizeof(*pp));
 
+       rc = ata_pad_alloc(ap, dev);
+       if (rc) {
+               kfree(pp);
+               return rc;
+       }
+
        mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
        if (!mem) {
-               rc = -ENOMEM;
-               goto err_out_kfree;
+               ata_pad_free(ap, dev);
+               kfree(pp);
+               return -ENOMEM;
        }
        memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
 
@@ -352,54 +403,139 @@ static int ahci_port_start(struct ata_port *ap)
 
        ap->private_data = pp;
 
-       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);
-       readl(port_mmio + PORT_LST_ADDR); /* flush */
+       /*
+        * Driver is setup; initialize the HBA
+        */
+       ahci_start_fis_rx(port_mmio, pp, hpriv);
+       rc = ahci_port_spinup(port_mmio, hpriv->cap);
+       if (rc)
+               printk(KERN_WARNING "ata%d: could not spinup device (%d)\n",
+                      ap->id, rc);
+       /*
+        * Do not enable DMA here; according to the spec
+        * (section 10.1.1) we should first enable FIS reception,
+        * then check if the port is enabled before we try to 
+        * switch on DMA.
+        * And as the port check is done during probe
+        * we really shouldn't be doing it here.
+        */
+       return 0;
+}
 
-       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);
-       readl(port_mmio + PORT_FIS_ADDR); /* flush */
 
-       writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
-              PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
-              PORT_CMD_START, port_mmio + PORT_CMD);
-       readl(port_mmio + PORT_CMD); /* flush */
+static void ahci_port_stop(struct ata_port *ap)
+{
+       struct device *dev = ap->host_set->dev;
+       struct ahci_port_priv *pp = ap->private_data;
 
-       return 0;
+       ahci_port_suspend(ap, PMSG_SUSPEND);
 
-err_out_kfree:
+       ap->private_data = NULL;
+       dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
+                         pp->cmd_slot, pp->cmd_slot_dma);
+       ata_pad_free(ap, dev);
        kfree(pp);
-err_out:
-       ata_port_stop(ap);
-       return rc;
 }
 
+static int ahci_port_suspend(struct ata_port *ap, pm_message_t state)
+{
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
+       int rc;
 
-static void ahci_port_stop(struct ata_port *ap)
+       /*
+        * Disable DMA
+        */
+       rc = ahci_stop_engine(port_mmio);
+       if (rc) {
+               printk(KERN_WARNING "ata%u: DMA engine busy\n", ap->id);
+               return rc;
+       }
+
+       /*
+        * Disable FIS reception
+        */
+       rc = ahci_stop_fis_rx(port_mmio);
+       if (rc)
+               printk(KERN_WARNING "ata%d: FIS RX still running (rc %d)\n",
+                      ap->id, rc);
+
+       /*
+        * Put device into slumber mode
+        */
+       if (!rc && state.event != PM_EVENT_FREEZE)
+               ahci_port_standby(port_mmio, hpriv->cap);
+
+       return rc;
+}
+
+static int ahci_port_resume(struct ata_port *ap)
 {
-       struct device *dev = ap->host_set->dev;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
        struct ahci_port_priv *pp = ap->private_data;
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       int rc;
        u32 tmp;
 
-       tmp = readl(port_mmio + PORT_CMD);
-       tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX);
-       writel(tmp, port_mmio + PORT_CMD);
-       readl(port_mmio + PORT_CMD); /* flush */
+       /*
+        * Enable FIS reception
+        */
+       ahci_start_fis_rx(port_mmio, pp, hpriv);
+
+       rc = ahci_port_spinup(port_mmio, hpriv->cap);
+       if (rc)
+               printk(KERN_WARNING "ata%d: could not spinup device (%d)\n",
+                      ap->id, rc);
 
-       /* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so
-        * this is slightly incorrect.
+       /*
+        * Clear error status
         */
-       msleep(500);
+       tmp = readl(port_mmio + PORT_SCR_ERR);
+       writel(tmp, port_mmio + PORT_SCR_ERR);
+       /*
+        * Clear interrupt status
+        */
+       tmp = readl(mmio + HOST_CTL);
+       if (!(tmp & HOST_IRQ_EN)) {
+               u32 irq_stat;
 
-       ap->private_data = NULL;
-       dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
-                         pp->cmd_slot, pp->cmd_slot_dma);
-       kfree(pp);
-       ata_port_stop(ap);
+               /* ack any pending irq events for this port */
+               irq_stat = readl(port_mmio + PORT_IRQ_STAT);
+               if (irq_stat)
+                       writel(irq_stat, port_mmio + PORT_IRQ_STAT);
+
+               /* set irq mask (enables interrupts) */
+               writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+
+               if ((hpriv->dev_map >> (ap->port_no + 1)) == 0) {
+                       /*
+                        * Enable interrupts if this was the last port
+                        */
+                       printk(KERN_WARNING "ata%d: enabling interrupts\n",
+                              ap->id);
+
+                       irq_stat = readl(mmio + HOST_IRQ_STAT);
+                       if (irq_stat)
+                               writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+                       tmp |= HOST_IRQ_EN;
+                       writel(tmp, mmio + HOST_CTL);
+                       (void) readl(mmio + HOST_CTL);
+               }
+       }
+
+       /*
+        * Enable DMA
+        */
+       rc = ahci_start_engine(port_mmio);
+       if (rc)
+               printk(KERN_WARNING "ata%d: cannot start DMA engine (rc %d)\n",
+                      ap->id, rc);
+
+       return rc;
 }
 
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
@@ -415,7 +551,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
                return 0xffffffffU;
        }
 
-       return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+       return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
 
@@ -433,20 +569,271 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
                return;
        }
 
-       writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+       writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static void ahci_phy_reset(struct ata_port *ap)
+static int ahci_stop_engine(void __iomem *port_mmio)
 {
-       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
-       struct ata_taskfile tf;
-       struct ata_device *dev = &ap->device[0];
+       int work;
        u32 tmp;
 
-       __sata_phy_reset(ap);
+       tmp = readl(port_mmio + PORT_CMD);
+       /* Check if the HBA is idle */
+       if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
+               return 0;
 
-       if (ap->flags & ATA_FLAG_PORT_DISABLED)
-               return;
+       /* Setting HBA to idle */
+       tmp &= ~PORT_CMD_START;
+       writel(tmp, port_mmio + PORT_CMD);
+
+       /*
+        * wait for engine to become idle
+        */
+       work = 1000;
+       while (work-- > 0) {
+               tmp = readl(port_mmio + PORT_CMD);
+               if ((tmp & PORT_CMD_LIST_ON) == 0)
+                       return 0;
+               udelay(10);
+       }
+
+       return -EIO;
+}
+
+static int ahci_start_engine(void __iomem *port_mmio)
+{
+       u32 tmp;
+       int work = 1000;
+
+       /*
+        * Get current status
+        */
+       tmp = readl(port_mmio + PORT_CMD);
+
+       /*
+        * AHCI rev 1.1 section 10.3.1:
+        * Software shall not set PxCMD.ST to '1' until it verifies
+        * that PxCMD.CR is '0' and has set PxCMD.FRE to '1'
+        */
+       if ((tmp & PORT_CMD_FIS_RX) == 0)
+               return -EPERM;
+
+       /*
+        * wait for engine to become idle.
+        */
+       while (work-- > 0) {
+               tmp = readl(port_mmio + PORT_CMD);
+               if ((tmp & PORT_CMD_LIST_ON) == 0)
+                       break;
+               udelay(10);
+       }
+
+       if (!work) {
+               /*
+                * We need to do a port reset / HBA reset here
+                */
+               return -EBUSY;
+       }
+
+       /*
+        * Start DMA
+        */
+       tmp |= PORT_CMD_START;
+       writel(tmp, port_mmio + PORT_CMD);
+       readl(port_mmio + PORT_CMD); /* flush */
+
+       return 0;
+}
+
+static int ahci_stop_fis_rx(void __iomem *port_mmio)
+{
+       u32 tmp;
+       int work = 1000;
+
+       /*
+        * Get current status
+        */
+       tmp = readl(port_mmio + PORT_CMD);
+
+       /* Check if FIS RX is already disabled */
+       if ((tmp & PORT_CMD_FIS_RX) == 0)
+               return 0;
+
+       /*
+        * AHCI Rev 1.1 section 10.3.2
+        * Software shall not clear PxCMD.FRE while
+        * PxCMD.ST or PxCMD.CR is set to '1'
+        */
+       if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_START)) {
+               return -EPERM;
+       }
+
+       /*
+        * Disable FIS reception
+        *
+        * AHCI Rev 1.1 Section 10.1.2:
+        * If PxCMD.FRE is set to '1', software should clear it
+        * to '0' and wait at least 500 milliseconds for PxCMD.FR
+        * to return '0' when read. If PxCMD.FR does not clear
+        * '0' correctly, then software may attempt a port reset
+        * of a full HBA reset to recover.
+        */
+       tmp &= ~(PORT_CMD_FIS_RX);
+       writel(tmp, port_mmio + PORT_CMD);
+
+       mdelay(500);
+       work = 1000;
+       while (work-- > 0) {
+               tmp = readl(port_mmio + PORT_CMD);
+               if ((tmp & PORT_CMD_FIS_ON) == 0)
+                       return 0;
+               udelay(10);
+       }
+
+       return -EBUSY;
+}
+
+static void ahci_start_fis_rx(void __iomem *port_mmio,
+                             struct ahci_port_priv *pp,
+                             struct ahci_host_priv *hpriv)
+{
+       u32 tmp;
+
+       /*
+        * Set FIS registers
+        */
+       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);
+       readl(port_mmio + PORT_LST_ADDR); /* flush */
+
+       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);
+       readl(port_mmio + PORT_FIS_ADDR); /* flush */
+
+       /*
+        * Enable FIS reception
+        */
+       tmp = readl(port_mmio + PORT_CMD);
+       tmp |= PORT_CMD_FIS_RX;
+       writel(tmp, port_mmio + PORT_CMD);
+       readl(port_mmio + PORT_CMD); /* flush */
+}
+
+static int ahci_port_standby(void __iomem *port_mmio, u32 cap)
+{
+       u32 tmp, scontrol, sstatus;
+
+       tmp = readl(port_mmio + PORT_CMD);
+       /*
+        * AHCI Rev1.1 Section 5.3.2.3:
+        * Software is only allowed to program the PxCMD.FRE,
+        * PxCMD.POD, PxSCTL.DET, and PxCMD.SUD register bits
+        * when PxCMD.ST is set to '0'
+        */
+       if (tmp & PORT_CMD_START)
+               return -EBUSY;
+
+       if (cap & HOST_CAP_SSC) {
+               /*
+                * Enable transitions to slumber mode
+                */
+               scontrol = readl(port_mmio + PORT_SCR_CTL);
+               if ((scontrol & 0x0f00) > 0x100) {
+                       scontrol &= ~0xf00;
+                       writel(scontrol, port_mmio + PORT_SCR_CTL);
+               }
+               /*
+                * Put device into slumber mode
+                */
+               tmp |= PORT_CMD_ICC_SLUMBER;
+               writel(tmp, port_mmio + PORT_CMD);
+               tmp = readl(port_mmio + PORT_CMD);
+
+               /*
+                * Actually, we should wait for the device to
+                * enter slumber mode by checking
+                * sstatus & 0xf00 == 6
+                */
+               sstatus = readl(port_mmio + PORT_SCR_STAT);
+       }
+
+       /*
+        * Put device into listen mode
+        */
+       scontrol = readl(port_mmio + PORT_SCR_CTL);
+       scontrol &= ~0xf;
+       writel(scontrol, port_mmio + PORT_SCR_CTL);
+
+       tmp = readl(port_mmio + PORT_CMD);
+       if (cap & HOST_CAP_SSS) {
+               /*
+                * Spin down the device for staggered spin-up support
+                */
+               tmp &= ~PORT_CMD_SPIN_UP;
+               writel(tmp, port_mmio + PORT_CMD);
+               readl(port_mmio + PORT_CMD); /* flush */
+       }
+
+       return 0;
+}
+
+static int ahci_port_spinup(void __iomem *port_mmio, u32 cap)
+{
+       u32 tmp;
+
+       tmp = readl(port_mmio + PORT_CMD);
+       /*
+        * AHCI Rev1.1 Section 5.3.2.3:
+        * Software is only allowed to program the PxCMD.FRE,
+        * PxCMD.POD, PxSCTL.DET, and PxCMD.SUD register bits
+        * when PxCMD.ST is set to '0'
+        */
+       if (tmp & PORT_CMD_START)
+               return -EBUSY;
+
+       /*
+        * Power on device if supported
+        */
+       if (tmp & PORT_CMD_CPD) {
+               tmp |= PORT_CMD_POWER_ON;
+               writel(tmp, port_mmio + PORT_CMD);
+               tmp = readl(port_mmio + PORT_CMD);
+       }
+
+       /*
+        * Spin up device
+        */
+       if (cap & HOST_CAP_SSS) {
+               tmp |= PORT_CMD_SPIN_UP;
+               writel(tmp, port_mmio + PORT_CMD);
+               tmp = readl(port_mmio + PORT_CMD);
+       }
+
+       if ((tmp & PORT_CMD_ICC_MASK) != PORT_CMD_ICC_ACTIVE) {
+               tmp |= PORT_CMD_ICC_ACTIVE;
+               writel(tmp, port_mmio + PORT_CMD);
+               tmp = readl(port_mmio + PORT_CMD);
+       }
+
+       return 0;
+}
+
+static void ahci_port_disable(struct ata_port *ap)
+{
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
+
+       ata_port_disable(ap);
+
+       hpriv->dev_map &= ~(1 << ap->port_no);
+}
+
+static unsigned int ahci_dev_classify(struct ata_port *ap)
+{
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+       struct ata_taskfile tf;
+       u32 tmp;
 
        tmp = readl(port_mmio + PORT_SIG);
        tf.lbah         = (tmp >> 24)   & 0xff;
@@ -454,23 +841,206 @@ static void ahci_phy_reset(struct ata_port *ap)
        tf.lbal         = (tmp >> 8)    & 0xff;
        tf.nsect        = (tmp)         & 0xff;
 
-       dev->class = ata_dev_classify(&tf);
-       if (!ata_dev_present(dev))
-               ata_port_disable(ap);
+       return ata_dev_classify(&tf);
 }
 
-static u8 ahci_check_status(struct ata_port *ap)
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
+{
+       pp->cmd_slot[0].opts = cpu_to_le32(opts);
+       pp->cmd_slot[0].status = 0;
+       pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
+       pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+}
+
+static int ahci_poll_register(void __iomem *reg, u32 mask, u32 val,
+                             unsigned long interval_msec,
+                             unsigned long timeout_msec)
 {
-       void *mmio = (void *) ap->ioaddr.cmd_addr;
+       unsigned long timeout;
+       u32 tmp;
 
-       return readl(mmio + PORT_TFDATA) & 0xFF;
+       timeout = jiffies + (timeout_msec * HZ) / 1000;
+       do {
+               tmp = readl(reg);
+               if ((tmp & mask) == val)
+                       return 0;
+               msleep(interval_msec);
+       } while (time_before(jiffies, timeout));
+
+       return -1;
 }
 
-static u8 ahci_check_err(struct ata_port *ap)
+static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
 {
-       void *mmio = (void *) ap->ioaddr.cmd_addr;
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
+       struct ahci_port_priv *pp = ap->private_data;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       const u32 cmd_fis_len = 5; /* five dwords */
+       const char *reason = NULL;
+       struct ata_taskfile tf;
+       u8 *fis;
+       int rc;
 
-       return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF;
+       DPRINTK("ENTER\n");
+
+       /* 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 */
+       ahci_tf_read(ap, &tf);
+       if (tf.command & (ATA_BUSY | ATA_DRQ)) {
+               u32 tmp;
+
+               if (!(hpriv->cap & HOST_CAP_CLO)) {
+                       rc = -EIO;
+                       reason = "port busy but no CLO";
+                       goto fail_restart;
+               }
+
+               tmp = readl(port_mmio + PORT_CMD);
+               tmp |= PORT_CMD_CLO;
+               writel(tmp, port_mmio + PORT_CMD);
+               readl(port_mmio + PORT_CMD); /* flush */
+
+               if (ahci_poll_register(port_mmio + PORT_CMD, PORT_CMD_CLO, 0x0,
+                                      1, 500)) {
+                       rc = -EIO;
+                       reason = "CLO failed";
+                       goto fail_restart;
+               }
+       }
+
+       /* restart engine */
+       ahci_start_engine(port_mmio);
+
+       ata_tf_init(ap, &tf, 0);
+       fis = pp->cmd_tbl;
+
+       /* issue the first D2H Register FIS */
+       ahci_fill_cmd_slot(pp, cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+
+       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 */
+
+       if (ahci_poll_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x0, 1, 500)) {
+               rc = -EIO;
+               reason = "1st FIS failed";
+               goto fail;
+       }
+
+       /* spec says at least 5us, but be generous and sleep for 1ms */
+       msleep(1);
+
+       /* issue the second D2H Register FIS */
+       ahci_fill_cmd_slot(pp, 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 */
+
+       /* spec mandates ">= 2ms" before checking status.
+        * We wait 150ms, because that was the magic delay used for
+        * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+        * between when the ATA command register is written, and then
+        * status is checked.  Because waiting for "a while" before
+        * checking status is fine, post SRST, we perform this magic
+        * delay here as well.
+        */
+       msleep(150);
+
+       *class = ATA_DEV_NONE;
+       if (sata_dev_present(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);
+       }
+
+       DPRINTK("EXIT, class=%u\n", *class);
+       return 0;
+
+ fail_restart:
+       ahci_start_engine(port_mmio);
+ fail:
+       if (verbose)
+               printk(KERN_ERR "ata%u: softreset failed (%s)\n",
+                      ap->id, reason);
+       else
+               DPRINTK("EXIT, rc=%d reason=\"%s\"\n", rc, reason);
+       return rc;
+}
+
+static int ahci_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
+       int rc;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+
+       DPRINTK("ENTER\n");
+
+       ahci_stop_engine(port_mmio);
+       rc = sata_std_hardreset(ap, verbose, class);
+       ahci_start_engine(port_mmio);
+
+       if (rc == 0)
+               *class = ahci_dev_classify(ap);
+       if (*class == ATA_DEV_UNKNOWN)
+               *class = ATA_DEV_NONE;
+
+       DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+       return rc;
+}
+
+static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+{
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
+       u32 new_tmp, tmp;
+
+       ata_std_postreset(ap, class);
+
+       /* Make sure port's ATAPI bit is set appropriately */
+       new_tmp = tmp = readl(port_mmio + PORT_CMD);
+       if (*class == ATA_DEV_ATAPI)
+               new_tmp |= PORT_CMD_ATAPI;
+       else
+               new_tmp &= ~PORT_CMD_ATAPI;
+       if (new_tmp != tmp) {
+               writel(new_tmp, port_mmio + PORT_CMD);
+               readl(port_mmio + PORT_CMD); /* flush */
+       }
+
+       if (*class != ATA_DEV_NONE)
+               hpriv->dev_map |= (1 << ap->port_no);
+}
+
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+       return ata_drive_probe_reset(ap, ata_std_probeinit,
+                                    ahci_softreset, ahci_hardreset,
+                                    ahci_postreset, classes);
+}
+
+static u8 ahci_check_status(struct ata_port *ap)
+{
+       void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+
+       return readl(mmio + PORT_TFDATA) & 0xFF;
 }
 
 static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -481,95 +1051,91 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
        ata_tf_from_fis(d2h_fis, tf);
 }
 
-static void ahci_fill_sg(struct ata_queued_cmd *qc)
+static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc)
 {
        struct ahci_port_priv *pp = qc->ap->private_data;
-       unsigned int i;
+       struct scatterlist *sg;
+       struct ahci_sg *ahci_sg;
+       unsigned int n_sg = 0;
 
        VPRINTK("ENTER\n");
 
        /*
         * Next, the S/G list.
         */
-       for (i = 0; i < qc->n_elem; i++) {
-               u32 sg_len;
-               dma_addr_t addr;
+       ahci_sg = pp->cmd_tbl_sg;
+       ata_for_each_sg(sg, qc) {
+               dma_addr_t addr = sg_dma_address(sg);
+               u32 sg_len = sg_dma_len(sg);
 
-               addr = sg_dma_address(&qc->sg[i]);
-               sg_len = sg_dma_len(&qc->sg[i]);
+               ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
+               ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
+               ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
 
-               pp->cmd_tbl_sg[i].addr = cpu_to_le32(addr & 0xffffffff);
-               pp->cmd_tbl_sg[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
-               pp->cmd_tbl_sg[i].flags_size = cpu_to_le32(sg_len - 1);
+               ahci_sg++;
+               n_sg++;
        }
+
+       return n_sg;
 }
 
 static void ahci_qc_prep(struct ata_queued_cmd *qc)
 {
-       struct ahci_port_priv *pp = qc->ap->private_data;
+       struct ata_port *ap = qc->ap;
+       struct ahci_port_priv *pp = ap->private_data;
+       int is_atapi = is_atapi_taskfile(&qc->tf);
        u32 opts;
        const u32 cmd_fis_len = 5; /* five dwords */
+       unsigned int n_elem;
 
        /*
-        * Fill in command slot information (currently only one slot,
-        * slot 0, is currently since we don't do queueing)
+        * Fill in command table information.  First, the header,
+        * a SATA Register - Host to Device command FIS.
         */
-
-       opts = (qc->n_elem << 16) | cmd_fis_len;
-       if (qc->tf.flags & ATA_TFLAG_WRITE)
-               opts |= AHCI_CMD_WRITE;
-
-       switch (qc->tf.protocol) {
-       case ATA_PROT_ATAPI:
-       case ATA_PROT_ATAPI_NODATA:
-       case ATA_PROT_ATAPI_DMA:
-               opts |= AHCI_CMD_ATAPI;
-               break;
-
-       default:
-               /* do nothing */
-               break;
+       ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
+       if (is_atapi) {
+               memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+               memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
+                      qc->dev->cdb_len);
        }
 
-       pp->cmd_slot[0].opts = cpu_to_le32(opts);
-       pp->cmd_slot[0].status = 0;
-       pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
-       pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+       n_elem = 0;
+       if (qc->flags & ATA_QCFLAG_DMAMAP)
+               n_elem = ahci_fill_sg(qc);
 
        /*
-        * Fill in command table information.  First, the header,
-        * a SATA Register - Host to Device command FIS.
+        * Fill in command slot information.
         */
-       ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
-
-       if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-               return;
+       opts = cmd_fis_len | n_elem << 16;
+       if (qc->tf.flags & ATA_TFLAG_WRITE)
+               opts |= AHCI_CMD_WRITE;
+       if (is_atapi)
+               opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
 
-       ahci_fill_sg(qc);
+       ahci_fill_cmd_slot(pp, opts);
 }
 
-static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
+static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
 {
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        u32 tmp;
-       int work;
 
-       /* stop DMA */
-       tmp = readl(port_mmio + PORT_CMD);
-       tmp &= ~PORT_CMD_START;
-       writel(tmp, port_mmio + PORT_CMD);
+       if ((ap->device[0].class != ATA_DEV_ATAPI) ||
+           ((irq_stat & PORT_IRQ_TF_ERR) == 0))
+               printk(KERN_WARNING "ata%u: port reset, "
+                      "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n",
+                       ap->id,
+                       irq_stat,
+                       readl(mmio + HOST_IRQ_STAT),
+                       readl(port_mmio + PORT_IRQ_STAT),
+                       readl(port_mmio + PORT_CMD),
+                       readl(port_mmio + PORT_TFDATA),
+                       readl(port_mmio + PORT_SCR_STAT),
+                       readl(port_mmio + PORT_SCR_ERR));
 
-       /* wait for engine to stop.  TODO: this could be
-        * as long as 500 msec
-        */
-       work = 1000;
-       while (work-- > 0) {
-               tmp = readl(port_mmio + PORT_CMD);
-               if ((tmp & PORT_CMD_LIST_ON) == 0)
-                       break;
-               udelay(10);
-       }
+       /* stop DMA */
+       ahci_stop_engine(port_mmio);
 
        /* clear SATA phy error, if any */
        tmp = readl(port_mmio + PORT_SCR_ERR);
@@ -588,45 +1154,99 @@ static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
        }
 
        /* re-start DMA */
-       tmp = readl(port_mmio + PORT_CMD);
-       tmp |= PORT_CMD_START;
-       writel(tmp, port_mmio + PORT_CMD);
-       readl(port_mmio + PORT_CMD); /* flush */
-
-       printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->id);
+       ahci_start_engine(port_mmio);
 }
 
 static void ahci_eng_timeout(struct ata_port *ap)
 {
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       struct ata_host_set *host_set = ap->host_set;
+       void __iomem *mmio = host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        struct ata_queued_cmd *qc;
+       unsigned long flags;
 
-       DPRINTK("ENTER\n");
+       printk(KERN_WARNING "ata%u: handling error/timeout\n", ap->id);
 
-       ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT));
+       spin_lock_irqsave(&host_set->lock, flags);
 
+       ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
        qc = ata_qc_from_tag(ap, ap->active_tag);
-       if (!qc) {
-               printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-                      ap->id);
-       } else {
-               /* hack alert!  We cannot use the supplied completion
-                * function from inside the ->eh_strategy_handler() thread.
-                * libata is the only user of ->eh_strategy_handler() in
-                * any kernel, so the default scsi_done() assumes it is
-                * not being called from the SCSI EH.
-                */
-               qc->scsidone = scsi_finish_command;
-               ata_qc_complete(qc, ATA_ERR);
+       qc->err_mask |= AC_ERR_TIMEOUT;
+
+       spin_unlock_irqrestore(&host_set->lock, flags);
+
+       ata_eh_qc_complete(qc);
+}
+
+int ahci_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
+{
+       struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
+       struct ata_device *dev = &ap->device[sdev->id];
+       int rc;
+
+       rc = ata_device_suspend(ap, dev, state);
+
+       if (!rc)
+               rc = ahci_port_suspend(ap, state);
+
+       return rc;
+}
+
+int ahci_scsi_device_resume(struct scsi_device *sdev)
+{
+       struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
+       struct ata_device *dev = &ap->device[sdev->id];
+
+       ahci_port_resume(ap);
+
+       return ata_device_resume(ap, dev);
+}
+
+int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct device *dev = pci_dev_to_dev(pdev);
+       struct ata_host_set *host_set = dev_get_drvdata(dev);
+       void __iomem *mmio = host_set->mmio_base;
+       u32 tmp;
+
+       /*
+        * AHCI spec rev1.1 section 8.3.3:
+        * Software must disable interrupts prior to
+        * requesting a transition of the HBA to
+        * D3 state.
+        */
+       tmp = readl(mmio + HOST_CTL);
+       tmp &= ~HOST_IRQ_EN;
+       writel(tmp, mmio + HOST_CTL);
+       tmp = readl(mmio + HOST_CTL); /* flush */
+
+       return ata_pci_device_suspend(pdev, state);
+}
+
+int ahci_pci_device_resume(struct pci_dev *pdev)
+{
+       struct device *dev = pci_dev_to_dev(pdev);
+       struct ata_host_set *host_set = dev_get_drvdata(dev);
+       void __iomem *mmio = host_set->mmio_base;
+       u32 tmp;
+
+       /*
+        * Enabling AHCI mode
+        */
+       tmp = readl(mmio + HOST_CTL);
+       if (!(tmp & HOST_AHCI_EN)) {
+               tmp |= HOST_AHCI_EN;
+               writel(tmp, mmio + HOST_CTL);
+               tmp = readl(mmio + HOST_CTL);
        }
 
+       return ata_pci_device_resume(pdev);
 }
 
 static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
 {
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        u32 status, serr, ci;
 
        serr = readl(port_mmio + PORT_SCR_ERR);
@@ -638,15 +1258,28 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
        ci = readl(port_mmio + PORT_CMD_ISSUE);
        if (likely((ci & 0x1) == 0)) {
                if (qc) {
-                       ata_qc_complete(qc, 0);
+                       WARN_ON(qc->err_mask);
+                       ata_qc_complete(qc);
                        qc = NULL;
                }
        }
 
        if (status & PORT_IRQ_FATAL) {
-               ahci_intr_error(ap, status);
-               if (qc)
-                       ata_qc_complete(qc, ATA_ERR);
+               unsigned int err_mask;
+               if (status & PORT_IRQ_TF_ERR)
+                       err_mask = AC_ERR_DEV;
+               else if (status & PORT_IRQ_IF_ERR)
+                       err_mask = AC_ERR_ATA_BUS;
+               else
+                       err_mask = AC_ERR_HOST_BUS;
+
+               /* command processing has stopped due to error; restart */
+               ahci_restart_port(ap, status);
+
+               if (qc) {
+                       qc->err_mask |= err_mask;
+                       ata_qc_complete(qc);
+               }
        }
 
        return 1;
@@ -662,7 +1295,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
        struct ata_host_set *host_set = dev_instance;
        struct ahci_host_priv *hpriv;
        unsigned int i, handled = 0;
-       void *mmio;
+       void __iomem *mmio;
        u32 irq_stat, irq_ack = 0;
 
        VPRINTK("ENTER\n");
@@ -680,17 +1313,29 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
 
         for (i = 0; i < host_set->n_ports; i++) {
                struct ata_port *ap;
-               u32 tmp;
 
-               VPRINTK("port %u\n", i);
+               if (!(irq_stat & (1 << i)))
+                       continue;
+
                ap = host_set->ports[i];
-               tmp = irq_stat & (1 << i);
-               if (tmp && ap) {
+               if (ap) {
                        struct ata_queued_cmd *qc;
                        qc = ata_qc_from_tag(ap, ap->active_tag);
-                       if (ahci_host_intr(ap, qc))
-                               irq_ack |= (1 << i);
+                       if (!ahci_host_intr(ap, qc))
+                               if (ata_ratelimit())
+                                       dev_printk(KERN_WARNING, host_set->dev,
+                                         "unhandled interrupt on port %u\n",
+                                         i);
+
+                       VPRINTK("port %u\n", i);
+               } else {
+                       VPRINTK("port %u (no irq)\n", i);
+                       if (ata_ratelimit())
+                               dev_printk(KERN_WARNING, host_set->dev,
+                                       "interrupt on disabled port %u\n", i);
                }
+
+               irq_ack |= (1 << i);
        }
 
        if (irq_ack) {
@@ -705,13 +1350,10 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
        return IRQ_RETVAL(handled);
 }
 
-static int ahci_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       void *port_mmio = (void *) ap->ioaddr.cmd_addr;
-
-       writel(1, port_mmio + PORT_SCR_ACT);
-       readl(port_mmio + PORT_SCR_ACT);        /* flush */
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
 
        writel(1, port_mmio + PORT_CMD_ISSUE);
        readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
@@ -738,7 +1380,6 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
        struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
        void __iomem *mmio = probe_ent->mmio_base;
        u32 tmp, cap_save;
-       u16 tmp16;
        unsigned int i, j, using_dac;
        int rc;
        void __iomem *port_mmio;
@@ -761,8 +1402,8 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
 
        tmp = readl(mmio + HOST_CTL);
        if (tmp & HOST_RESET) {
-               printk(KERN_ERR DRV_NAME "(%s): controller reset failed (0x%x)\n",
-                       pci_name(pdev), tmp);
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "controller reset failed (0x%x)\n", tmp);
                return -EIO;
        }
 
@@ -772,12 +1413,17 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
        writel(0xf, mmio + HOST_PORTS_IMPL);
        (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
 
-       pci_read_config_word(pdev, 0x92, &tmp16);
-       tmp16 |= 0xf;
-       pci_write_config_word(pdev, 0x92, tmp16);
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+               u16 tmp16;
+
+               pci_read_config_word(pdev, 0x92, &tmp16);
+               tmp16 |= 0xf;
+               pci_write_config_word(pdev, 0x92, tmp16);
+       }
 
        hpriv->cap = readl(mmio + HOST_CAP);
        hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
+       hpriv->dev_map = 0;
        probe_ent->n_ports = (hpriv->cap & 0x1f) + 1;
 
        VPRINTK("cap 0x%x  port_map 0x%x  n_ports %d\n",
@@ -790,24 +1436,22 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
                if (rc) {
                        rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
                        if (rc) {
-                               printk(KERN_ERR DRV_NAME "(%s): 64-bit DMA enable failed\n",
-                                       pci_name(pdev));
+                               dev_printk(KERN_ERR, &pdev->dev,
+                                          "64-bit DMA enable failed\n");
                                return rc;
                        }
                }
-
-               hpriv->flags |= HOST_CAP_64;
        } else {
                rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc) {
-                       printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n",
-                               pci_name(pdev));
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit DMA enable failed\n");
                        return rc;
                }
                rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc) {
-                       printk(KERN_ERR DRV_NAME "(%s): 32-bit consistent DMA enable failed\n",
-                               pci_name(pdev));
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit consistent DMA enable failed\n");
                        return rc;
                }
        }
@@ -825,23 +1469,29 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
                                (unsigned long) mmio, i);
 
                /* make sure port is not active */
-               tmp = readl(port_mmio + PORT_CMD);
-               VPRINTK("PORT_CMD 0x%x\n", tmp);
-               if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
-                          PORT_CMD_FIS_RX | PORT_CMD_START)) {
-                       tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
-                                PORT_CMD_FIS_RX | PORT_CMD_START);
-                       writel(tmp, port_mmio + PORT_CMD);
-                       readl(port_mmio + PORT_CMD); /* flush */
-
-                       /* spec says 500 msecs for each bit, so
-                        * this is slightly incorrect.
-                        */
-                       msleep(500);
-               }
+               rc = ahci_stop_engine(port_mmio);
+               if (rc)
+                       printk(KERN_WARNING "ata%u: DMA engine busy (rc %d)\n",
+                              i, rc);
+
+               rc = ahci_stop_fis_rx(port_mmio);
+               if (rc)
+                       printk(KERN_WARNING "ata%u: FIS RX not stopped (rc %d)\n",
+                              i, rc);
+
+               /*
+                * Actually, this is wrong again.
+                * AHCI spec says that we first should
+                * enable FIS reception before sending
+                * SPIN_UP to the device ...
+                */
 
                writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
 
+               /*
+                * Wait for the communications link to establish
+                */
+
                j = 0;
                while (j < 100) {
                        msleep(10);
@@ -878,23 +1528,11 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
        return 0;
 }
 
-/* move to PCI layer, integrate w/ MSI stuff */
-static void pci_enable_intx(struct pci_dev *pdev)
-{
-       u16 pci_command;
-
-       pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-       if (pci_command & PCI_COMMAND_INTX_DISABLE) {
-               pci_command &= ~PCI_COMMAND_INTX_DISABLE;
-               pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-       }
-}
-
 static void ahci_print_info(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 *mmio = probe_ent->mmio_base;
+       void __iomem *mmio = probe_ent->mmio_base;
        u32 vers, cap, impl, speed;
        const char *speed_s;
        u16 cc;
@@ -922,10 +1560,10 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
        else
                scc_s = "unknown";
 
-       printk(KERN_INFO DRV_NAME "(%s) AHCI %02x%02x.%02x%02x "
+       dev_printk(KERN_INFO, &pdev->dev,
+               "AHCI %02x%02x.%02x%02x "
                "%u slots %u ports %s Gbps 0x%x impl %s mode\n"
                ,
-               pci_name(pdev),
 
                (vers >> 24) & 0xff,
                (vers >> 16) & 0xff,
@@ -938,11 +1576,11 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
                impl,
                scc_s);
 
-       printk(KERN_INFO DRV_NAME "(%s) flags: "
+       dev_printk(KERN_INFO, &pdev->dev,
+               "flags: "
                "%s%s%s%s%s%s"
                "%s%s%s%s%s%s%s\n"
                ,
-               pci_name(pdev),
 
                cap & (1 << 31) ? "64bit " : "",
                cap & (1 << 30) ? "ncq " : "",
@@ -967,15 +1605,15 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        struct ata_probe_ent *probe_ent = NULL;
        struct ahci_host_priv *hpriv;
        unsigned long base;
-       void *mmio_base;
+       void __iomem *mmio_base;
        unsigned int board_idx = (unsigned int) ent->driver_data;
-       int pci_dev_busy = 0;
+       int have_msi, pci_dev_busy = 0;
        int rc;
 
        VPRINTK("ENTER\n");
 
        if (!printed_version++)
-               printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+               dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
        rc = pci_enable_device(pdev);
        if (rc)
@@ -987,20 +1625,24 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out;
        }
 
-       pci_enable_intx(pdev);
+       if (pci_enable_msi(pdev) == 0)
+               have_msi = 1;
+       else {
+               pci_intx(pdev, 1);
+               have_msi = 0;
+       }
 
        probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
        if (probe_ent == NULL) {
                rc = -ENOMEM;
-               goto err_out_regions;
+               goto err_out_msi;
        }
 
        memset(probe_ent, 0, sizeof(*probe_ent));
        probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
-       mmio_base = ioremap(pci_resource_start(pdev, AHCI_PCI_BAR),
-                           pci_resource_len(pdev, AHCI_PCI_BAR));
+       mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
        if (mmio_base == NULL) {
                rc = -ENOMEM;
                goto err_out_free_ent;
@@ -1025,6 +1667,13 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        probe_ent->mmio_base = mmio_base;
        probe_ent->private_data = hpriv;
 
+       if (have_msi)
+               hpriv->flags |= AHCI_FLAG_MSI;
+
+       /* JMicron-specific fixup: make sure we're in AHCI mode */
+       if (pdev->vendor == 0x197b)
+               pci_write_config_byte(pdev, 0x41, 0xa1);
+
        /* initialize adapter */
        rc = ahci_host_init(probe_ent);
        if (rc)
@@ -1041,10 +1690,14 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 err_out_hpriv:
        kfree(hpriv);
 err_out_iounmap:
-       iounmap(mmio_base);
+       pci_iounmap(pdev, mmio_base);
 err_out_free_ent:
        kfree(probe_ent);
-err_out_regions:
+err_out_msi:
+       if (have_msi)
+               pci_disable_msi(pdev);
+       else
+               pci_intx(pdev, 0);
        pci_release_regions(pdev);
 err_out:
        if (!pci_dev_busy)
@@ -1052,13 +1705,49 @@ err_out:
        return rc;
 }
 
+static void ahci_remove_one (struct pci_dev *pdev)
+{
+       struct device *dev = pci_dev_to_dev(pdev);
+       struct ata_host_set *host_set = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host_set->private_data;
+       struct ata_port *ap;
+       unsigned int i;
+       int have_msi;
+
+       for (i = 0; i < host_set->n_ports; i++) {
+               ap = host_set->ports[i];
+
+               scsi_remove_host(ap->host);
+       }
+
+       have_msi = hpriv->flags & AHCI_FLAG_MSI;
+       free_irq(host_set->irq, host_set);
+
+       for (i = 0; i < host_set->n_ports; i++) {
+               ap = host_set->ports[i];
+
+               ata_scsi_release(ap->host);
+               scsi_host_put(ap->host);
+       }
+
+       kfree(hpriv);
+       pci_iounmap(pdev, host_set->mmio_base);
+       kfree(host_set);
+
+       if (have_msi)
+               pci_disable_msi(pdev);
+       else
+               pci_intx(pdev, 0);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       dev_set_drvdata(dev, NULL);
+}
 
 static int __init ahci_init(void)
 {
        return pci_module_init(&ahci_pci_driver);
 }
 
-
 static void __exit ahci_exit(void)
 {
        pci_unregister_driver(&ahci_pci_driver);
@@ -1069,6 +1758,7 @@ MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("AHCI SATA low-level driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
 
 module_init(ahci_init);
 module_exit(ahci_exit);