Author: mav
Date: Sun Aug 30 15:20:13 2009
New Revision: 196656
URL: http://svn.freebsd.org/changeset/base/196656

Log:
  MFp4:
   - Add Command Completion Coalescing support.
   - Add SNTF support.
   - Add two more power management modes (4, 5), implemented on driver level.
   - Fix interface mode setting.
   - Reduce interface reset time.
   - Do not report meaningless protocol/transport versions.
   - Report CAP2 register content.
   - Some performance optimizations.

Modified:
  head/share/man/man4/ahci.4
  head/sys/dev/ahci/ahci.c
  head/sys/dev/ahci/ahci.h

Modified: head/share/man/man4/ahci.4
==============================================================================
--- head/share/man/man4/ahci.4  Sun Aug 30 15:06:03 2009        (r196655)
+++ head/share/man/man4/ahci.4  Sun Aug 30 15:20:13 2009        (r196656)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd June 26, 2009
+.Dd August 24, 2009
 .Dt AHCI 4
 .Os
 .Sh NAME
@@ -60,6 +60,13 @@ single MSI vector used, if supported (de
 .It 2
 multiple MSI vectors used, if supported;
 .El
+.It Va hint.ahci.X.ccc
+controls Command Completion Coalescing (CCC) usage by the specified controller.
+Non-zero value enables CCC and defines maximum time (in ms), request can wait
+for interrupt, if there are some more requests present on controller queue.
+CCC reduces number of context switches on systems with many parallel requests,
+but it can decrease disk performance on some workloads due to additional
+command latency.
 .It Va hint.ahcich.X.pm_level
 controls SATA interface Power Management for specified channel,
 allowing some power to be saved at the cost of additional command
@@ -74,7 +81,15 @@ device is allowed to initiate PM state c
 host initiates PARTIAL PM state transition every time port becomes idle;
 .It 3
 host initiates SLUMBER PM state transition every time port becomes idle.
+.It 4
+driver initiates PARTIAL PM state transition 1ms after port becomes idle;
+.It 5
+driver initiates SLUMBER PM state transition 125ms after port becomes idle.
 .El
+Some controllers, such as ICH8, do not implement modes 2 and 3 with NCQ used.
+Because of artificial entering latency, performance degradation in modes
+4 and 5 is much smaller then in modes 2 and 3.
+.Pp
 Note that interface Power Management is not compatible with
 device presence detection.
 You will have to reset bus manually on device hot-plug.

Modified: head/sys/dev/ahci/ahci.c
==============================================================================
--- head/sys/dev/ahci/ahci.c    Sun Aug 30 15:06:03 2009        (r196655)
+++ head/sys/dev/ahci/ahci.c    Sun Aug 30 15:20:13 2009        (r196656)
@@ -63,6 +63,7 @@ static int ahci_suspend(device_t dev);
 static int ahci_resume(device_t dev);
 static int ahci_ch_suspend(device_t dev);
 static int ahci_ch_resume(device_t dev);
+static void ahci_ch_pm(void *arg);
 static void ahci_ch_intr_locked(void *data);
 static void ahci_ch_intr(void *data);
 static int ahci_ctlr_reset(device_t dev);
@@ -121,9 +122,11 @@ ahci_attach(device_t dev)
        struct ahci_controller *ctlr = device_get_softc(dev);
        device_t child;
        int     error, unit, speed;
-       u_int32_t version, caps;
+       u_int32_t version;
 
        ctlr->dev = dev;
+       resource_int_value(device_get_name(dev),
+           device_get_unit(dev), "ccc", &ctlr->ccc);
        /* if we have a memory BAR(5) we are likely on an AHCI part */
        ctlr->r_rid = PCIR_BAR(5);
        if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
@@ -160,41 +163,49 @@ ahci_attach(device_t dev)
        }
        /* Announce HW capabilities. */
        version = ATA_INL(ctlr->r_mem, AHCI_VS);
