Author: mav
Date: Sun May  2 12:07:47 2010
New Revision: 207499
URL: http://svn.freebsd.org/changeset/base/207499

Log:
  Make SATA XPT negotiate and enable some additional SATA features, such as:
   - device initiated power management (some devices support only this way);
   - Automatic Partial to Slumber Transition (more power saving);
   - DMA auto-activation (expected to slightly improve performance).
  More features could be added later, when hardware supports.

Modified:
  head/sbin/camcontrol/camcontrol.c
  head/sys/cam/ata/ata_pmp.c
  head/sys/cam/ata/ata_xpt.c
  head/sys/cam/cam_ccb.h
  head/sys/dev/ahci/ahci.c
  head/sys/dev/ahci/ahci.h
  head/sys/dev/siis/siis.c
  head/sys/dev/siis/siis.h

Modified: head/sbin/camcontrol/camcontrol.c
==============================================================================
--- head/sbin/camcontrol/camcontrol.c   Sun May  2 11:36:27 2010        
(r207498)
+++ head/sbin/camcontrol/camcontrol.c   Sun May  2 12:07:47 2010        
(r207499)
@@ -2855,6 +2855,10 @@ cts_print(struct cam_device *device, str
                        fprintf(stdout, "%sNumber of tags: %d\n", pathstr,
                                sata->tags);
                }
