AHCI - separate pmreg.h out, always zero the FIS in ahci_ata_get_xfer()
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 16 Jun 2009 19:02:16 +0000 (12:02 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 16 Jun 2009 19:02:16 +0000 (12:02 -0700)
* Separate the register defs for PMs out into pmreg.h, as they are not
  AHCI-specific.

* Always zero the FIS returned by ahic_ata_get_xfer().  Don't let any cruft
  accumulate.

sys/dev/disk/ahci/ahci.c
sys/dev/disk/ahci/ahci.h
sys/dev/disk/ahci/ahci_cam.c
sys/dev/disk/ahci/ahci_pm.c
sys/dev/disk/ahci/pmreg.h [new file with mode: 0644]

index 01222a9..5f258e7 100644 (file)
@@ -436,7 +436,7 @@ ahci_port_init(struct ahci_port *ap, struct ata_port *atx)
                 */
                if (atx) {
                        ahci_pm_read(ap, atx->at_target,
-                                    AHCI_PMREG_SSTS, &data);
+                                    SATA_PMREG_SSTS, &data);
                } else {
                        data = ahci_pread(ap, AHCI_PREG_SSTS);
                }
@@ -616,7 +616,7 @@ ahci_port_state_machine(struct ahci_port *ap, int initial)
         * states already present.
         */
        for (loop = 0; ;++loop) {
-               if (ahci_pm_read(ap, 15, AHCI_PMREG_EINFO, &data)) {
+               if (ahci_pm_read(ap, 15, SATA_PMREG_EINFO, &data)) {
                        kprintf("%s: PM unable to read hot-plug bitmap\n",
                                PORTNAME(ap));
                        break;
@@ -1092,6 +1092,7 @@ ahci_port_softreset(struct ahci_port *ap)
         *        the signature.
         */
        ccb = ahci_get_err_ccb(ap);
+       ccb->ccb_done = ahci_empty_done;
        KKASSERT(ccb->ccb_slot == 1);
        ccb->ccb_xa.at = NULL;
        cmd_slot = ccb->ccb_cmd_hdr;
@@ -1476,6 +1477,7 @@ retry:
         *        the signature.
         */
        ccb = ahci_get_err_ccb(ap);
+       ccb->ccb_done = ahci_empty_done;
        cmd_slot = ccb->ccb_cmd_hdr;
        KKASSERT(ccb->ccb_slot == 1);
 
@@ -3136,6 +3138,7 @@ ahci_ata_get_xfer(struct ahci_port *ap, struct ata_port *at)
        DPRINTF(AHCI_D_XFER, "%s: ahci_ata_get_xfer got slot %d\n",
            PORTNAME(ap), ccb->ccb_slot);
 
+       bzero(ccb->ccb_xa.fis, sizeof(*ccb->ccb_xa.fis));
        ccb->ccb_xa.at = at;
        ccb->ccb_xa.fis->type = ATA_FIS_TYPE_H2D;
 
index f1d201a..967fe20 100644 (file)
@@ -21,6 +21,7 @@
 #else
 #error "build for OS unknown"
 #endif
+#include "pmreg.h"
 #include "atascsi.h"
 
 /* change to AHCI_DEBUG for dmesg spam */
@@ -38,10 +39,8 @@ int ahcidebug = AHCI_D_VERBOSE;
 #define DPRINTF(m, f...)
 #endif
 
-#define AHCI_PCI_BAR           0x24
 #define AHCI_PCI_ATI_SB600_MAGIC       0x40
 #define AHCI_PCI_ATI_SB600_LOCKED      0x01
-#define AHCI_PCI_INTERFACE     0x01
 
 #define AHCI_REG_CAP           0x000 /* HBA Capabilities */
 #define  AHCI_REG_CAP_NP(_r)           (((_r) & 0x1f)+1) /* Number of Ports */
@@ -263,49 +262,6 @@ int ahcidebug = AHCI_D_VERBOSE;
 #define AHCI_PREG_SNTF         0x3c /* SNotification */
 
 /*
- * AHCI port multiplier registers
- */
-#define AHCI_PMREG_SSTS                0       /* use AHCI_PREG_SSTS_ bit defs */
-#define AHCI_PMREG_SERR                1       /* use AHCI_PREG_SERR_ bit defs */
-#define AHCI_PMREG_SCTL                2       /* use AHCI_PREG_SCTL_ bit defs */
-#define AHCI_PMREG_SACT                3       /* (not implemented on PM) */
-
-/*
- * AHCI port multiplier revision information SCR[1] (see ahci_pm_read)
- *
- * Rev 1.1 is the one that should support async notification.
- */
-#define AHCI_PMREV_PM1_0       0x00000002
-#define AHCI_PMREV_PM1_1       0x00000004
-#define AHCI_PFMT_PM_REV       "\20" "\003PM1.1" "\002PM1.0"
-
-/*
- * GSCR[64] and GSCR[96] - Port Multiplier features available and features
- *                        enabled.
- */
-#define AHCI_PMREG_FEA         64
-#define AHCI_PMREG_FEAEN       96              /* (features enabled) */
-#define AHCI_PMFEA_BIST                0x00000001      /* BIST Support */
-#define AHCI_PMFEA_PMREQ       0x00000002      /* Can issue PMREQp to host */
-#define AHCI_PMFEA_DYNSSC      0x00000004      /* Dynamic SSC transmit enab */
-#define AHCI_PMFEA_ASYNCNOTIFY 0x00000008      /* Async notification */
-
-#define AHCI_PFMT_PM_FEA       "\20"                   \
-                               "\004AsyncNotify"       \
-                               "\003DynamicSSC"        \
-                               "\002PMREQ"             \
-                               "\001BIST"
-
-/*
- * Enable generation of async notify events for individual targets
- * via the PMEENA register.  Each bit in PMEINFO is a wire-or of all
- * SERROR bits for that target.  To enable a new notification event
- * the SERROR bits in PMSERROR_REGNO must be cleared.
- */
-#define AHCI_PMREG_EINFO       32              /* error info 16 ports */
-#define AHCI_PMREG_EEENA       33              /* error info enable 16 ports */
-
-/*
  * AHCI mapped structures
  */
 struct ahci_cmd_hdr {
index dbd4171..f0ce536 100644 (file)
@@ -808,7 +808,7 @@ ahci_xpt_action(struct cam_sim *sim, union ccb *ccb)
                ccb->cpi.unit_number = cam_sim_unit(sim);
                ccb->cpi.bus_id = cam_sim_bus(sim);
                ccb->cpi.base_transfer_speed = 150000;
-               ccb->cpi.transport = XPORT_AHCI;
+               ccb->cpi.transport = XPORT_SATA;
                ccb->cpi.transport_version = 1;
                ccb->cpi.protocol = PROTO_SCSI;
                ccb->cpi.protocol_version = SCSI_REV_2;
@@ -864,7 +864,7 @@ ahci_xpt_action(struct cam_sim *sim, union ccb *ccb)
        case XPT_GET_TRAN_SETTINGS:
                ccb->cts.protocol = PROTO_SCSI;
                ccb->cts.protocol_version = SCSI_REV_2;
-               ccb->cts.transport = XPORT_AHCI;
+               ccb->cts.transport = XPORT_SATA;
                ccb->cts.transport_version = XPORT_VERSION_UNSPECIFIED;
                ccb->cts.proto_specific.valid = 0;
                ccb->cts.xport_specific.valid = 0;
index d6f97fd..3925314 100644 (file)
@@ -62,24 +62,24 @@ ahci_pm_identify(struct ahci_port *ap)
        kprintf("%s: Port multiplier: chip=%08x rev=0x%b nports=%d\n",
                PORTNAME(ap),
                chipid,
-               rev, AHCI_PFMT_PM_REV,
+               rev, SATA_PFMT_PM_REV,
                nports);
        ap->ap_pmcount = nports;
 
-       if (ahci_pm_read(ap, 15, AHCI_PMREG_FEA, &data1)) {
+       if (ahci_pm_read(ap, 15, SATA_PMREG_FEA, &data1)) {
                kprintf("%s: Port multiplier: Warning, "
                        "cannot read feature register\n", PORTNAME(ap));
        } else {
                kprintf("%s: Port multiplier features: 0x%b\n",
                        PORTNAME(ap),
                        data1,
-                       AHCI_PFMT_PM_FEA);
+                       SATA_PFMT_PM_FEA);
        }
-       if (ahci_pm_read(ap, 15, AHCI_PMREG_FEAEN, &data2) == 0) {
+       if (ahci_pm_read(ap, 15, SATA_PMREG_FEAEN, &data2) == 0) {
                kprintf("%s: Port multiplier defaults: 0x%b\n",
                        PORTNAME(ap),
                        data2,
-                       AHCI_PFMT_PM_FEA);
+                       SATA_PFMT_PM_FEA);
        }
 
        /*
@@ -89,14 +89,14 @@ ahci_pm_identify(struct ahci_port *ap)
         * (or is supposed to anyway).
         */
        if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF) &&
-           (data1 & AHCI_PMFEA_ASYNCNOTIFY)) {
+           (data1 & SATA_PMFEA_ASYNCNOTIFY)) {
                u_int32_t serr_bits = AHCI_PREG_SERR_DIAG_N |
                                      AHCI_PREG_SERR_DIAG_X;
-               data2 |= AHCI_PMFEA_ASYNCNOTIFY;
-               if (ahci_pm_write(ap, 15, AHCI_PMREG_FEAEN, data2)) {
+               data2 |= SATA_PMFEA_ASYNCNOTIFY;
+               if (ahci_pm_write(ap, 15, SATA_PMREG_FEAEN, data2)) {
                        kprintf("%s: Port multiplier: AsyncNotify cannot be "
                                "enabled\n", PORTNAME(ap));
-               } else if (ahci_pm_write(ap, 15, AHCI_PMREG_EEENA, serr_bits)) {
+               } else if (ahci_pm_write(ap, 15, SATA_PMREG_EEENA, serr_bits)) {
                        kprintf("%s: Port mulltiplier: AsyncNotify unable "
                                "to enable error info bits\n", PORTNAME(ap));
                } else {
@@ -138,9 +138,9 @@ ahci_pm_hardreset(struct ahci_port *ap, int target, int hard)
        data = AHCI_PREG_SCTL_IPM_DISABLED;
        if (hard == 2)
                data |= AHCI_PREG_SCTL_DET_DISABLE;
-       if (ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1))
+       if (ahci_pm_write(ap, target, SATA_PMREG_SERR, -1))
                goto err;
-       if (ahci_pm_write(ap, target, AHCI_PMREG_SCTL, data))
+       if (ahci_pm_write(ap, target, SATA_PMREG_SCTL, data))
                goto err;
        ahci_os_sleep(10);
 
@@ -157,7 +157,7 @@ ahci_pm_hardreset(struct ahci_port *ap, int target, int hard)
        } else {
                data |= AHCI_PREG_SCTL_SPD_ANY;
        }
-       if (ahci_pm_write(ap, target, AHCI_PMREG_SCTL, data))
+       if (ahci_pm_write(ap, target, SATA_PMREG_SCTL, data))
                goto err;
 
        /*
@@ -175,9 +175,9 @@ ahci_pm_hardreset(struct ahci_port *ap, int target, int hard)
        /*
         * Flush any status, then clear DET to initiate negotiation.
         */
-       ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1);
+       ahci_pm_write(ap, target, SATA_PMREG_SERR, -1);
        data = AHCI_PREG_SCTL_IPM_DISABLED | AHCI_PREG_SCTL_DET_NONE;
-       if (ahci_pm_write(ap, target, AHCI_PMREG_SCTL, data))
+       if (ahci_pm_write(ap, target, SATA_PMREG_SCTL, data))
                goto err;
 
        /*
@@ -188,7 +188,7 @@ ahci_pm_hardreset(struct ahci_port *ap, int target, int hard)
         * cycled the phy and probably caused another PRCS interrupt.
         */
        for (loop = 3; loop; --loop) {
-               if (ahci_pm_read(ap, target, AHCI_PMREG_SSTS, &data))
+               if (ahci_pm_read(ap, target, SATA_PMREG_SSTS, &data))
                        goto err;
                if (data & AHCI_PREG_SSTS_DET)
                        break;
@@ -206,7 +206,7 @@ ahci_pm_hardreset(struct ahci_port *ap, int target, int hard)
         * to fully negotiate.
         */
        for (loop = 30; loop; --loop) {
-               if (ahci_pm_read(ap, target, AHCI_PMREG_SSTS, &data))
+               if (ahci_pm_read(ap, target, SATA_PMREG_SSTS, &data))
                        goto err;
                if ((data & AHCI_PREG_SSTS_DET) == AHCI_PREG_SSTS_DET_DEV)
                        break;
@@ -281,7 +281,7 @@ retry:
                kprintf("%s: (B)Cannot clear phy status\n",
                        ATANAME(ap ,at));
        }
-       ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1);
+       ahci_pm_write(ap, target, SATA_PMREG_SERR, -1);
 #endif
 
        /*
@@ -386,12 +386,12 @@ retry:
 
        ahci_put_err_ccb(ccb);
        ahci_os_sleep(100);
-       ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1);
+       ahci_pm_write(ap, target, SATA_PMREG_SERR, -1);
        if (ahci_pm_phy_status(ap, target, &data)) {
                kprintf("%s: (C)Cannot clear phy status\n",
                        ATANAME(ap ,at));
        }
-       ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1);
+       ahci_pm_write(ap, target, SATA_PMREG_SERR, -1);
 
        /*
         * Do it again, even if we think we got a good result
@@ -429,7 +429,7 @@ err:
        /*
         * Clear error status so we can detect removal.
         */
-       if (ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1)) {
+       if (ahci_pm_write(ap, target, SATA_PMREG_SERR, -1)) {
                kprintf("%s: ahci_pm_softreset unable to clear SERR\n",
                        ATANAME(ap, at));
                ap->ap_flags &= ~AP_F_IGNORE_IFS;
@@ -443,7 +443,7 @@ err:
 
 /*
  * Return the phy status for a target behind a port multiplier and
- * reset AHCI_PMREG_SERR.
+ * reset SATA_PMREG_SERR.
  *
  * Returned bits follow AHCI_PREG_SSTS bits.  The AHCI_PREG_SSTS_SPD
  * bits can be used to determine the link speed and will be 0 if there
@@ -456,9 +456,9 @@ ahci_pm_phy_status(struct ahci_port *ap, int target, u_int32_t *datap)
 {
        int error;
 
-       error = ahci_pm_read(ap, target, AHCI_PMREG_SSTS, datap);
+       error = ahci_pm_read(ap, target, SATA_PMREG_SSTS, datap);
        if (error == 0)
-               error = ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1);
+               error = ahci_pm_write(ap, target, SATA_PMREG_SERR, -1);
        if (error)
                *datap = 0;
        return(error);
@@ -472,7 +472,6 @@ ahci_pm_set_feature(struct ahci_port *ap, int feature, int enable)
 
        xa = ahci_ata_get_xfer(ap, &ap->ap_ata[15]);
 
-       bzero(xa->fis, sizeof(*xa->fis));
        xa->fis->type = ATA_FIS_TYPE_H2D;
        xa->fis->flags = ATA_H2D_FLAGS_CMD | 15;
        xa->fis->command = enable ? ATA_C_SATA_FEATURE_ENA :
@@ -506,12 +505,12 @@ ahci_pm_check_good(struct ahci_port *ap, int target)
         * It looks like we might have to read the EINFO register
         * to allow the PM to generate a new event.
         */
-       if (ahci_pm_read(ap, 15, AHCI_PMREG_EINFO, &data)) {
+       if (ahci_pm_read(ap, 15, SATA_PMREG_EINFO, &data)) {
                kprintf("%s: Port multiplier EINFO could not be read\n",
                        PORTNAME(ap));
        }
 
-       if (ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1)) {
+       if (ahci_pm_write(ap, target, SATA_PMREG_SERR, -1)) {
                kprintf("%s: Port multiplier: SERR could not be cleared\n",
                        PORTNAME(ap));
        }
@@ -532,7 +531,7 @@ ahci_pm_check_good(struct ahci_port *ap, int target)
        /*
         * Read the detect status
         */
-       if (ahci_pm_read(ap, target, AHCI_PMREG_SSTS, &data)) {
+       if (ahci_pm_read(ap, target, SATA_PMREG_SSTS, &data)) {
                kprintf("%s: Unable to access PM SSTS register target %d\n",
                        PORTNAME(ap), target);
                return;
@@ -567,7 +566,6 @@ ahci_pm_read(struct ahci_port *ap, int target, int which, u_int32_t *datap)
 
        xa = ahci_ata_get_xfer(ap, &ap->ap_ata[15]);
 
-       bzero(xa->fis, sizeof(*xa->fis));
        xa->fis->type = ATA_FIS_TYPE_H2D;
        xa->fis->flags = ATA_H2D_FLAGS_CMD | 15;
        xa->fis->command = ATA_C_READ_PM;
@@ -605,7 +603,6 @@ ahci_pm_write(struct ahci_port *ap, int target, int which, u_int32_t data)
 
        xa = ahci_ata_get_xfer(ap, &ap->ap_ata[15]);
 
-       bzero(xa->fis, sizeof(*xa->fis));
        xa->fis->type = ATA_FIS_TYPE_H2D;
        xa->fis->flags = ATA_H2D_FLAGS_CMD | 15;
        xa->fis->command = ATA_C_WRITE_PM;
diff --git a/sys/dev/disk/ahci/pmreg.h b/sys/dev/disk/ahci/pmreg.h
new file mode 100644 (file)
index 0000000..2a2da5d
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * SATA port multiplier registers
+ */
+#define SATA_PMREG_SSTS                0       /* use SATA_PM_SSTS_ bit defs */
+#define SATA_PMREG_SERR                1       /* use SATA_PM_SERR_ bit defs */
+#define SATA_PMREG_SCTL                2       /* use SATA_PM_SCTL_ bit defs */
+#define SATA_PMREG_SACT                3       /* (not implemented on PM) */
+
+#define  SATA_PM_SSTS_DET              0xf /* Device Detection */
+#define  SATA_PM_SSTS_DET_NONE         0x0
+#define  SATA_PM_SSTS_DET_DEV_NE       0x1
+#define  SATA_PM_SSTS_DET_DEV          0x3
+#define  SATA_PM_SSTS_DET_PHYOFFLINE   0x4
+#define  SATA_PM_SSTS_SPD              0xf0 /* Current Interface Speed */
+#define  SATA_PM_SSTS_SPD_NONE         0x00
+#define  SATA_PM_SSTS_SPD_GEN1         0x10
+#define  SATA_PM_SSTS_SPD_GEN2         0x20
+#define  SATA_PM_SSTS_IPM              0xf00 /* Interface Power Management */
+#define  SATA_PM_SSTS_IPM_NONE         0x000
+#define  SATA_PM_SSTS_IPM_ACTIVE       0x100
+#define  SATA_PM_SSTS_IPM_PARTIAL      0x200
+#define  SATA_PM_SSTS_IPM_SLUMBER      0x600
+
+#define  SATA_PM_SCTL_DET              0xf /* Device Detection */
+#define  SATA_PM_SCTL_DET_NONE         0x0
+#define  SATA_PM_SCTL_DET_INIT         0x1
+#define  SATA_PM_SCTL_DET_DISABLE      0x4
+#define  SATA_PM_SCTL_SPD              0xf0 /* Speed Allowed */
+#define  SATA_PM_SCTL_SPD_ANY          0x00
+#define  SATA_PM_SCTL_SPD_GEN1         0x10
+#define  SATA_PM_SCTL_SPD_GEN2         0x20
+#define  SATA_PM_SCTL_IPM              0xf00 /* Interface Power Management */
+#define  SATA_PM_SCTL_IPM_NONE         0x000
+#define  SATA_PM_SCTL_IPM_NOPARTIAL    0x100
+#define  SATA_PM_SCTL_IPM_NOSLUMBER    0x200
+#define  SATA_PM_SCTL_IPM_DISABLED     0x300
+#define         SATA_PM_SCTL_SPM               0xf000  /* Select Power Management */
+#define         SATA_PM_SCTL_SPM_NONE          0x0000
+#define         SATA_PM_SCTL_SPM_NOPARTIAL     0x1000
+#define         SATA_PM_SCTL_SPM_NOSLUMBER     0x2000
+#define         SATA_PM_SCTL_SPM_DISABLED      0x3000
+#define  SATA_PM_SCTL_PMP              0xf0000 /* Set PM port for xmit FISes */
+#define  SATA_PM_SCTL_PMP_SHIFT                16
+
+#define  SATA_PM_SERR_ERR_I            (1<<0) /* Recovered Data Integrity */
+#define  SATA_PM_SERR_ERR_M            (1<<1) /* Recovered Communications */
+#define  SATA_PM_SERR_ERR_T            (1<<8) /* Transient Data Integrity */
+#define  SATA_PM_SERR_ERR_C            (1<<9) /* Persistent Comm/Data */
+#define  SATA_PM_SERR_ERR_P            (1<<10) /* Protocol */
+#define  SATA_PM_SERR_ERR_E            (1<<11) /* Internal */
+#define  SATA_PM_SERR_DIAG_N           (1<<16) /* PhyRdy Change */
+#define  SATA_PM_SERR_DIAG_I           (1<<17) /* Phy Internal Error */
+#define  SATA_PM_SERR_DIAG_W           (1<<18) /* Comm Wake */
+#define  SATA_PM_SERR_DIAG_B           (1<<19) /* 10B to 8B Decode Error */
+#define  SATA_PM_SERR_DIAG_D           (1<<20) /* Disparity Error */
+#define  SATA_PM_SERR_DIAG_C           (1<<21) /* CRC Error */
+#define  SATA_PM_SERR_DIAG_H           (1<<22) /* Handshake Error */
+#define  SATA_PM_SERR_DIAG_S           (1<<23) /* Link Sequence Error */
+#define  SATA_PM_SERR_DIAG_T           (1<<24) /* Transport State Trans Err */
+#define  SATA_PM_SERR_DIAG_F           (1<<25) /* Unknown FIS Type */
+#define  SATA_PM_SERR_DIAG_X           (1<<26) /* Exchanged */
+
+#define  SATA_PFMT_SERR        "\020"  \
+                       "\033DIAG.X" "\032DIAG.F" "\031DIAG.T" "\030DIAG.S" \
+                       "\027DIAG.H" "\026DIAG.C" "\025DIAG.D" "\024DIAG.B" \
+                       "\023DIAG.W" "\022DIAG.I" "\021DIAG.N"              \
+                       "\014ERR.E" "\013ERR.P" "\012ERR.C" "\011ERR.T"     \
+                       "\002ERR.M" "\001ERR.I"
+
+/*
+ * AHCI port multiplier revision information SCR[1] (see ahci_pm_read)
+ *
+ * Rev 1.1 is the one that should support async notification.
+ */
+#define SATA_PMREV_PM1_0       0x00000002
+#define SATA_PMREV_PM1_1       0x00000004
+#define SATA_PFMT_PM_REV       "\20" "\003PM1.1" "\002PM1.0"
+
+/*
+ * GSCR[64] and GSCR[96] - Port Multiplier features available and features
+ *                        enabled.
+ */
+#define SATA_PMREG_FEA         64
+#define SATA_PMREG_FEAEN       96              /* (features enabled) */
+#define SATA_PMFEA_BIST                0x00000001      /* BIST Support */
+#define SATA_PMFEA_PMREQ       0x00000002      /* Can issue PMREQp to host */
+#define SATA_PMFEA_DYNSSC      0x00000004      /* Dynamic SSC transmit enab */
+#define SATA_PMFEA_ASYNCNOTIFY 0x00000008      /* Async notification */
+
+#define SATA_PFMT_PM_FEA       "\20"                   \
+                               "\004AsyncNotify"       \
+                               "\003DynamicSSC"        \
+                               "\002PMREQ"             \
+                               "\001BIST"
+
+/*
+ * Enable generation of async notify events for individual targets
+ * via the PMEENA register.  Each bit in PMEINFO is a wire-or of all
+ * SERROR bits for that target.  To enable a new notification event
+ * the SERROR bits in PMSERROR_REGNO must be cleared.
+ */
+#define SATA_PMREG_EINFO       32              /* error info 16 ports */
+#define SATA_PMREG_EEENA       33              /* error info enable 16 ports */