-       caps = ATA_INL(ctlr->r_mem, AHCI_CAP);
-       speed = (caps & AHCI_CAP_ISS) >> AHCI_CAP_ISS_SHIFT;
+       ctlr->caps = ATA_INL(ctlr->r_mem, AHCI_CAP);
+       if (version >= 0x00010020)
+               ctlr->caps2 = ATA_INL(ctlr->r_mem, AHCI_CAP2);
+       speed = (ctlr->caps & AHCI_CAP_ISS) >> AHCI_CAP_ISS_SHIFT;
        device_printf(dev,
                    "AHCI v%x.%02x with %d %sGbps ports, Port Multiplier %s\n",
                    ((version >> 20) & 0xf0) + ((version >> 16) & 0x0f),
                    ((version >> 4) & 0xf0) + (version & 0x0f),
-                   (caps & AHCI_CAP_NPMASK) + 1,
+                   (ctlr->caps & AHCI_CAP_NPMASK) + 1,
                    ((speed == 1) ? "1.5":((speed == 2) ? "3":
                    ((speed == 3) ? "6":"?"))),
-                   (caps & AHCI_CAP_SPM) ?
+                   (ctlr->caps & AHCI_CAP_SPM) ?
                    "supported" : "not supported");
        if (bootverbose) {
                device_printf(dev, "Caps:%s%s%s%s%s%s%s%s %sGbps",
-                   (caps & AHCI_CAP_64BIT) ? " 64bit":"",
-                   (caps & AHCI_CAP_SNCQ) ? " NCQ":"",
-                   (caps & AHCI_CAP_SSNTF) ? " SNTF":"",
-                   (caps & AHCI_CAP_SMPS) ? " MPS":"",
-                   (caps & AHCI_CAP_SSS) ? " SS":"",
-                   (caps & AHCI_CAP_SALP) ? " ALP":"",
-                   (caps & AHCI_CAP_SAL) ? " AL":"",
-                   (caps & AHCI_CAP_SCLO) ? " CLO":"",
+                   (ctlr->caps & AHCI_CAP_64BIT) ? " 64bit":"",
+                   (ctlr->caps & AHCI_CAP_SNCQ) ? " NCQ":"",
+                   (ctlr->caps & AHCI_CAP_SSNTF) ? " SNTF":"",
+                   (ctlr->caps & AHCI_CAP_SMPS) ? " MPS":"",
+                   (ctlr->caps & AHCI_CAP_SSS) ? " SS":"",
+                   (ctlr->caps & AHCI_CAP_SALP) ? " ALP":"",
+                   (ctlr->caps & AHCI_CAP_SAL) ? " AL":"",
+                   (ctlr->caps & AHCI_CAP_SCLO) ? " CLO":"",
                    ((speed == 1) ? "1.5":((speed == 2) ? "3":
                    ((speed == 3) ? "6":"?"))));
                printf("%s%s%s%s%s%s %dcmd%s%s%s %dports\n",
-                   (caps & AHCI_CAP_SAM) ? " AM":"",
-                   (caps & AHCI_CAP_SPM) ? " PM":"",
-                   (caps & AHCI_CAP_FBSS) ? " FBS":"",
-                   (caps & AHCI_CAP_PMD) ? " PMD":"",
-                   (caps & AHCI_CAP_SSC) ? " SSC":"",
-                   (caps & AHCI_CAP_PSC) ? " PSC":"",
-                   ((caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1,
-                   (caps & AHCI_CAP_CCCS) ? " CCC":"",
-                   (caps & AHCI_CAP_EMS) ? " EM":"",
-                   (caps & AHCI_CAP_SXS) ? " eSATA":"",
-                   (caps & AHCI_CAP_NPMASK) + 1);
+                   (ctlr->caps & AHCI_CAP_SAM) ? " AM":"",
+                   (ctlr->caps & AHCI_CAP_SPM) ? " PM":"",
+                   (ctlr->caps & AHCI_CAP_FBSS) ? " FBS":"",
+                   (ctlr->caps & AHCI_CAP_PMD) ? " PMD":"",
+                   (ctlr->caps & AHCI_CAP_SSC) ? " SSC":"",
+                   (ctlr->caps & AHCI_CAP_PSC) ? " PSC":"",
+                   ((ctlr->caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1,
+                   (ctlr->caps & AHCI_CAP_CCCS) ? " CCC":"",
+                   (ctlr->caps & AHCI_CAP_EMS) ? " EM":"",
+                   (ctlr->caps & AHCI_CAP_SXS) ? " eSATA":"",
+                   (ctlr->caps & AHCI_CAP_NPMASK) + 1);
+       }
+       if (bootverbose && version >= 0x00010020) {
+               device_printf(dev, "Caps2:%s%s%s\n",
+                   (ctlr->caps2 & AHCI_CAP2_APST) ? " APST":"",
+                   (ctlr->caps2 & AHCI_CAP2_NVMP) ? " NVMP":"",
+                   (ctlr->caps2 & AHCI_CAP2_BOH) ? " BOH":"");
        }
        /* Attach all channels on this controller */
        for (unit = 0; unit < ctlr->channels; unit++) {
@@ -266,6 +277,21 @@ ahci_ctlr_reset(device_t dev)
        ATA_OUTL(ctlr->r_mem, AHCI_GHC, AHCI_GHC_AE);
        /* Clear interrupts */
        ATA_OUTL(ctlr->r_mem, AHCI_IS, ATA_INL(ctlr->r_mem, AHCI_IS));
+       /* Configure CCC */
+       if (ctlr->ccc) {
+               ATA_OUTL(ctlr->r_mem, AHCI_CCCP, ATA_INL(ctlr->r_mem, AHCI_PI));
+               ATA_OUTL(ctlr->r_mem, AHCI_CCCC,
+                   (ctlr->ccc << AHCI_CCCC_TV_SHIFT) |
+                   (4 << AHCI_CCCC_CC_SHIFT) |
+                   AHCI_CCCC_EN);
+               ctlr->cccv = (ATA_INL(ctlr->r_mem, AHCI_CCCC) &
+                   AHCI_CCCC_INT_MASK) >> AHCI_CCCC_INT_SHIFT;
+               if (bootverbose) {
+                       device_printf(dev,
+                           "CCC with %dms/4cmd enabled on vector %d\n",
+                           ctlr->ccc, ctlr->cccv);
+               }
+       }
        /* Enable AHCI interrupts */
        ATA_OUTL(ctlr->r_mem, AHCI_GHC,
            ATA_INL(ctlr->r_mem, AHCI_GHC) | AHCI_GHC_IE);
@@ -326,7 +352,8 @@ ahci_setup_interrupt(device_t dev)
        for (i = 0; i < ctlr->numirqs; i++) {
                ctlr->irqs[i].ctlr = ctlr;
                ctlr->irqs[i].r_irq_rid = i + (msi ? 1 : 0);
-               if (ctlr->numirqs == 1 || i >= ctlr->channels)
+               if (ctlr->numirqs == 1 || i >= ctlr->channels ||
+                   (ctlr->ccc && i == ctlr->cccv))
                        ctlr->irqs[i].mode = AHCI_IRQ_MODE_ALL;
                else if (i == ctlr->numirqs - 1)
                        ctlr->irqs[i].mode = AHCI_IRQ_MODE_AFTER;
@@ -360,11 +387,16 @@ ahci_intr(void *data)
        void *arg;
        int unit;
 
-       is = ATA_INL(ctlr->r_mem, AHCI_IS);
-       if (irq->mode == AHCI_IRQ_MODE_ALL)
+       if (irq->mode == AHCI_IRQ_MODE_ALL) {
                unit = 0;
-       else    /* AHCI_IRQ_MODE_AFTER */
+               if (ctlr->ccc)
+                       is = ctlr->ichannels;
+               else
+                       is = ATA_INL(ctlr->r_mem, AHCI_IS);
+       } else {        /* AHCI_IRQ_MODE_AFTER */
                unit = irq->r_irq_rid - 1;
+               is = ATA_INL(ctlr->r_mem, AHCI_IS);
+       }
        for (; unit < ctlr->channels; unit++) {
                if ((is & (1 << unit)) != 0 &&
                    (arg = ctlr->interrupt[unit].argument)) {
@@ -523,10 +555,14 @@ ahci_ch_attach(device_t dev)
 
        ch->dev = dev;
        ch->unit = (intptr_t)device_get_ivars(dev);
-       ch->caps = ATA_INL(ctlr->r_mem, AHCI_CAP);
+       ch->caps = ctlr->caps;
+       ch->caps2 = ctlr->caps2;
        ch->numslots = ((ch->caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1,
+       mtx_init(&ch->mtx, "AHCI channel lock", NULL, MTX_DEF);
        resource_int_value(device_get_name(dev),
            device_get_unit(dev), "pm_level", &ch->pm_level);
+       if (ch->pm_level > 3)
+               callout_init_mtx(&ch->pm_timer, &ch->mtx, 0);
        /* Limit speed for my onboard JMicron external port.
         * It is not eSATA really. */
        if (pci_get_devid(ctlr->dev) == 0x2363197b &&
@@ -536,7 +572,6 @@ ahci_ch_attach(device_t dev)
                ch->sata_rev = 1;
        resource_int_value(device_get_name(dev),
            device_get_unit(dev), "sata_rev", &ch->sata_rev);
-       mtx_init(&ch->mtx, "AHCI channel lock", NULL, MTX_DEF);
        rid = ch->unit;
        if (!(ch->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
            &rid, RF_ACTIVE)))
@@ -584,6 +619,11 @@ ahci_ch_attach(device_t dev)
                error = ENXIO;
                goto err3;
        }
+       if (ch->pm_level > 3) {
+               callout_reset(&ch->pm_timer,
+                   (ch->pm_level == 4) ? hz / 1000 : hz / 8,
+                   ahci_ch_pm, dev);
+       }
        mtx_unlock(&ch->mtx);
        return (0);
 
@@ -610,6 +650,8 @@ ahci_ch_detach(device_t dev)
        cam_sim_free(ch->sim, /*free_devq*/TRUE);
        mtx_unlock(&ch->mtx);
 
+       if (ch->pm_level > 3)
+               callout_drain(&ch->pm_timer);
        bus_teardown_intr(dev, ch->r_irq, ch->ih);
        bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq);
 
@@ -661,7 +703,7 @@ ahci_ch_resume(device_t dev)
        /* Activate the channel and power/spin up device */
        ATA_OUTL(ch->r_mem, AHCI_P_CMD,
             (AHCI_P_CMD_ACTIVE | AHCI_P_CMD_POD | AHCI_P_CMD_SUD |
-            ((ch->pm_level > 1) ? AHCI_P_CMD_ALPE : 0) |
+            ((ch->pm_level == 2 || ch->pm_level == 3) ? AHCI_P_CMD_ALPE : 0) |
             ((ch->pm_level > 2) ? AHCI_P_CMD_ASP : 0 )));
        ahci_start_fr(dev);
        ahci_start(dev);
@@ -815,6 +857,7 @@ ahci_slotsfree(device_t dev)
        for (i = 0; i < ch->numslots; i++) {
                struct ahci_slot *slot = &ch->slot[i];
 
+               callout_drain(&slot->timeout);
                if (slot->dma.data_map) {
                        bus_dmamap_destroy(ch->dma.data_tag, 
slot->dma.data_map);
                        slot->dma.data_map = NULL;
@@ -848,6 +891,31 @@ ahci_phy_check_events(device_t dev)
 }
 
 static void
+ahci_notify_events(device_t dev)
+{
+       struct ahci_channel *ch = device_get_softc(dev);
+       struct cam_path *dpath;
+       u_int32_t status;
+       int i;
+
+       status = ATA_INL(ch->r_mem, AHCI_P_SNTF);
+       if (status == 0)
+               return;
+       ATA_OUTL(ch->r_mem, AHCI_P_SNTF, status);
+       if (bootverbose)
+               device_printf(dev, "SNTF 0x%04x\n", status);
+       for (i = 0; i < 16; i++) {
+               if ((status & (1 << i)) == 0)
+                       continue;
+               if (xpt_create_path(&dpath, NULL,
+                   xpt_path_path_id(ch->path), i, 0) == CAM_REQ_CMP) {
+                       xpt_async(AC_SCSI_AEN, dpath, NULL);
+                       xpt_free_path(dpath);
+               }
+       }
+}
+
+static void
 ahci_ch_intr_locked(void *data)
 {
        device_t dev = (device_t)data;
@@ -859,6 +927,23 @@ ahci_ch_intr_locked(void *data)
 }
 
 static void
+ahci_ch_pm(void *arg)
+{
+       device_t dev = (device_t)arg;
+       struct ahci_channel *ch = device_get_softc(dev);
+       uint32_t work;
+
+       if (ch->numrslots != 0)
+               return;
+       work = ATA_INL(ch->r_mem, AHCI_P_CMD);
+       if (ch->pm_level == 4)
+               work |= AHCI_P_CMD_PARTIAL;
+       else
+               work |= AHCI_P_CMD_SLUMBER;
+       ATA_OUTL(ch->r_mem, AHCI_P_CMD, work);
+}
+
+static void
 ahci_ch_intr(void *data)
 {
        device_t dev = (device_t)data;
@@ -869,6 +954,8 @@ ahci_ch_intr(void *data)
 
        /* Read and clear interrupt statuses. */
        istatus = ATA_INL(ch->r_mem, AHCI_P_IS);
+       if (istatus == 0)
+               return;
        ATA_OUTL(ch->r_mem, AHCI_P_IS, istatus);
        /* Read command statuses. */
        cstatus = ATA_INL(ch->r_mem, AHCI_P_CI);
@@ -884,17 +971,16 @@ ahci_ch_intr(void *data)
 //    ATA_INL(ch->r_mem, AHCI_P_SERR));
                ccs = (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CCS_MASK)
                    >> AHCI_P_CMD_CCS_SHIFT;
+               err = ch->rslots & (cstatus | sstatus);
                /* Kick controller into sane state */
                ahci_stop(dev);
                ahci_start(dev);
-               ok = ch->rslots & ~(cstatus | sstatus);
-               err = ch->rslots & (cstatus | sstatus);
        } else {
                ccs = 0;
-               ok = ch->rslots & ~(cstatus | sstatus);
                err = 0;
        }
        /* Complete all successfull commands. */
+       ok = ch->rslots & ~(cstatus | sstatus);
        for (i = 0; i < ch->numslots; i++) {
                if ((ok >> i) & 1)
                        ahci_end_transaction(&ch->slot[i], AHCI_ERR_NONE);
@@ -936,6 +1022,9 @@ ahci_ch_intr(void *data)
                if (ncq_err)
                        ahci_issue_read_log(dev);
        }
+       /* Process NOTIFY events */
+       if ((istatus & AHCI_P_IX_SDB) && (ch->caps & AHCI_CAP_SSNTF))
+               ahci_notify_events(dev);
 }
 
 /* Must be called with channel locked. */
@@ -980,19 +1069,18 @@ ahci_begin_transaction(device_t dev, uni
 
        /* Choose empty slot. */
        tag = ch->lastslot;
-       do {
-               tag++;
-               if (tag >= ch->numslots)
+       while (ch->slot[tag].state != AHCI_SLOT_EMPTY) {
+               if (++tag >= ch->numslots)
                        tag = 0;
-               if (ch->slot[tag].state == AHCI_SLOT_EMPTY)
-                       break;
-       } while (tag != ch->lastslot);
-       if (ch->slot[tag].state != AHCI_SLOT_EMPTY)
-               device_printf(ch->dev, "ALL SLOTS BUSY!\n");
+               KASSERT(tag != ch->lastslot, "ahci: ALL SLOTS BUSY!");
+       }
        ch->lastslot = tag;
        /* Occupy chosen slot. */
        slot = &ch->slot[tag];
        slot->ccb = ccb;
+       /* Stop PM timer. */
+       if (ch->numrslots == 0 && ch->pm_level > 3)
+               callout_stop(&ch->pm_timer);
        /* Update channel stats. */
        ch->numrslots++;
        if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
@@ -1162,6 +1250,10 @@ ahci_timeout(struct ahci_slot *slot)
        struct ahci_channel *ch = device_get_softc(dev);
        int i;
 
+       /* Check for stale timeout. */
+       if (slot->state != AHCI_SLOT_RUNNING)
+               return;
+
        device_printf(dev, "Timeout on slot %d\n", slot->slot);
        /* Kick controller into sane state. */
        ahci_stop(ch->dev);
@@ -1194,8 +1286,6 @@ ahci_end_transaction(struct ahci_slot *s
        struct ahci_channel *ch = device_get_softc(dev);
        union ccb *ccb = slot->ccb;
 
-       /* Cancel command execution timeout */
-       callout_stop(&slot->timeout);
        bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
            BUS_DMASYNC_POSTWRITE);
        /* Read result registers to the result struct
@@ -1302,6 +1392,11 @@ ahci_end_transaction(struct ahci_slot *s
                ahci_begin_transaction(dev, fccb);
                xpt_release_simq(ch->sim, TRUE);
        }
+       /* Start PM timer. */
+       if (ch->numrslots == 0 && ch->pm_level > 3) {
+               callout_schedule(&ch->pm_timer,
+                   (ch->pm_level == 4) ? hz / 1000 : hz / 8);
+       }
 }
 
 static void
@@ -1516,6 +1611,7 @@ static void
 ahci_reset(device_t dev)
 {
        struct ahci_channel *ch = device_get_softc(dev);
+       struct ahci_controller *ctlr = device_get_softc(device_get_parent(dev));
        int i;
 
        if (bootverbose)
@@ -1562,10 +1658,10 @@ ahci_reset(device_t dev)
             (AHCI_P_IX_CPD | AHCI_P_IX_TFE | AHCI_P_IX_HBF |
              AHCI_P_IX_HBD | AHCI_P_IX_IF | AHCI_P_IX_OF |
              ((ch->pm_level == 0) ? AHCI_P_IX_PRC | AHCI_P_IX_PC : 0) |
-             AHCI_P_IX_DP | AHCI_P_IX_UF | AHCI_P_IX_SDB |
-             AHCI_P_IX_DS | AHCI_P_IX_PS | AHCI_P_IX_DHR));
+             AHCI_P_IX_DP | AHCI_P_IX_UF | (ctlr->ccc ? 0 : AHCI_P_IX_SDB) |
+             AHCI_P_IX_DS | AHCI_P_IX_PS | (ctlr->ccc ? 0 : AHCI_P_IX_DHR)));
        if (bootverbose)
-               device_printf(dev, "AHCI reset done: devices=%08x\n", 
ch->devices);
+               device_printf(dev, "AHCI reset done: device found\n");
        /* Tell the XPT about the event */
        xpt_async(AC_BUS_RESET, ch->path, NULL);
 }
@@ -1632,6 +1728,13 @@ ahci_sata_connect(struct ahci_channel *c
                    ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) &&
                    ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE))
                        break;
+               if ((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_OFFLINE) {
+                       if (bootverbose) {
+                               device_printf(ch->dev, "SATA offline 
status=%08x\n",
+                                   status);
+                       }
+                       return (0);
+               }
                DELAY(1000);
        }
        if (timeout >= 100) {
@@ -1664,9 +1767,6 @@ ahci_sata_phy_reset(device_t dev, int qu
 
        if (bootverbose)
                device_printf(dev, "hardware reset ...\n");
-       ATA_OUTL(ch->r_mem, AHCI_P_SCTL, ATA_SC_IPM_DIS_PARTIAL |
-           ATA_SC_IPM_DIS_SLUMBER | ATA_SC_DET_RESET);
-       DELAY(50000);
        if (ch->sata_rev == 1)
                val = ATA_SC_SPD_SPEED_GEN1;
        else if (ch->sata_rev == 2)
@@ -1676,9 +1776,13 @@ ahci_sata_phy_reset(device_t dev, int qu
        else
                val = 0;
        ATA_OUTL(ch->r_mem, AHCI_P_SCTL,
+           ATA_SC_DET_RESET | val |
+           ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER);
+       DELAY(5000);
+       ATA_OUTL(ch->r_mem, AHCI_P_SCTL,
            ATA_SC_DET_IDLE | val | ((ch->pm_level > 0) ? 0 :
            (ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)));
-       DELAY(50000);
+       DELAY(5000);
        return (ahci_sata_connect(ch));
 }
 
@@ -1739,9 +1843,9 @@ ahciaction(struct cam_sim *sim, union cc
                uint32_t status;
 
                cts->protocol = PROTO_ATA;
-               cts->protocol_version = SCSI_REV_2;
+               cts->protocol_version = PROTO_VERSION_UNSPECIFIED;
                cts->transport = XPORT_SATA;
-               cts->transport_version = 2;
+               cts->transport_version = XPORT_VERSION_UNSPECIFIED;
                cts->proto_specific.valid = 0;
                cts->xport_specific.sata.valid = 0;
                if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
@@ -1834,9 +1938,9 @@ ahciaction(struct cam_sim *sim, union cc
                strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
                cpi->unit_number = cam_sim_unit(sim);
                cpi->transport = XPORT_SATA;
-               cpi->transport_version = 2;
+               cpi->transport_version = XPORT_VERSION_UNSPECIFIED;
                cpi->protocol = PROTO_ATA;
-               cpi->protocol_version = SCSI_REV_2;
+               cpi->protocol_version = PROTO_VERSION_UNSPECIFIED;
                cpi->maxio = MAXPHYS;
                cpi->ccb_h.status = CAM_REQ_CMP;
                xpt_done(ccb);

Modified: head/sys/dev/ahci/ahci.h
==============================================================================
--- head/sys/dev/ahci/ahci.h    Sun Aug 30 15:06:03 2009        (r196655)
+++ head/sys/dev/ahci/ahci.h    Sun Aug 30 15:20:13 2009        (r196656)
@@ -176,6 +176,21 @@
 #define AHCI_PI                     0x0c
 #define AHCI_VS                     0x10
 
+#define AHCI_CCCC                   0x14
+#define                AHCI_CCCC_TV_MASK       0xffff0000
+#define                AHCI_CCCC_TV_SHIFT      16
+#define                AHCI_CCCC_CC_MASK       0x0000ff00
+#define                AHCI_CCCC_CC_SHIFT      8
+#define                AHCI_CCCC_INT_MASK      0x000000f8
+#define                AHCI_CCCC_INT_SHIFT     3
+#define                AHCI_CCCC_EN            0x00000001
+#define AHCI_CCCP                   0x18
+
+#define AHCI_CAP2                   0x24
+#define                AHCI_CAP2_BOH   0x00000001
+#define                AHCI_CAP2_NVMP  0x00000002
+#define                AHCI_CAP2_APST  0x00000004
+
 #define AHCI_OFFSET                 0x100
 #define AHCI_STEP                   0x80
 
@@ -336,6 +351,7 @@ struct ahci_channel {
        struct cam_sim          *sim;
        struct cam_path         *path;
        uint32_t                caps;           /* Controller capabilities */
+       uint32_t                caps2;          /* Controller capabilities */
        int                     numslots;       /* Number of present slots */
        int                     pm_level;       /* power management level */
        int                     sata_rev;       /* Maximum allowed SATA 
generation */
@@ -353,6 +369,7 @@ struct ahci_channel {
        int                     lastslot;       /* Last used slot */
        int                     taggedtarget;   /* Last tagged target */
        union ccb               *frozen;        /* Frozen command */
+       struct callout          pm_timer;       /* Power management events */
 };
 
 /* structure describing a AHCI controller */
@@ -371,9 +388,13 @@ struct ahci_controller {
 #define        AHCI_IRQ_MODE_AFTER     1
 #define        AHCI_IRQ_MODE_ONE       2
        } irqs[16];
+       uint32_t                caps;           /* Controller capabilities */
+       uint32_t                caps2;          /* Controller capabilities */
        int                     numirqs;
        int                     channels;
        int                     ichannels;
+       int                     ccc;            /* CCC timeout */
+       int                     cccv;           /* CCC vector */
        struct {
                void                    (*function)(void *);
                void                    *argument;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to