Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 2 May 2010 12:07:47 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r207499 - in head: sbin/camcontrol sys/cam sys/cam/ata sys/dev/ahci sys/dev/siis
Message-ID:  <201005021207.o42C7l1Y052542@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201005021207.o42C7l1Y052542>