svn commit: r200022 - in stable/8: . contrib/top lib/libusb sbin/camcontrol sys/cam sys/cam/ata sys/dev/ahci sys/dev/siis tools/regression/lib/msun tools/regression/usr.bin/pkill tools/tools/ath/co...

Alexander Motin mav at FreeBSD.org
Wed Dec 2 10:32:34 UTC 2009


Author: mav
Date: Wed Dec  2 10:32:34 2009
New Revision: 200022
URL: http://svn.freebsd.org/changeset/base/200022

Log:
  MFC r199747, r199799, r199821:
  - Extend XPT-SIM transfer settings control API. Now it allows to report to
  SATA SIM number of tags supported by each device, implement ATA mode and
  SATA revision negotiation for both SATA and PATA SIMs.
  - Make ahci(4) and siis(4) to use submitted maximum tag number, when
  scheduling requests. It allows to support NCQ on devices with lower tags
  count then controller supports.
  - Make PMP driver to report attached devices connection speeds.
  - Implement ATA mode negotiation between user settings, device and
  controller capabilities.
  - Improve ATA mode/SATA revision control.

Modified:
  stable/8/sbin/camcontrol/camcontrol.8
  stable/8/sbin/camcontrol/camcontrol.c
  stable/8/sys/cam/ata/ata_all.c
  stable/8/sys/cam/ata/ata_all.h
  stable/8/sys/cam/ata/ata_pmp.c
  stable/8/sys/cam/ata/ata_xpt.c
  stable/8/sys/cam/cam_ccb.h
  stable/8/sys/cam/cam_xpt.c
  stable/8/sys/dev/ahci/ahci.c
  stable/8/sys/dev/ahci/ahci.h
  stable/8/sys/dev/siis/siis.c
  stable/8/sys/dev/siis/siis.h
Directory Properties:
  stable/8/   (props changed)
  stable/8/ObsoleteFiles.inc   (props changed)
  stable/8/UPDATING   (props changed)
  stable/8/bin/csh/   (props changed)
  stable/8/bin/ps/   (props changed)
  stable/8/bin/sh/   (props changed)
  stable/8/cddl/compat/opensolaris/   (props changed)
  stable/8/cddl/contrib/opensolaris/   (props changed)
  stable/8/cddl/lib/libnvpair/   (props changed)
  stable/8/contrib/bind9/   (props changed)
  stable/8/contrib/bzip2/   (props changed)
  stable/8/contrib/cpio/   (props changed)
  stable/8/contrib/csup/   (props changed)
  stable/8/contrib/ee/   (props changed)
  stable/8/contrib/file/   (props changed)
  stable/8/contrib/gdb/   (props changed)
  stable/8/contrib/gdtoa/   (props changed)
  stable/8/contrib/less/   (props changed)
  stable/8/contrib/libpcap/   (props changed)
  stable/8/contrib/ncurses/   (props changed)
  stable/8/contrib/netcat/   (props changed)
  stable/8/contrib/ntp/   (props changed)
  stable/8/contrib/openbsm/   (props changed)
  stable/8/contrib/openpam/   (props changed)
  stable/8/contrib/pf/   (props changed)
  stable/8/contrib/sendmail/   (props changed)
  stable/8/contrib/tcpdump/   (props changed)
  stable/8/contrib/tcsh/   (props changed)
  stable/8/contrib/top/   (props changed)
  stable/8/contrib/top/install-sh   (props changed)
  stable/8/contrib/traceroute/   (props changed)
  stable/8/contrib/wpa/   (props changed)
  stable/8/crypto/openssh/   (props changed)
  stable/8/crypto/openssl/   (props changed)
  stable/8/etc/   (props changed)
  stable/8/games/fortune/   (props changed)
  stable/8/games/fortune/datfiles/   (props changed)
  stable/8/gnu/usr.bin/groff/   (props changed)
  stable/8/gnu/usr.bin/patch/   (props changed)
  stable/8/include/   (props changed)
  stable/8/kerberos5/lib/libgssapi_krb5/   (props changed)
  stable/8/kerberos5/lib/libgssapi_spnego/   (props changed)
  stable/8/lib/libarchive/   (props changed)
  stable/8/lib/libc/   (props changed)
  stable/8/lib/libc/stdtime/   (props changed)
  stable/8/lib/libdevinfo/   (props changed)
  stable/8/lib/libdisk/   (props changed)
  stable/8/lib/libfetch/   (props changed)
  stable/8/lib/libkvm/   (props changed)
  stable/8/lib/libradius/   (props changed)
  stable/8/lib/libstand/   (props changed)
  stable/8/lib/libthr/   (props changed)
  stable/8/lib/libusb/   (props changed)
  stable/8/lib/libusb/usb.h   (props changed)
  stable/8/lib/libutil/   (props changed)
  stable/8/libexec/rtld-elf/   (props changed)
  stable/8/release/   (props changed)
  stable/8/release/doc/   (props changed)
  stable/8/release/doc/en_US.ISO8859-1/hardware/   (props changed)
  stable/8/sbin/   (props changed)
  stable/8/sbin/bsdlabel/   (props changed)
  stable/8/sbin/camcontrol/   (props changed)
  stable/8/sbin/ddb/   (props changed)
  stable/8/sbin/dhclient/   (props changed)
  stable/8/sbin/fsck/   (props changed)
  stable/8/sbin/geom/   (props changed)
  stable/8/sbin/ifconfig/   (props changed)
  stable/8/sbin/ipfw/   (props changed)
  stable/8/sbin/mksnap_ffs/   (props changed)
  stable/8/sbin/mount/   (props changed)
  stable/8/sbin/mount_cd9660/   (props changed)
  stable/8/sbin/mount_nfs/   (props changed)
  stable/8/sbin/umount/   (props changed)
  stable/8/secure/usr.bin/bdes/   (props changed)
  stable/8/share/man/man3/   (props changed)
  stable/8/share/man/man4/   (props changed)
  stable/8/share/man/man5/   (props changed)
  stable/8/share/man/man7/   (props changed)
  stable/8/share/man/man9/   (props changed)
  stable/8/share/misc/   (props changed)
  stable/8/share/timedef/   (props changed)
  stable/8/share/zoneinfo/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)
  stable/8/tools/kerneldoc/subsys/   (props changed)
  stable/8/tools/regression/bin/sh/   (props changed)
  stable/8/tools/regression/lib/msun/test-conj.t   (props changed)
  stable/8/tools/regression/poll/   (props changed)
  stable/8/tools/regression/priv/   (props changed)
  stable/8/tools/regression/usr.bin/pkill/pgrep-_g.t   (props changed)
  stable/8/tools/regression/usr.bin/pkill/pgrep-_s.t   (props changed)
  stable/8/tools/regression/usr.bin/pkill/pkill-_g.t   (props changed)
  stable/8/tools/tools/ath/common/dumpregs.h   (props changed)
  stable/8/tools/tools/ath/common/dumpregs_5210.c   (props changed)
  stable/8/tools/tools/ath/common/dumpregs_5211.c   (props changed)
  stable/8/tools/tools/ath/common/dumpregs_5212.c   (props changed)
  stable/8/tools/tools/ath/common/dumpregs_5416.c   (props changed)
  stable/8/tools/tools/termcap/termcap.pl   (props changed)
  stable/8/tools/tools/vimage/   (props changed)
  stable/8/usr.bin/calendar/calendars/calendar.freebsd   (props changed)
  stable/8/usr.bin/csup/   (props changed)
  stable/8/usr.bin/find/   (props changed)
  stable/8/usr.bin/fstat/   (props changed)
  stable/8/usr.bin/gcore/   (props changed)
  stable/8/usr.bin/kdump/   (props changed)
  stable/8/usr.bin/locale/   (props changed)
  stable/8/usr.bin/look/   (props changed)
  stable/8/usr.bin/netstat/   (props changed)
  stable/8/usr.bin/procstat/   (props changed)
  stable/8/usr.bin/systat/   (props changed)
  stable/8/usr.bin/vmstat/   (props changed)
  stable/8/usr.bin/w/   (props changed)
  stable/8/usr.bin/whois/   (props changed)
  stable/8/usr.sbin/   (props changed)
  stable/8/usr.sbin/acpi/   (props changed)
  stable/8/usr.sbin/arp/   (props changed)
  stable/8/usr.sbin/cdcontrol/   (props changed)
  stable/8/usr.sbin/crashinfo/   (props changed)
  stable/8/usr.sbin/dumpcis/cardinfo.h   (props changed)
  stable/8/usr.sbin/dumpcis/cis.h   (props changed)
  stable/8/usr.sbin/freebsd-update/   (props changed)
  stable/8/usr.sbin/iostat/   (props changed)
  stable/8/usr.sbin/jail/   (props changed)
  stable/8/usr.sbin/jls/   (props changed)
  stable/8/usr.sbin/lpr/   (props changed)
  stable/8/usr.sbin/makefs/ffs/ffs_bswap.c   (props changed)
  stable/8/usr.sbin/makefs/ffs/ffs_subr.c   (props changed)
  stable/8/usr.sbin/makefs/ffs/ufs_bswap.h   (props changed)
  stable/8/usr.sbin/makefs/getid.c   (props changed)
  stable/8/usr.sbin/mfiutil/mfiutil.8   (props changed)
  stable/8/usr.sbin/ndp/   (props changed)
  stable/8/usr.sbin/ntp/   (props changed)
  stable/8/usr.sbin/ppp/   (props changed)
  stable/8/usr.sbin/pstat/   (props changed)
  stable/8/usr.sbin/sysinstall/   (props changed)
  stable/8/usr.sbin/traceroute6/   (props changed)
  stable/8/usr.sbin/usbconfig/   (props changed)
  stable/8/usr.sbin/wpa/   (props changed)
  stable/8/usr.sbin/zic/   (props changed)