+               if ((sata->valid & CTS_SATA_VALID_CAPS) != 0) {
+                       fprintf(stdout, "%sSATA capabilities: %08x\n", pathstr,
+                               sata->caps);
+               }
        }
        if (cts->protocol == PROTO_SCSI) {
                struct ccb_trans_settings_scsi *scsi=

Modified: head/sys/cam/ata/ata_pmp.c
==============================================================================
--- head/sys/cam/ata/ata_pmp.c  Sun May  2 11:36:27 2010        (r207498)
+++ head/sys/cam/ata/ata_pmp.c  Sun May  2 12:07:47 2010        (r207499)
@@ -101,6 +101,7 @@ struct pmp_softc {
        int                     events;
 #define PMP_EV_RESET   1
 #define PMP_EV_RESCAN  2
+       u_int                   caps;
        struct task             sysctl_task;
        struct sysctl_ctx_list  sysctl_ctx;
        struct sysctl_oid       *sysctl_tree;
@@ -457,6 +458,14 @@ pmpstart(struct cam_periph *periph, unio
                ata_pm_read_cmd(ataio, 2, 15);
                break;
        case PMP_STATE_PRECONFIG:
+               /* Get/update host SATA capabilities. */
+               bzero(&cts, sizeof(cts));
+               xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
+               cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+               cts.type = CTS_TYPE_CURRENT_SETTINGS;
+               xpt_action((union ccb *)&cts);
+               if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
+                       softc->caps = cts.xport_specific.sata.caps;
                cam_fill_ataio(ataio,
                      pmp_retry_count,
                      pmpdone,
@@ -644,14 +653,16 @@ pmpdone(struct cam_periph *periph, union
                    (done_ccb->ataio.res.lba_mid << 16) +
                    (done_ccb->ataio.res.lba_low << 8) +
                    done_ccb->ataio.res.sector_count;
-               if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) {
+               if (((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) ||
+                   (res & 0x600) != 0) {
                        if (bootverbose) {
                                printf("%s%d: port %d status: %08x\n",
                                    periph->periph_name, periph->unit_number,
                                    softc->pm_step, res);
                        }
-                       /* Report device speed. */
-                       if (xpt_create_path(&dpath, periph,
+                       /* Report device speed if it is online. */
+                       if ((res & 0xf0f) == 0x103 &&
+                           xpt_create_path(&dpath, periph,
                            xpt_path_path_id(periph->path),
                            softc->pm_step, 0) == CAM_REQ_CMP) {
                                bzero(&cts, sizeof(cts));
@@ -660,6 +671,9 @@ pmpdone(struct cam_periph *periph, union
                                cts.type = CTS_TYPE_CURRENT_SETTINGS;
                                cts.xport_specific.sata.revision = (res & 
0x0f0) >> 4;
                                cts.xport_specific.sata.valid = 
CTS_SATA_VALID_REVISION;
+                               cts.xport_specific.sata.caps = softc->caps &
+                                   (CTS_SATA_CAPS_H_PMREQ | 
CTS_SATA_CAPS_H_DMAAA);
+                               cts.xport_specific.sata.valid |= 
CTS_SATA_VALID_CAPS;
                                xpt_action((union ccb *)&cts);
                                xpt_free_path(dpath);
                        }

Modified: head/sys/cam/ata/ata_xpt.c
==============================================================================
--- head/sys/cam/ata/ata_xpt.c  Sun May  2 11:36:27 2010        (r207498)
+++ head/sys/cam/ata/ata_xpt.c  Sun May  2 12:07:47 2010        (r207499)
@@ -88,6 +88,9 @@ typedef enum {
        PROBE_IDENTIFY,
        PROBE_SPINUP,
        PROBE_SETMODE,
+       PROBE_SETPM,
+       PROBE_SETAPST,
+       PROBE_SETDMAAA,
        PROBE_SET_MULTI,
        PROBE_INQUIRY,
        PROBE_FULL_INQUIRY,
@@ -101,6 +104,9 @@ static char *probe_action_text[] = {
        "PROBE_IDENTIFY",
        "PROBE_SPINUP",
        "PROBE_SETMODE",
+       "PROBE_SETPM",
+       "PROBE_SETAPST",
+       "PROBE_SETDMAAA",
        "PROBE_SET_MULTI",
        "PROBE_INQUIRY",
        "PROBE_FULL_INQUIRY",
@@ -132,6 +138,7 @@ typedef struct {
        uint32_t        pm_prv;
        int             restart;
        int             spinup;
+       u_int           caps;
        struct cam_periph *periph;
 } probe_softc;
 
@@ -393,6 +400,45 @@ negotiate:
                ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
                break;
        }
+       case PROBE_SETPM:
+               cam_fill_ataio(ataio,
+                   1,
+                   probedone,
+                   CAM_DIR_NONE,
+                   0,
+                   NULL,
+                   0,
+                   30*1000);
+               ata_28bit_cmd(ataio, ATA_SETFEATURES,
+                   (softc->caps & CTS_SATA_CAPS_H_PMREQ) ? 0x10 : 0x90,
+                   0, 0x03);
+               break;
+       case PROBE_SETAPST:
+               cam_fill_ataio(ataio,
+                   1,
+                   probedone,
+                   CAM_DIR_NONE,
+                   0,
+                   NULL,
+                   0,
+                   30*1000);
+               ata_28bit_cmd(ataio, ATA_SETFEATURES,
+                   (softc->caps & CTS_SATA_CAPS_H_APST) ? 0x10 : 0x90,
+                   0, 0x07);
+               break;
+       case PROBE_SETDMAAA:
+               cam_fill_ataio(ataio,
+                   1,
+                   probedone,
+                   CAM_DIR_NONE,
+                   0,
+                   NULL,
+                   0,
+                   30*1000);
+               ata_28bit_cmd(ataio, ATA_SETFEATURES,
+                   (softc->caps & CTS_SATA_CAPS_H_DMAAA) ? 0x10 : 0x90,
+                   0, 0x02);
+               break;
        case PROBE_SET_MULTI:
        {
                u_int sectors, bytecount;
@@ -685,6 +731,7 @@ probedone(struct cam_periph *periph, uni
        probe_softc *softc;
        struct cam_path *path;
        u_int32_t  priority;
+       u_int caps;
        int found = 1;
 
        CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
@@ -879,6 +926,67 @@ noerror:
                xpt_schedule(periph, priority);
                return;
        case PROBE_SETMODE:
+               if (path->device->transport != XPORT_SATA)
+                       goto notsata;
+               /* Set supported bits. */
+               bzero(&cts, sizeof(cts));
+               xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
+               cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+               cts.type = CTS_TYPE_CURRENT_SETTINGS;
+               xpt_action((union ccb *)&cts);
+               if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
+                       caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
+               else
+                       caps = 0;
+               if (ident_buf->satacapabilities != 0xffff) {
+                       if (ident_buf->satacapabilities & 
ATA_SUPPORT_IFPWRMNGTRCV)
+                               caps |= CTS_SATA_CAPS_D_PMREQ;
+                       if (ident_buf->satacapabilities & ATA_SUPPORT_HAPST)
+                               caps |= CTS_SATA_CAPS_D_APST;
+               }
+               /* Mask unwanted bits. */
+               bzero(&cts, sizeof(cts));
+               xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
+               cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+               cts.type = CTS_TYPE_USER_SETTINGS;
+               xpt_action((union ccb *)&cts);
+               if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
+                       caps &= cts.xport_specific.sata.caps;
+               /* Store result to SIM. */
+               bzero(&cts, sizeof(cts));
+               xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
+               cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+               cts.type = CTS_TYPE_CURRENT_SETTINGS;
+               cts.xport_specific.sata.caps = caps;
+               cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
+               xpt_action((union ccb *)&cts);
+               softc->caps = caps;
+               if (ident_buf->satasupport & ATA_SUPPORT_IFPWRMNGT) {
+                       PROBE_SET_ACTION(softc, PROBE_SETPM);
+                       xpt_release_ccb(done_ccb);
+                       xpt_schedule(periph, priority);
+                       return;
+               }
+               /* FALLTHROUGH */
+       case PROBE_SETPM:
+               if (ident_buf->satacapabilities != 0xffff &&
+                   ident_buf->satacapabilities & ATA_SUPPORT_DAPST) {
+                       PROBE_SET_ACTION(softc, PROBE_SETAPST);
+                       xpt_release_ccb(done_ccb);
+                       xpt_schedule(periph, priority);
+                       return;
+               }
+               /* FALLTHROUGH */
+       case PROBE_SETAPST:
+               if (ident_buf->satasupport & ATA_SUPPORT_AUTOACTIVATE) {
+                       PROBE_SET_ACTION(softc, PROBE_SETDMAAA);
+                       xpt_release_ccb(done_ccb);
+                       xpt_schedule(periph, priority);
+                       return;
+               }
+               /* FALLTHROUGH */
+       case PROBE_SETDMAAA:
+notsata:
                if (path->device->protocol == PROTO_ATA) {
                        PROBE_SET_ACTION(softc, PROBE_SET_MULTI);
                } else {
@@ -964,6 +1072,35 @@ noerror:
                snprintf(ident_buf->revision, sizeof(ident_buf->revision),
                    "%04x", softc->pm_prv);
                path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
+               /* Set supported bits. */
+               bzero(&cts, sizeof(cts));
+               xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
+               cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+               cts.type = CTS_TYPE_CURRENT_SETTINGS;
+               xpt_action((union ccb *)&cts);
+               if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
+                       caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
+               else
+                       caps = 0;
+               /* All PMPs must support PM requests. */
+               caps |= CTS_SATA_CAPS_D_PMREQ;
+               /* Mask unwanted bits. */
+               bzero(&cts, sizeof(cts));
+               xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
+               cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+               cts.type = CTS_TYPE_USER_SETTINGS;
+               xpt_action((union ccb *)&cts);
+               if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
+                       caps &= cts.xport_specific.sata.caps;
+               /* Store result to SIM. */
+               bzero(&cts, sizeof(cts));
+               xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
+               cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+               cts.type = CTS_TYPE_CURRENT_SETTINGS;
+               cts.xport_specific.sata.caps = caps;
+               cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
+               xpt_action((union ccb *)&cts);
+               softc->caps = caps;
                if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
                        path->device->flags &= ~CAM_DEV_UNCONFIGURED;
                        xpt_acquire_device(path->device);

Modified: head/sys/cam/cam_ccb.h
==============================================================================
--- head/sys/cam/cam_ccb.h      Sun May  2 11:36:27 2010        (r207498)
+++ head/sys/cam/cam_ccb.h      Sun May  2 12:07:47 2010        (r207499)
@@ -837,12 +837,21 @@ struct ccb_trans_settings_sata {
 #define        CTS_SATA_VALID_PM               0x08
 #define        CTS_SATA_VALID_TAGS             0x10
 #define        CTS_SATA_VALID_ATAPI            0x20
+#define        CTS_SATA_VALID_CAPS             0x40
        int             mode;           /* Legacy PATA mode */
        u_int           bytecount;      /* Length of PIO transaction */
        int             revision;       /* SATA revision */
        u_int           pm_present;     /* PM is present (XPT->SIM) */
        u_int           tags;           /* Number of allowed tags */
        u_int           atapi;          /* Length of ATAPI CDB */
+       u_int           caps;           /* Device and host SATA caps. */
+#define        CTS_SATA_CAPS_H                 0x0000ffff
+#define        CTS_SATA_CAPS_H_PMREQ           0x00000001
+#define        CTS_SATA_CAPS_H_APST            0x00000002
+#define        CTS_SATA_CAPS_H_DMAAA           0x00000010 /* Auto-activation */
+#define        CTS_SATA_CAPS_D                 0xffff0000
+#define        CTS_SATA_CAPS_D_PMREQ           0x00010000
+#define        CTS_SATA_CAPS_D_APST            0x00020000
 };
 
 /* Get/Set transfer rate/width/disconnection/tag queueing settings */

Modified: head/sys/dev/ahci/ahci.c
==============================================================================
--- head/sys/dev/ahci/ahci.c    Sun May  2 11:36:27 2010        (r207498)
+++ head/sys/dev/ahci/ahci.c    Sun May  2 12:07:47 2010        (r207499)
@@ -111,6 +111,7 @@ static struct {
 #define AHCI_Q_EDGEIS  64
 #define AHCI_Q_SATA2   128
 #define AHCI_Q_NOBSYRES        256
+#define AHCI_Q_NOAA    512
 } ahci_ids[] = {
        {0x43801002, 0x00, "ATI IXP600",        0},
        {0x43901002, 0x00, "ATI IXP700",        0},
@@ -167,75 +168,75 @@ static struct {
        {0x614511ab, 0x00, "Marvell 88SX6145",  
AHCI_Q_NOFORCE|AHCI_Q_4CH|AHCI_Q_EDGEIS},
        {0x91231b4b, 0x11, "Marvell 88SE912x",  AHCI_Q_NOBSYRES},
        {0x91231b4b, 0x00, "Marvell 88SE912x",  
AHCI_Q_EDGEIS|AHCI_Q_SATA2|AHCI_Q_NOBSYRES},
-       {0x044c10de, 0x00, "NVIDIA MCP65",      0},
-       {0x044d10de, 0x00, "NVIDIA MCP65",      0},
-       {0x044e10de, 0x00, "NVIDIA MCP65",      0},
-       {0x044f10de, 0x00, "NVIDIA MCP65",      0},
-       {0x045c10de, 0x00, "NVIDIA MCP65",      0},
-       {0x045d10de, 0x00, "NVIDIA MCP65",      0},
-       {0x045e10de, 0x00, "NVIDIA MCP65",      0},
-       {0x045f10de, 0x00, "NVIDIA MCP65",      0},
-       {0x055010de, 0x00, "NVIDIA MCP67",      0},
-       {0x055110de, 0x00, "NVIDIA MCP67",      0},
-       {0x055210de, 0x00, "NVIDIA MCP67",      0},
-       {0x055310de, 0x00, "NVIDIA MCP67",      0},
-       {0x055410de, 0x00, "NVIDIA MCP67",      0},
-       {0x055510de, 0x00, "NVIDIA MCP67",      0},
-       {0x055610de, 0x00, "NVIDIA MCP67",      0},
-       {0x055710de, 0x00, "NVIDIA MCP67",      0},
-       {0x055810de, 0x00, "NVIDIA MCP67",      0},
-       {0x055910de, 0x00, "NVIDIA MCP67",      0},
-       {0x055A10de, 0x00, "NVIDIA MCP67",      0},
-       {0x055B10de, 0x00, "NVIDIA MCP67",      0},
-       {0x058410de, 0x00, "NVIDIA MCP67",      0},
-       {0x07f010de, 0x00, "NVIDIA MCP73",      0},
-       {0x07f110de, 0x00, "NVIDIA MCP73",      0},
-       {0x07f210de, 0x00, "NVIDIA MCP73",      0},
-       {0x07f310de, 0x00, "NVIDIA MCP73",      0},
-       {0x07f410de, 0x00, "NVIDIA MCP73",      0},
-       {0x07f510de, 0x00, "NVIDIA MCP73",      0},
-       {0x07f610de, 0x00, "NVIDIA MCP73",      0},
-       {0x07f710de, 0x00, "NVIDIA MCP73",      0},
-       {0x07f810de, 0x00, "NVIDIA MCP73",      0},
-       {0x07f910de, 0x00, "NVIDIA MCP73",      0},
-       {0x07fa10de, 0x00, "NVIDIA MCP73",      0},
-       {0x07fb10de, 0x00, "NVIDIA MCP73",      0},
-       {0x0ad010de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ad110de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ad210de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ad310de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ad410de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ad510de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ad610de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ad710de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ad810de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ad910de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ada10de, 0x00, "NVIDIA MCP77",      0},
-       {0x0adb10de, 0x00, "NVIDIA MCP77",      0},
-       {0x0ab410de, 0x00, "NVIDIA MCP79",      0},
-       {0x0ab510de, 0x00, "NVIDIA MCP79",      0},
-       {0x0ab610de, 0x00, "NVIDIA MCP79",      0},
-       {0x0ab710de, 0x00, "NVIDIA MCP79",      0},
-       {0x0ab810de, 0x00, "NVIDIA MCP79",      0},
-       {0x0ab910de, 0x00, "NVIDIA MCP79",      0},
-       {0x0aba10de, 0x00, "NVIDIA MCP79",      0},
-       {0x0abb10de, 0x00, "NVIDIA MCP79",      0},
-       {0x0abc10de, 0x00, "NVIDIA MCP79",      0},
-       {0x0abd10de, 0x00, "NVIDIA MCP79",      0},
-       {0x0abe10de, 0x00, "NVIDIA MCP79",      0},
-       {0x0abf10de, 0x00, "NVIDIA MCP79",      0},
-       {0x0d8410de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8510de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8610de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8710de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8810de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8910de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8a10de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8b10de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8c10de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8d10de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8e10de, 0x00, "NVIDIA MCP89",      0},
-       {0x0d8f10de, 0x00, "NVIDIA MCP89",      0},
+       {0x044c10de, 0x00, "NVIDIA MCP65",      AHCI_Q_NOAA},
+       {0x044d10de, 0x00, "NVIDIA MCP65",      AHCI_Q_NOAA},
+       {0x044e10de, 0x00, "NVIDIA MCP65",      AHCI_Q_NOAA},
+       {0x044f10de, 0x00, "NVIDIA MCP65",      AHCI_Q_NOAA},
+       {0x045c10de, 0x00, "NVIDIA MCP65",      AHCI_Q_NOAA},
+       {0x045d10de, 0x00, "NVIDIA MCP65",      AHCI_Q_NOAA},
+       {0x045e10de, 0x00, "NVIDIA MCP65",      AHCI_Q_NOAA},
+       {0x045f10de, 0x00, "NVIDIA MCP65",      AHCI_Q_NOAA},
+       {0x055010de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055110de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055210de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055310de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055410de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055510de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055610de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055710de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055810de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055910de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055A10de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x055B10de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x058410de, 0x00, "NVIDIA MCP67",      AHCI_Q_NOAA},
+       {0x07f010de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07f110de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07f210de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07f310de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07f410de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07f510de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07f610de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07f710de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07f810de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07f910de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07fa10de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x07fb10de, 0x00, "NVIDIA MCP73",      AHCI_Q_NOAA},
+       {0x0ad010de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ad110de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ad210de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ad310de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ad410de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ad510de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ad610de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ad710de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ad810de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ad910de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ada10de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0adb10de, 0x00, "NVIDIA MCP77",      AHCI_Q_NOAA},
+       {0x0ab410de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0ab510de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0ab610de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0ab710de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0ab810de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0ab910de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0aba10de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0abb10de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0abc10de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0abd10de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0abe10de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0abf10de, 0x00, "NVIDIA MCP79",      AHCI_Q_NOAA},
+       {0x0d8410de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8510de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8610de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8710de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8810de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8910de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8a10de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8b10de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8c10de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8d10de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8e10de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
+       {0x0d8f10de, 0x00, "NVIDIA MCP89",      AHCI_Q_NOAA},
        {0x33491106, 0x00, "VIA VT8251",        0},
        {0x62871106, 0x00, "VIA VT8251",        0},
        {0x11841039, 0x00, "SiS 966",           0},
@@ -860,7 +861,14 @@ ahci_ch_attach(device_t dev)
                ch->user[i].mode = 0;
                ch->user[i].bytecount = 8192;
                ch->user[i].tags = ch->numslots;
+               ch->user[i].caps = 0;
                ch->curr[i] = ch->user[i];
+               if (ch->pm_level) {
+                       ch->user[i].caps = CTS_SATA_CAPS_H_PMREQ |
+                           CTS_SATA_CAPS_H_APST |
+                           CTS_SATA_CAPS_D_PMREQ | CTS_SATA_CAPS_D_APST;
+               }
+               ch->user[i].caps |= CTS_SATA_CAPS_H_DMAAA;
        }
        rid = ch->unit;
        if (!(ch->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
@@ -1960,7 +1968,8 @@ ahci_end_transaction(struct ahci_slot *s
            et != AHCI_ERR_TIMEOUT)
                ahci_rearm_timeout(dev);
        /* Start PM timer. */
-       if (ch->numrslots == 0 && ch->pm_level > 3) {
+       if (ch->numrslots == 0 && ch->pm_level > 3 &&
+           (ch->curr[ch->pm_present ? 15 : 0].caps & CTS_SATA_CAPS_D_PMREQ)) {
                callout_schedule(&ch->pm_timer,
                    (ch->pm_level == 4) ? hz / 1000 : hz / 8);
        }
@@ -2464,6 +2473,8 @@ ahciaction(struct cam_sim *sim, union cc
                        ch->pm_present = cts->xport_specific.sata.pm_present;
                if (cts->xport_specific.sata.valid & CTS_SATA_VALID_ATAPI)
                        d->atapi = cts->xport_specific.sata.atapi;
+               if (cts->xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
+                       d->caps = cts->xport_specific.sata.caps;
                ccb->ccb_h.status = CAM_REQ_CMP;
                break;
        }
@@ -2496,9 +2507,24 @@ ahciaction(struct cam_sim *sim, union cc
                                cts->xport_specific.sata.valid |=
                                    CTS_SATA_VALID_REVISION;
                        }
+                       cts->xport_specific.sata.caps = d->caps & 
CTS_SATA_CAPS_D;
+                       if (ch->pm_level) {
+                               if (ch->caps & (AHCI_CAP_PSC | AHCI_CAP_SSC))
+                                       cts->xport_specific.sata.caps |= 
CTS_SATA_CAPS_H_PMREQ;
+                               if (ch->caps2 & AHCI_CAP2_APST)
+                                       cts->xport_specific.sata.caps |= 
CTS_SATA_CAPS_H_APST;
+                       }
+                       if ((ch->caps & AHCI_CAP_SNCQ) &&
+                           (ch->quirks & AHCI_Q_NOAA) == 0)
+                               cts->xport_specific.sata.caps |= 
CTS_SATA_CAPS_H_DMAAA;
+                       cts->xport_specific.sata.caps &=
+                           ch->user[ccb->ccb_h.target_id].caps;
+                       cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS;
                } else {
                        cts->xport_specific.sata.revision = d->revision;
                        cts->xport_specific.sata.valid |= 
CTS_SATA_VALID_REVISION;
+                       cts->xport_specific.sata.caps = d->caps;
+                       cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS;
                }
                cts->xport_specific.sata.mode = d->mode;
                cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE;

Modified: head/sys/dev/ahci/ahci.h
==============================================================================
--- head/sys/dev/ahci/ahci.h    Sun May  2 11:36:27 2010        (r207498)
+++ head/sys/dev/ahci/ahci.h    Sun May  2 12:07:47 2010        (r207499)
@@ -372,6 +372,7 @@ struct ahci_device {
        u_int                   bytecount;
        u_int                   atapi;
        u_int                   tags;
+       u_int                   caps;
 };
 
 /* structure describing an ATA channel */

Modified: head/sys/dev/siis/siis.c
==============================================================================
--- head/sys/dev/siis/siis.c    Sun May  2 11:36:27 2010        (r207498)
+++ head/sys/dev/siis/siis.c    Sun May  2 12:07:47 2010        (r207499)
@@ -448,6 +448,8 @@ siis_ch_attach(device_t dev)
                ch->user[i].bytecount = 8192;
                ch->user[i].tags = SIIS_MAX_SLOTS;
                ch->curr[i] = ch->user[i];
+               if (ch->pm_level)
+                       ch->user[i].caps = CTS_SATA_CAPS_H_PMREQ;
        }
        mtx_init(&ch->mtx, "SIIS channel lock", NULL, MTX_DEF);
        rid = ch->unit;
@@ -1697,6 +1699,8 @@ siisaction(struct cam_sim *sim, union cc
                }
                if (cts->xport_specific.sata.valid & CTS_SATA_VALID_TAGS)
                        d->atapi = cts->xport_specific.sata.atapi;
+               if (cts->xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
+                       d->caps = cts->xport_specific.sata.caps;
                ccb->ccb_h.status = CAM_REQ_CMP;
                break;
        }
@@ -1729,9 +1733,17 @@ siisaction(struct cam_sim *sim, union cc
                                cts->xport_specific.sata.valid |=
                                    CTS_SATA_VALID_REVISION;
                        }
+                       cts->xport_specific.sata.caps = d->caps & 
CTS_SATA_CAPS_D;
+                       if (ch->pm_level)
+                               cts->xport_specific.sata.caps |= 
CTS_SATA_CAPS_H_PMREQ;
+                       cts->xport_specific.sata.caps &=
+                           ch->user[ccb->ccb_h.target_id].caps;
+                       cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS;
                } else {
                        cts->xport_specific.sata.revision = d->revision;
                        cts->xport_specific.sata.valid |= 
CTS_SATA_VALID_REVISION;
+                       cts->xport_specific.sata.caps = d->caps;
+                       cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS;
                }
                cts->xport_specific.sata.mode = d->mode;
                cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE;

Modified: head/sys/dev/siis/siis.h
==============================================================================
--- head/sys/dev/siis/siis.h    Sun May  2 11:36:27 2010        (r207498)
+++ head/sys/dev/siis/siis.h    Sun May  2 12:07:47 2010        (r207499)
@@ -358,6 +358,7 @@ struct siis_device {
        u_int                   bytecount;
        u_int                   atapi;
        u_int                   tags;
+       u_int                   caps;
 };
 
 /* structure describing an ATA channel */
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to