Modified: stable/8/sbin/camcontrol/camcontrol.8
==============================================================================
--- stable/8/sbin/camcontrol/camcontrol.8	Wed Dec  2 10:10:37 2009	(r200021)
+++ stable/8/sbin/camcontrol/camcontrol.8	Wed Dec  2 10:32:34 2009	(r200022)
@@ -149,6 +149,7 @@
 .Op generic args
 .Op Fl c
 .Op Fl D Ar enable|disable
+.Op Fl M Ar mode
 .Op Fl O Ar offset
 .Op Fl q
 .Op Fl R Ar syncrate
@@ -705,6 +706,8 @@ Show or set current negotiation settings
 This is the default.
 .It Fl D Ar enable|disable
 Enable or disable disconnection.
+.It Fl M Ar mode
+Set ATA mode.
 .It Fl O Ar offset
 Set the command delay offset.
 .It Fl q

Modified: stable/8/sbin/camcontrol/camcontrol.c
==============================================================================
--- stable/8/sbin/camcontrol/camcontrol.c	Wed Dec  2 10:10:37 2009	(r200021)
+++ stable/8/sbin/camcontrol/camcontrol.c	Wed Dec  2 10:32:34 2009	(r200022)
@@ -125,7 +125,7 @@ struct camcontrol_opts {
 #ifndef MINIMALISTIC
 static const char scsicmd_opts[] = "a:c:i:o:r";
 static const char readdefect_opts[] = "f:GP";
-static const char negotiate_opts[] = "acD:O:qR:T:UW:";
+static const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
 #endif
 
 struct camcontrol_opts option_table[] = {
@@ -226,6 +226,12 @@ static int scsireadcapacity(struct cam_d
 static int atapm(struct cam_device *device, int argc, char **argv,
 			    char *combinedopt, int retry_count, int timeout);
 #endif /* MINIMALISTIC */
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
 
 camcontrol_optret
 getoption(char *arg, cam_cmdmask *cmdnum, cam_argmask *argnum, 
@@ -950,21 +956,27 @@ camxferrate(struct cam_device *device)
 
 		if (sas->valid & CTS_SAS_VALID_SPEED)
 			speed = sas->bitrate;
+	} else if (ccb->cts.transport == XPORT_ATA) {
+		struct ccb_trans_settings_ata *ata =
+		    &ccb->cts.xport_specific.ata;
+
+		if (ata->valid & CTS_ATA_VALID_MODE)
+			speed = ata_mode2speed(ata->mode);
 	} else if (ccb->cts.transport == XPORT_SATA) {
-		struct ccb_trans_settings_sata *sata =
+		struct	ccb_trans_settings_sata *sata =
 		    &ccb->cts.xport_specific.sata;
 
-		if (sata->valid & CTS_SATA_VALID_SPEED)
-			speed = sata->bitrate;
+		if (sata->valid & CTS_SATA_VALID_REVISION)
+			speed = ata_revision2speed(sata->revision);
 	}
 
 	mb = speed / 1000;
 	if (mb > 0) {
-		fprintf(stdout, "%s%d: %d.%03dMB/s transfers ",
+		fprintf(stdout, "%s%d: %d.%03dMB/s transfers",
 			device->device_name, device->dev_unit_num,
 			mb, speed % 1000);
 	} else {
-		fprintf(stdout, "%s%d: %dKB/s transfers ",
+		fprintf(stdout, "%s%d: %dKB/s transfers",
 			device->device_name, device->dev_unit_num,
 			speed);
 	}
@@ -975,7 +987,7 @@ camxferrate(struct cam_device *device)
 
 		if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
 		 && (spi->sync_offset != 0))
-			fprintf(stdout, "(%d.%03dMHz, offset %d", freq / 1000,
+			fprintf(stdout, " (%d.%03dMHz, offset %d", freq / 1000,
 				freq % 1000, spi->sync_offset);
 
 		if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
@@ -995,18 +1007,24 @@ camxferrate(struct cam_device *device)
 		struct ccb_trans_settings_ata *ata =
 		    &ccb->cts.xport_specific.ata;
 
-		if (ata->valid & CTS_ATA_VALID_BYTECOUNT) {
-			fprintf(stdout, "(PIO size %dbytes)",
-			    ata->bytecount);
-		}
+		printf(" (");
+		if (ata->valid & CTS_ATA_VALID_MODE)
+			printf("%s, ", ata_mode2string(ata->mode));
+		if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
+			printf("PIO size %dbytes", ata->bytecount);
+		printf(")");
 	} else if (ccb->cts.transport == XPORT_SATA) {
 		struct ccb_trans_settings_sata *sata =
 		    &ccb->cts.xport_specific.sata;
 
-		if (sata->valid & CTS_SATA_VALID_BYTECOUNT) {
-			fprintf(stdout, "(PIO size %dbytes)",
-			    sata->bytecount);
-		}
+		printf(" (");
+		if (sata->valid & CTS_SATA_VALID_REVISION)
+			printf("SATA %d.x, ", sata->revision);
+		if (sata->valid & CTS_SATA_VALID_MODE)
+			printf("%s, ", ata_mode2string(sata->mode));
+		if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
+			printf("PIO size %dbytes", sata->bytecount);
+		printf(")");
 	}
 
 	if (ccb->cts.protocol == PROTO_SCSI) {
@@ -2757,7 +2775,44 @@ cts_print(struct cam_device *device, str
 				"enabled" : "disabled");
 		}
 	}
+	if (cts->transport == XPORT_ATA) {
+		struct ccb_trans_settings_ata *ata =
+		    &cts->xport_specific.ata;
+
+		if ((ata->valid & CTS_ATA_VALID_MODE) != 0) {
+			fprintf(stdout, "%sATA mode: %s\n", pathstr,
+				ata_mode2string(ata->mode));
+		}
+		if ((ata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) {
+			fprintf(stdout, "%sPIO transaction length: %d\n",
+				pathstr, ata->bytecount);
+		}
+	}
+	if (cts->transport == XPORT_SATA) {
+		struct ccb_trans_settings_sata *sata =
+		    &cts->xport_specific.sata;
 
+		if ((sata->valid & CTS_SATA_VALID_REVISION) != 0) {
+			fprintf(stdout, "%sSATA revision: %d.x\n", pathstr,
+				sata->revision);
+		}
+		if ((sata->valid & CTS_SATA_VALID_MODE) != 0) {
+			fprintf(stdout, "%sATA mode: %s\n", pathstr,
+				ata_mode2string(sata->mode));
+		}
+		if ((sata->valid & CTS_SATA_VALID_BYTECOUNT) != 0) {
+			fprintf(stdout, "%sPIO transaction length: %d\n",
+				pathstr, sata->bytecount);
+		}
+		if ((sata->valid & CTS_SATA_VALID_PM) != 0) {
+			fprintf(stdout, "%sPMP presence: %d\n", pathstr,
+				sata->pm_present);
+		}
+		if ((sata->valid & CTS_SATA_VALID_TAGS) != 0) {
+			fprintf(stdout, "%sNumber of tags: %d\n", pathstr,
+				sata->tags);
+		}
+	}
 	if (cts->protocol == PROTO_SCSI) {
 		struct ccb_trans_settings_scsi *scsi=
 		    &cts->proto_specific.scsi;
@@ -3057,6 +3112,7 @@ ratecontrol(struct cam_device *device, i
 	int user_settings = 0;
 	int retval = 0;
 	int disc_enable = -1, tag_enable = -1;
+	int mode = -1;
 	int offset = -1;
 	double syncrate = -1;
 	int bus_width = -1;
@@ -3065,12 +3121,10 @@ ratecontrol(struct cam_device *device, i
 	struct ccb_pathinq cpi;
 
 	ccb = cam_getccb(device);
-
 	if (ccb == NULL) {
 		warnx("ratecontrol: error allocating ccb");
 		return(1);
 	}
-
 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
 		switch(c){
 		case 'a':
@@ -3091,6 +3145,15 @@ ratecontrol(struct cam_device *device, i
 			}
 			change_settings = 1;
 			break;
+		case 'M':
+			mode = ata_string2mode(optarg);
+			if (mode < 0) {
+				warnx("unknown mode '%s'", optarg);
+				retval = 1;
+				goto ratecontrol_bailout;
+			}
+			change_settings = 1;
+			break;
 		case 'O':
 			offset = strtol(optarg, NULL, 0);
 			if (offset < 0) {
@@ -3105,7 +3168,6 @@ ratecontrol(struct cam_device *device, i
 			break;
 		case 'R':
 			syncrate = atof(optarg);
-
 			if (syncrate < 0) {
 				warnx("sync rate %f is < 0", syncrate);
 				retval = 1;
@@ -3141,17 +3203,14 @@ ratecontrol(struct cam_device *device, i
 			break;
 		}
 	}
-
 	bzero(&(&ccb->ccb_h)[1],
 	      sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
-
 	/*
 	 * Grab path inquiry information, so we can determine whether
 	 * or not the initiator is capable of the things that the user
 	 * requests.
 	 */
 	ccb->ccb_h.func_code = XPT_PATH_INQ;
-
 	if (cam_send_ccb(device, ccb) < 0) {
 		perror("error sending XPT_PATH_INQ CCB");
 		if (arglist & CAM_ARG_VERBOSE) {
@@ -3161,7 +3220,6 @@ ratecontrol(struct cam_device *device, i
 		retval = 1;
 		goto ratecontrol_bailout;
 	}
-
 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
 		warnx("XPT_PATH_INQ CCB failed");
 		if (arglist & CAM_ARG_VERBOSE) {
@@ -3171,17 +3229,14 @@ ratecontrol(struct cam_device *device, i
 		retval = 1;
 		goto ratecontrol_bailout;
 	}
-
 	bcopy(&ccb->cpi, &cpi, sizeof(struct ccb_pathinq));
-
 	bzero(&(&ccb->ccb_h)[1],
 	      sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
-
-	if (quiet == 0)
-		fprintf(stdout, "Current Parameters:\n");
-
+	if (quiet == 0) {
+		fprintf(stdout, "%s parameters:\n",
+		    user_settings ? "User" : "Current");
+	}
 	retval = get_print_cts(device, user_settings, quiet, &ccb->cts);
-
 	if (retval != 0)
 		goto ratecontrol_bailout;
 
@@ -3191,16 +3246,20 @@ ratecontrol(struct cam_device *device, i
 	if (change_settings) {
 		int didsettings = 0;
 		struct ccb_trans_settings_spi *spi = NULL;
+		struct ccb_trans_settings_ata *ata = NULL;
+		struct ccb_trans_settings_sata *sata = NULL;
 		struct ccb_trans_settings_scsi *scsi = NULL;
 
-		if (ccb->cts.transport == XPORT_SPI) {
+		if (ccb->cts.transport == XPORT_SPI)
 			spi = &ccb->cts.xport_specific.spi;
-			spi->valid = 0;
-		}
-		if (ccb->cts.protocol == PROTO_SCSI) {
+		if (ccb->cts.transport == XPORT_ATA)
+			ata = &ccb->cts.xport_specific.ata;
+		if (ccb->cts.transport == XPORT_SATA)
+			sata = &ccb->cts.xport_specific.sata;
+		if (ccb->cts.protocol == PROTO_SCSI)
 			scsi = &ccb->cts.proto_specific.scsi;
-			scsi->valid = 0;
-		}
+		ccb->cts.xport_specific.valid = 0;
+		ccb->cts.proto_specific.valid = 0;
 		if (spi && disc_enable != -1) {
 			spi->valid |= CTS_SPI_VALID_DISC;
 			if (disc_enable == 0)
@@ -3208,7 +3267,6 @@ ratecontrol(struct cam_device *device, i
 			else
 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
 		}
-
 		if (scsi && tag_enable != -1) {
 			if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) {
 				warnx("HBA does not support tagged queueing, "
@@ -3216,21 +3274,16 @@ ratecontrol(struct cam_device *device, i
 				retval = 1;
 				goto ratecontrol_bailout;
 			}
-
 			scsi->valid |= CTS_SCSI_VALID_TQ;
-
 			if (tag_enable == 0)
 				scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
 			else
 				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
 			didsettings++;
 		}
-
 		if (spi && offset != -1) {
 			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
-				warnx("HBA at %s%d is not cable of changing "
-				      "offset", cpi.dev_name,
-				      cpi.unit_number);
+				warnx("HBA is not capable of changing offset");
 				retval = 1;
 				goto ratecontrol_bailout;
 			}
@@ -3238,28 +3291,23 @@ ratecontrol(struct cam_device *device, i
 			spi->sync_offset = offset;
 			didsettings++;
 		}
-
 		if (spi && syncrate != -1) {
 			int prelim_sync_period;
 			u_int freq;
 
 			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
-				warnx("HBA at %s%d is not cable of changing "
-				      "transfer rates", cpi.dev_name,
-				      cpi.unit_number);
+				warnx("HBA is not capable of changing "
+				      "transfer rates");
 				retval = 1;
 				goto ratecontrol_bailout;
 			}
-
 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
-
 			/*
 			 * The sync rate the user gives us is in MHz.
 			 * We need to translate it into KHz for this
 			 * calculation.
 			 */
 			syncrate *= 1000;
-
 			/*
 			 * Next, we calculate a "preliminary" sync period
 			 * in tenths of a nanosecond.
@@ -3268,14 +3316,43 @@ ratecontrol(struct cam_device *device, i
 				prelim_sync_period = 0;
 			else
 				prelim_sync_period = 10000000 / syncrate;
-
 			spi->sync_period =
 				scsi_calc_syncparam(prelim_sync_period);
-
 			freq = scsi_calc_syncsrate(spi->sync_period);
 			didsettings++;
 		}
-
+		if (sata && syncrate != -1) {
+			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
+				warnx("HBA is not capable of changing "
+				      "transfer rates");
+				retval = 1;
+				goto ratecontrol_bailout;
+			}
+			sata->revision = ata_speed2revision(syncrate * 100);
+			if (sata->revision < 0) {
+				warnx("Invalid rate %f", syncrate);
+				retval = 1;
+				goto ratecontrol_bailout;
+			}
+			sata->valid |= CTS_SATA_VALID_REVISION;
+			didsettings++;
+		}
+		if ((ata || sata) && mode != -1) {
+			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
+				warnx("HBA is not capable of changing "
+				      "transfer rates");
+				retval = 1;
+				goto ratecontrol_bailout;
+			}
+			if (ata) {
+				ata->mode = mode;
+				ata->valid |= CTS_ATA_VALID_MODE;
+			} else {
+				sata->mode = mode;
+				sata->valid |= CTS_SATA_VALID_MODE;
+			}
+			didsettings++;
+		}
 		/*
 		 * The bus_width argument goes like this:
 		 * 0 == 8 bit
@@ -3286,7 +3363,6 @@ ratecontrol(struct cam_device *device, i
 		 * number.
 		 */
 		if (spi && bus_width != -1) {
-
 			/*
 			 * We might as well validate things here with a
 			 * decipherable error message, rather than what
@@ -3310,17 +3386,19 @@ ratecontrol(struct cam_device *device, i
 				retval = 1;
 				goto ratecontrol_bailout;
 			}
-
 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
 			spi->bus_width = bus_width >> 4;
 			didsettings++;
 		}
-
 		if  (didsettings == 0) {
 			goto ratecontrol_bailout;
 		}
+		if  (!user_settings && (ata || sata)) {
+			warnx("You can modify only user settings for ATA/SATA");
+			retval = 1;
+			goto ratecontrol_bailout;
+		}
 		ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
-
 		if (cam_send_ccb(device, ccb) < 0) {
 			perror("error sending XPT_SET_TRAN_SETTINGS CCB");
 			if (arglist & CAM_ARG_VERBOSE) {
@@ -3330,7 +3408,6 @@ ratecontrol(struct cam_device *device, i
 			retval = 1;
 			goto ratecontrol_bailout;
 		}
-
 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
 			warnx("XPT_SET_TRANS_SETTINGS CCB failed");
 			if (arglist & CAM_ARG_VERBOSE) {
@@ -3341,11 +3418,9 @@ ratecontrol(struct cam_device *device, i
 			goto ratecontrol_bailout;
 		}
 	}
-
 	if (send_tur) {
 		retval = testunitready(device, retry_count, timeout,
 				       (arglist & CAM_ARG_VERBOSE) ? 0 : 1);
-
 		/*
 		 * If the TUR didn't succeed, just bail.
 		 */
@@ -3354,7 +3429,6 @@ ratecontrol(struct cam_device *device, i
 				fprintf(stderr, "Test Unit Ready failed\n");
 			goto ratecontrol_bailout;
 		}
-
 		/*
 		 * If the user wants things quiet, there's no sense in
 		 * getting the transfer settings, if we're not going
@@ -3362,13 +3436,11 @@ ratecontrol(struct cam_device *device, i
 		 */
 		if (quiet != 0)
 			goto ratecontrol_bailout;
-
-		fprintf(stdout, "New Parameters:\n");
+		fprintf(stdout, "New parameters:\n");
 		retval = get_print_cts(device, user_settings, 0, NULL);
 	}
 
 ratecontrol_bailout:
-
 	cam_freeccb(ccb);
 	return(retval);
 }
@@ -4255,8 +4327,8 @@ usage(int verbose)
 "                              <all|bus[:target[:lun]]|off>\n"
 "        camcontrol tags       [dev_id][generic args] [-N tags] [-q] [-v]\n"
 "        camcontrol negotiate  [dev_id][generic args] [-a][-c]\n"
-"                              [-D <enable|disable>][-O offset][-q]\n"
-"                              [-R syncrate][-v][-T <enable|disable>]\n"
+"                              [-D <enable|disable>][-M mode][-O offset]\n"
+"                              [-q][-R syncrate][-v][-T <enable|disable>]\n"
 "                              [-U][-W bus_width]\n"
 "        camcontrol format     [dev_id][generic args][-q][-r][-w][-y]\n"
 "        camcontrol idle       [dev_id][generic args][-t time]\n"
@@ -4347,6 +4419,7 @@ usage(int verbose)
 "-a                send a test unit ready after negotiation\n"
 "-c                report/set current negotiation settings\n"
 "-D <arg>          \"enable\" or \"disable\" disconnection\n"
+"-M mode           set ATA mode\n"
 "-O offset         set command delay offset\n"
 "-q                be quiet, don't report anything\n"
 "-R syncrate       synchronization rate in MHz\n"

Modified: stable/8/sys/cam/ata/ata_all.c
==============================================================================
--- stable/8/sys/cam/ata/ata_all.c	Wed Dec  2 10:10:37 2009	(r200021)
+++ stable/8/sys/cam/ata/ata_all.c	Wed Dec  2 10:32:34 2009	(r200022)
@@ -491,22 +491,143 @@ ata_max_umode(struct ata_params *ap)
 }
 
 int
-ata_max_mode(struct ata_params *ap, int mode, int maxmode)
+ata_max_mode(struct ata_params *ap, int maxmode)
 {
 
-    if (maxmode && mode > maxmode)
-	mode = maxmode;
+	if (maxmode == 0)
+		maxmode = ATA_DMA_MAX;
+	if (maxmode >= ATA_UDMA0 && ata_max_umode(ap) > 0)
+		return (min(maxmode, ata_max_umode(ap)));
+	if (maxmode >= ATA_WDMA0 && ata_max_wmode(ap) > 0)
+		return (min(maxmode, ata_max_wmode(ap)));
+	return (min(maxmode, ata_max_pmode(ap)));
+}
 
-    if (mode >= ATA_UDMA0 && ata_max_umode(ap) > 0)
-	return (min(mode, ata_max_umode(ap)));
+char *
+ata_mode2string(int mode)
+{
+    switch (mode) {
+    case -1: return "UNSUPPORTED";
+    case 0: return "NONE";
+    case ATA_PIO0: return "PIO0";
+    case ATA_PIO1: return "PIO1";
+    case ATA_PIO2: return "PIO2";
+    case ATA_PIO3: return "PIO3";
+    case ATA_PIO4: return "PIO4";
+    case ATA_WDMA0: return "WDMA0";
+    case ATA_WDMA1: return "WDMA1";
+    case ATA_WDMA2: return "WDMA2";
+    case ATA_UDMA0: return "UDMA0";
+    case ATA_UDMA1: return "UDMA1";
+    case ATA_UDMA2: return "UDMA2";
+    case ATA_UDMA3: return "UDMA3";
+    case ATA_UDMA4: return "UDMA4";
+    case ATA_UDMA5: return "UDMA5";
+    case ATA_UDMA6: return "UDMA6";
+    default:
+	if (mode & ATA_DMA_MASK)
+	    return "BIOSDMA";
+	else
+	    return "BIOSPIO";
+    }
+}
 
-    if (mode >= ATA_WDMA0 && ata_max_wmode(ap) > 0)
-	return (min(mode, ata_max_wmode(ap)));
+int
+ata_string2mode(char *str)
+{
+	if (!strcasecmp(str, "PIO0")) return (ATA_PIO0);
+	if (!strcasecmp(str, "PIO1")) return (ATA_PIO1);
+	if (!strcasecmp(str, "PIO2")) return (ATA_PIO2);
+	if (!strcasecmp(str, "PIO3")) return (ATA_PIO3);
+	if (!strcasecmp(str, "PIO4")) return (ATA_PIO4);
+	if (!strcasecmp(str, "WDMA0")) return (ATA_WDMA0);
+	if (!strcasecmp(str, "WDMA1")) return (ATA_WDMA1);
+	if (!strcasecmp(str, "WDMA2")) return (ATA_WDMA2);
+	if (!strcasecmp(str, "UDMA0")) return (ATA_UDMA0);
+	if (!strcasecmp(str, "UDMA16")) return (ATA_UDMA0);
+	if (!strcasecmp(str, "UDMA1")) return (ATA_UDMA1);
+	if (!strcasecmp(str, "UDMA25")) return (ATA_UDMA1);
+	if (!strcasecmp(str, "UDMA2")) return (ATA_UDMA2);
+	if (!strcasecmp(str, "UDMA33")) return (ATA_UDMA2);
+	if (!strcasecmp(str, "UDMA3")) return (ATA_UDMA3);
+	if (!strcasecmp(str, "UDMA44")) return (ATA_UDMA3);
+	if (!strcasecmp(str, "UDMA4")) return (ATA_UDMA4);
+	if (!strcasecmp(str, "UDMA66")) return (ATA_UDMA4);
+	if (!strcasecmp(str, "UDMA5")) return (ATA_UDMA5);
+	if (!strcasecmp(str, "UDMA100")) return (ATA_UDMA5);
+	if (!strcasecmp(str, "UDMA6")) return (ATA_UDMA6);
+	if (!strcasecmp(str, "UDMA133")) return (ATA_UDMA6);
+	return (-1);
+}
+
+
+u_int
+ata_mode2speed(int mode)
+{
+	switch (mode) {
+	case ATA_PIO0:
+	default:
+		return (3300);
+	case ATA_PIO1:
+		return (5200);
+	case ATA_PIO2:
+		return (8300);
+	case ATA_PIO3:
+		return (11100);
+	case ATA_PIO4:
+		return (16700);
+	case ATA_WDMA0:
+		return (4200);
+	case ATA_WDMA1:
+		return (13300);
+	case ATA_WDMA2:
+		return (16700);
+	case ATA_UDMA0:
+		return (16700);
+	case ATA_UDMA1:
+		return (25000);
+	case ATA_UDMA2:
+		return (33300);
+	case ATA_UDMA3:
+		return (44400);
+	case ATA_UDMA4:
+		return (66700);
+	case ATA_UDMA5:
+		return (100000);
+	case ATA_UDMA6:
+		return (133000);
+	}
+}
 
-    if (mode > ata_max_pmode(ap))
-	return (min(mode, ata_max_pmode(ap)));
+u_int
+ata_revision2speed(int revision)
+{
+	switch (revision) {
+	case 1:
+	default:
+		return (150000);
+	case 2:
+		return (300000);
+	case 3:
+		return (600000);
+	}
+}
 
-    return (mode);
+int
+ata_speed2revision(u_int speed)
+{
+	switch (speed) {
+	case 0:
+		return (0);
+	case 150000:
+		return (1);
+	case 300000:
+		return (2);
+	case 600000:
+		return (3);
+	default:
+		return (-1);
+	}
 }
 
 int

Modified: stable/8/sys/cam/ata/ata_all.h
==============================================================================
--- stable/8/sys/cam/ata/ata_all.h	Wed Dec  2 10:10:37 2009	(r200021)
+++ stable/8/sys/cam/ata/ata_all.h	Wed Dec  2 10:32:34 2009	(r200022)
@@ -112,7 +112,13 @@ void	ata_bpack(int8_t *src, int8_t *dst,
 int	ata_max_pmode(struct ata_params *ap);
 int	ata_max_wmode(struct ata_params *ap);
 int	ata_max_umode(struct ata_params *ap);
-int	ata_max_mode(struct ata_params *ap, int mode, int maxmode);
+int	ata_max_mode(struct ata_params *ap, int maxmode);
+
+char *	ata_mode2string(int mode);
+int	ata_string2mode(char *str);
+u_int	ata_mode2speed(int mode);
+u_int	ata_revision2speed(int revision);
+int	ata_speed2revision(u_int speed);
 
 int	ata_identify_match(caddr_t identbuffer, caddr_t table_entry);
 int	ata_static_identify_match(caddr_t identbuffer, caddr_t table_entry);

Modified: stable/8/sys/cam/ata/ata_pmp.c
==============================================================================
--- stable/8/sys/cam/ata/ata_pmp.c	Wed Dec  2 10:10:37 2009	(r200021)
+++ stable/8/sys/cam/ata/ata_pmp.c	Wed Dec  2 10:32:34 2009	(r200022)
@@ -516,6 +516,7 @@ printf("PM RESET %d%s\n", softc->pm_step
 static void
 pmpdone(struct cam_periph *periph, union ccb *done_ccb)
 {
+	struct ccb_trans_settings cts;
 	struct pmp_softc *softc;
 	struct ccb_ataio *ataio;
 	union ccb *work_ccb;
@@ -635,6 +636,19 @@ pmpdone(struct cam_periph *periph, union
 		    done_ccb->ataio.res.sector_count;
 		if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) {
 			printf("PM status: %d - %08x\n", softc->pm_step, res);
+			/* Report device speed. */
+			if (xpt_create_path(&dpath, periph,
+			    xpt_path_path_id(periph->path),
+			    softc->pm_step, 0) == CAM_REQ_CMP) {
+				bzero(&cts, sizeof(cts));
+				xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NORMAL);
+				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+				cts.type = CTS_TYPE_CURRENT_SETTINGS;
+				cts.xport_specific.sata.revision = (res & 0x0f0) >> 4;
+				cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION;
+				xpt_action((union ccb *)&cts);
+				xpt_free_path(dpath);
+			}
 			softc->found |= (1 << softc->pm_step);
 			softc->pm_step++;
 		} else {

Modified: stable/8/sys/cam/ata/ata_xpt.c
==============================================================================
--- stable/8/sys/cam/ata/ata_xpt.c	Wed Dec  2 10:10:37 2009	(r200021)
+++ stable/8/sys/cam/ata/ata_xpt.c	Wed Dec  2 10:32:34 2009	(r200022)
@@ -275,7 +275,7 @@ probeschedule(struct cam_periph *periph)
 static void
 probestart(struct cam_periph *periph, union ccb *start_ccb)
 {
-	/* Probe the device that our peripheral driver points to */
+	struct ccb_trans_settings cts;
 	struct ccb_ataio *ataio;
 	struct ccb_scsiio *csio;
 	probe_softc *softc;
@@ -333,6 +333,55 @@ probestart(struct cam_periph *periph, un
 			ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
 		break;
 	case PROBE_SETMODE:
+	{
+		int mode, wantmode;
+
+		mode = 0;
+		/* Fetch user modes from SIM. */
+		bzero(&cts, sizeof(cts));
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+		cts.type = CTS_TYPE_USER_SETTINGS;
+		xpt_action((union ccb *)&cts);
+		if (path->device->transport == XPORT_ATA) {
+			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
+				mode = cts.xport_specific.ata.mode;
+		} else {
+			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE)
+				mode = cts.xport_specific.sata.mode;
+		}
+negotiate:
+		/* Honor device capabilities. */
+		wantmode = mode = ata_max_mode(ident_buf, mode);
+		/* Report modes to SIM. */
+		bzero(&cts, sizeof(cts));
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+		cts.type = CTS_TYPE_CURRENT_SETTINGS;
+		if (path->device->transport == XPORT_ATA) {
+			cts.xport_specific.ata.mode = mode;
+			cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE;
+		} else {
+			cts.xport_specific.sata.mode = mode;
+			cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE;
+		}
+		xpt_action((union ccb *)&cts);
+		/* Fetch user modes from SIM. */
+		bzero(&cts, sizeof(cts));
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+		cts.type = CTS_TYPE_CURRENT_SETTINGS;
+		xpt_action((union ccb *)&cts);
+		if (path->device->transport == XPORT_ATA) {
+			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
+				mode = cts.xport_specific.ata.mode;
+		} else {
+			if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE)
+				mode = cts.xport_specific.sata.mode;
+		}
+		/* If SIM disagree - renegotiate. */
+		if (mode != wantmode)
+			goto negotiate;
 		cam_fill_ataio(ataio,
 		      1,
 		      probedone,
@@ -341,12 +390,11 @@ probestart(struct cam_periph *periph, un
 		      /*data_ptr*/NULL,
 		      /*dxfer_len*/0,
 		      30 * 1000);
-		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
-		    ata_max_mode(ident_buf, ATA_UDMA6, ATA_UDMA6));
+		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
 		break;
+	}
 	case PROBE_SET_MULTI:
 	{
-		struct ccb_trans_settings cts;
 		u_int sectors;
 
 		sectors = max(1, min(ident_buf->sectors_intr & 0xff, 16));
@@ -564,6 +612,7 @@ proberequestbackoff(struct cam_periph *p
 static void
 probedone(struct cam_periph *periph, union ccb *done_ccb)
 {
+	struct ccb_trans_settings cts;
 	struct ata_params *ident_buf;
 	probe_softc *softc;
 	struct cam_path *path;
@@ -619,9 +668,7 @@ noerror:
 			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
 		} else if (sign == 0x9669 &&
 		    done_ccb->ccb_h.target_id == 15) {
-			struct ccb_trans_settings cts;
-
-				/* Report SIM that PM is present. */
+			/* Report SIM that PM is present. */
 			bzero(&cts, sizeof(cts));
 			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
 			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
@@ -716,11 +763,17 @@ noerror:
 			    ATA_QUEUE_LEN(ident_buf->queue) + 1;
 		}
 		ata_find_quirk(path->device);
-		/* XXX: If not all tags allowed, we must to tell SIM which are. */
-		if (path->device->mintags < path->bus->sim->max_tagged_dev_openings)
-			path->device->mintags = path->device->maxtags = 0;
 		if (path->device->mintags != 0 &&
 		    path->bus->sim->max_tagged_dev_openings != 0) {
+			/* Report SIM which tags are allowed. */
+			bzero(&cts, sizeof(cts));
+			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+			cts.type = CTS_TYPE_CURRENT_SETTINGS;
+			cts.xport_specific.sata.tags = path->device->maxtags;
+			cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS;
+			xpt_action((union ccb *)&cts);
+			/* Reconfigure queues for tagged queueing. */
 			xpt_start_tags(path);
 		}
 		ata_device_transport(path);

Modified: stable/8/sys/cam/cam_ccb.h
==============================================================================
--- stable/8/sys/cam/cam_ccb.h	Wed Dec  2 10:10:37 2009	(r200021)
+++ stable/8/sys/cam/cam_ccb.h	Wed Dec  2 10:32:34 2009	(r200022)
@@ -819,19 +819,23 @@ struct ccb_trans_settings_sas {
 struct ccb_trans_settings_ata {
 	u_int     	valid;		/* Which fields to honor */
 #define	CTS_ATA_VALID_MODE		0x01
-#define	CTS_ATA_VALID_BYTECOUNT		0x04
-	u_int32_t 	mode;
+#define	CTS_ATA_VALID_BYTECOUNT		0x02
+	int		mode;		/* Mode */
 	u_int 		bytecount;	/* Length of PIO transaction */
 };
 
 struct ccb_trans_settings_sata {
 	u_int     	valid;		/* Which fields to honor */
-#define	CTS_SATA_VALID_SPEED		0x01
-#define	CTS_SATA_VALID_PM		0x02
-#define	CTS_SATA_VALID_BYTECOUNT	0x04
-	u_int32_t 	bitrate;	/* Mbps */
-	u_int 		pm_present;	/* PM is present (XPT->SIM) */
+#define	CTS_SATA_VALID_MODE		0x01
+#define	CTS_SATA_VALID_BYTECOUNT	0x02
+#define	CTS_SATA_VALID_REVISION		0x04
+#define	CTS_SATA_VALID_PM		0x08
+#define	CTS_SATA_VALID_TAGS		0x10
+	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 */
 };
 
 /* Get/Set transfer rate/width/disconnection/tag queueing settings */

Modified: stable/8/sys/cam/cam_xpt.c
==============================================================================
--- stable/8/sys/cam/cam_xpt.c	Wed Dec  2 10:10:37 2009	(r200021)
+++ stable/8/sys/cam/cam_xpt.c	Wed Dec  2 10:32:34 2009	(r200022)
@@ -1140,12 +1140,19 @@ xpt_announce_periph(struct cam_periph *p
 		if (sas->valid & CTS_SAS_VALID_SPEED)
 			speed = sas->bitrate;
 	}
+	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
+		struct	ccb_trans_settings_ata *ata =
+		    &cts.xport_specific.ata;
+
+		if (ata->valid & CTS_ATA_VALID_MODE)
+			speed = ata_mode2speed(ata->mode);
+	}
 	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
 		struct	ccb_trans_settings_sata *sata =
 		    &cts.xport_specific.sata;
 
-		if (sata->valid & CTS_SATA_VALID_SPEED)
-			speed = sata->bitrate;
+		if (sata->valid & CTS_SATA_VALID_REVISION)
+			speed = ata_revision2speed(sata->revision);
 	}
 
 	mb = speed / 1000;
@@ -1195,15 +1202,25 @@ xpt_announce_periph(struct cam_periph *p
 		struct ccb_trans_settings_ata *ata =
 		    &cts.xport_specific.ata;
 
+		printf(" (");
+		if (ata->valid & CTS_ATA_VALID_MODE)
+			printf("%s, ", ata_mode2string(ata->mode));
 		if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
-			printf(" (PIO size %dbytes)", ata->bytecount);
+			printf("PIO size %dbytes", ata->bytecount);
+		printf(")");
 	}
 	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
 		struct ccb_trans_settings_sata *sata =
 		    &cts.xport_specific.sata;
 
+		printf(" (");
+		if (sata->valid & CTS_SATA_VALID_REVISION)
+			printf("SATA %d.x, ", sata->revision);
+		if (sata->valid & CTS_SATA_VALID_MODE)
+			printf("%s, ", ata_mode2string(sata->mode));
 		if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
-			printf(" (PIO size %dbytes)", sata->bytecount);
+			printf("PIO size %dbytes", sata->bytecount);
+		printf(")");
 	}
 	if (path->device->inq_flags & SID_CmdQue
 	 || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) {

Modified: stable/8/sys/dev/ahci/ahci.c
==============================================================================
--- stable/8/sys/dev/ahci/ahci.c	Wed Dec  2 10:10:37 2009	(r200021)
+++ stable/8/sys/dev/ahci/ahci.c	Wed Dec  2 10:32:34 2009	(r200022)
@@ -72,7 +72,7 @@ static void ahci_dmasetprd(void *arg, bu
 static void ahci_execute_transaction(struct ahci_slot *slot);
 static void ahci_timeout(struct ahci_slot *slot);
 static void ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et);
-static int ahci_setup_fis(struct ahci_cmd_tab *ctp, union ccb *ccb, int tag);
+static int ahci_setup_fis(device_t dev, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag);
 static void ahci_dmainit(device_t dev);
 static void ahci_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
 static void ahci_dmafini(device_t dev);
@@ -776,7 +776,7 @@ ahci_ch_attach(device_t dev)
 	struct ahci_controller *ctlr = device_get_softc(device_get_parent(dev));
 	struct ahci_channel *ch = device_get_softc(dev);
 	struct cam_devq *devq;
-	int rid, error;
+	int rid, error, i, sata_rev = 0;
 
 	ch->dev = dev;
 	ch->unit = (intptr_t)device_get_ivars(dev);
@@ -795,9 +795,16 @@ ahci_ch_attach(device_t dev)
 	    pci_get_subvendor(ctlr->dev) == 0x1043 &&
 	    pci_get_subdevice(ctlr->dev) == 0x81e4 &&
 	    ch->unit == 0)
-		ch->sata_rev = 1;
+		sata_rev = 1;
 	resource_int_value(device_get_name(dev),
-	    device_get_unit(dev), "sata_rev", &ch->sata_rev);
+	    device_get_unit(dev), "sata_rev", &sata_rev);
+	for (i = 0; i < 16; i++) {
+		ch->user[i].revision = sata_rev;
+		ch->user[i].mode = 0;
+		ch->user[i].bytecount = 8192;
+		ch->user[i].tags = ch->numslots;
+		ch->curr[i] = ch->user[i];
+	}
 	rid = ch->unit;
 	if (!(ch->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
 	    &rid, RF_ACTIVE)))
@@ -1275,6 +1282,10 @@ ahci_check_collision(device_t dev, union
 		if (ch->numtslots != 0 &&
 		    ch->taggedtarget != ccb->ccb_h.target_id)
 			return (1);
+		/* Tagged command while we have no supported tag free. */
+		if (((~ch->oslots) & (0xffffffff >> (32 -
+		    ch->curr[ccb->ccb_h.target_id].tags))) == 0)
+			return (1);
 	} else {
 		/* Untagged command while tagged are active. */
 		if (ch->numrslots != 0 && ch->numtslots != 0)
@@ -1298,15 +1309,21 @@ ahci_begin_transaction(device_t dev, uni
 {
 	struct ahci_channel *ch = device_get_softc(dev);
 	struct ahci_slot *slot;
-	int tag;
+	int tag, tags;
 
 	/* Choose empty slot. */
+	tags = ch->numslots;
+	if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
+	    (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA))
+		tags = ch->curr[ccb->ccb_h.target_id].tags;
 	tag = ch->lastslot;
-	while (ch->slot[tag].state != AHCI_SLOT_EMPTY) {
-		if (++tag >= ch->numslots)
+	while (1) {
+		if (tag >= tags)
 			tag = 0;
-		KASSERT(tag != ch->lastslot, ("ahci: ALL SLOTS BUSY!"));
-	}
+		if (ch->slot[tag].state == AHCI_SLOT_EMPTY)
+			break;
+		tag++;
+	};
 	ch->lastslot = tag;
 	/* Occupy chosen slot. */
 	slot = &ch->slot[tag];
@@ -1315,6 +1332,7 @@ ahci_begin_transaction(device_t dev, uni
 	if (ch->numrslots == 0 && ch->pm_level > 3)
 		callout_stop(&ch->pm_timer);
 	/* Update channel stats. */
+	ch->oslots |= (1 << slot->slot);
 	ch->numrslots++;
 	if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
 	    (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) {
@@ -1392,7 +1410,7 @@ ahci_execute_transaction(struct ahci_slo
 	ctp = (struct ahci_cmd_tab *)
 		(ch->dma.work + AHCI_CT_OFFSET + (AHCI_CT_SIZE * slot->slot));
 	/* Setup the FIS for this request */
-	if (!(fis_size = ahci_setup_fis(ctp, ccb, slot->slot))) {
+	if (!(fis_size = ahci_setup_fis(dev, ctp, ccb, slot->slot))) {
 		device_printf(ch->dev, "Setting up SATA FIS failed\n");
 		ahci_end_transaction(slot, AHCI_ERR_INVALID);
 		return;
@@ -1635,6 +1653,7 @@ ahci_end_transaction(struct ahci_slot *s
 		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
 	}
 	/* Free slot. */
+	ch->oslots &= ~(1 << slot->slot);
 	ch->rslots &= ~(1 << slot->slot);
 	ch->aslots &= ~(1 << slot->slot);
 	slot->state = AHCI_SLOT_EMPTY;
@@ -1664,7 +1683,7 @@ ahci_end_transaction(struct ahci_slot *s
 	} else
 		xpt_done(ccb);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-stable-8 mailing list