diff -u src.old/sys/bus/cam/cam_xpt.c src/sys/bus/cam/cam_xpt.c
--- src.old/sys/bus/cam/cam_xpt.c	2006-11-17 08:16:55.000000000 -0500
+++ src/sys/bus/cam/cam_xpt.c	2006-11-17 08:44:52.000000000 -0500
@@ -141,6 +141,9 @@
 #define CAM_DEV_RESIZE_QUEUE_NEEDED	0x10
 #define CAM_DEV_TAG_AFTER_COUNT		0x20
 #define CAM_DEV_INQUIRY_DATA_VALID	0x40
+#define	CAM_DEV_IN_DV			0x80
+#define	CAM_DEV_DV_HIT_BOTTOM		0x100
+
 	u_int32_t	 tag_delay_count;
 #define	CAM_TAG_DELAY_COUNT		5
 	u_int32_t	 refcount;
@@ -766,6 +769,8 @@
 static void	 probeschedule(struct cam_periph *probe_periph);
 static void	 probestart(struct cam_periph *periph, union ccb *start_ccb);
 static void	 proberequestdefaultnegotiation(struct cam_periph *periph);
+static int       proberequestbackoff(struct cam_periph *periph,
+				     struct cam_ed *device);
 static void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
 static void	 probecleanup(struct cam_periph *periph);
 static void	 xpt_find_quirk(struct cam_ed *device);
@@ -5017,7 +5022,10 @@
 	PROBE_FULL_INQUIRY,
 	PROBE_MODE_SENSE,
 	PROBE_SERIAL_NUM,
-	PROBE_TUR_FOR_NEGOTIATION
+	PROBE_TUR_FOR_NEGOTIATION,
+	PROBE_INQUIRY_BASIC_DV1,
+	PROBE_INQUIRY_BASIC_DV2,
+	PROBE_DV_EXIT
 } probe_action;
 
 typedef enum {
@@ -5228,6 +5236,7 @@
 	switch (softc->action) {
 	case PROBE_TUR:
 	case PROBE_TUR_FOR_NEGOTIATION:
+	case PROBE_DV_EXIT:
 	{
 		scsi_test_unit_ready(csio,
 				     /*retries*/4,
@@ -5239,6 +5248,8 @@
 	}
 	case PROBE_INQUIRY:
 	case PROBE_FULL_INQUIRY:
+	case PROBE_INQUIRY_BASIC_DV1:
+	case PROBE_INQUIRY_BASIC_DV2:
 	{
 		u_int inquiry_len;
 		struct scsi_inquiry_data *inq_buf;
@@ -5270,8 +5281,34 @@
 		if (softc->action == PROBE_INQUIRY)
 			inquiry_len = SHORT_INQUIRY_LENGTH;
 		else
-			inquiry_len = inq_buf->additional_length + 5;
+			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
 	
+		/*
+		 * Some parallel SCSI devices fail to send an
+		 * ignore wide residue message when dealing with
+		 * odd length inquiry requests.  Round up to be
+		 * safe.
+		 */
+
+		inquiry_len = roundup2(inquiry_len, 2);
+
+		if (softc->action == PROBE_INQUIRY_BASIC_DV1
+		 || softc->action == PROBE_INQUIRY_BASIC_DV2) {
+			inq_buf = malloc(inquiry_len, M_TEMP, M_NOWAIT);
+		}
+		if (inq_buf == NULL) {
+			xpt_print_path(periph->path);
+			printf("malloc failure- skipping Basic Domain Validation\n");
+			softc->action = PROBE_DV_EXIT;
+			scsi_test_unit_ready(csio,
+					     /*retries*/4,
+					     probedone,
+					     MSG_SIMPLE_Q_TAG,
+					     SSD_FULL_SIZE,
+					     /*timeout*/60000);
+			break;
+		}
+
 		scsi_inquiry(csio,
 			     /*retries*/4,
 			     probedone,
@@ -5358,6 +5395,115 @@
 	xpt_action((union ccb *)&cts);
 }
 
+/*
+ * Backoff Negotiation Code- only pertinent for SPI devices.
+ */
+static int
+proberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
+{
+	struct ccb_trans_settings cts;
+	struct ccb_trans_settings_spi *spi;
+
+	memset(&cts, 0, sizeof (cts));
+	xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1);
+	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+	cts.type = CTS_TYPE_CURRENT_SETTINGS;
+	xpt_action((union ccb *)&cts);
+	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+		if (bootverbose) {
+			xpt_print_path(periph->path);
+			printf("failed to get current settings\n");
+		}
+		return (0);
+	}
+	if (cts.transport != XPORT_SPI) {
+		if (bootverbose) {
+			xpt_print_path(periph->path);
+			printf("not SPI transport\n");
+		}
+		return (0);
+	}
+	spi = &cts.xport_specific.spi;
+
+	/*
+	 * We cannot renegotiate sync rate if we don't have one.
+	 */
+	if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
+		if (bootverbose) {
+			xpt_print_path(periph->path);
+			printf("no sync rate known\n");
+		}
+		return (0);
+	}
+
+	/*
+	 * We'll assert that we don't have to touch PPR options- the
+	 * SIM will see what we do with period and offset and adjust
+	 * the PPR options as appropriate.
+	 */
+
+	/*
+	 * A sync rate with unknown or zero offset is nonsensical.
+	 * A sync period of zero means Async.
+	 */
+	if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0
+	 || spi->sync_offset == 0 || spi->sync_period == 0) {
+		if (bootverbose) {
+			xpt_print_path(periph->path);
+			printf("no sync rate available\n");
+		}
+		return (0);
+	}
+
+	if (device->flags & CAM_DEV_DV_HIT_BOTTOM) {
+		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+		    ("hit async: giving up on DV\n"));
+		return (0);
+	}
+
+
+	/*
+	 * Jump sync_period up by one, but stop at 5MHz and fall back to Async.
+	 * We don't try to remember 'last' settings to see if the SIM actually
+	 * gets into the speed we want to set. We check on the SIM telling
+	 * us that a requested speed is bad, but otherwise don't try and
+	 * check the speed due to the asynchronous and handshake nature
+	 * of speed setting.
+	 */
+	spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET;
+	for (;;) {
+		spi->sync_period++;
+		if (spi->sync_period >= 0xf) {
+			spi->sync_period = 0;
+			spi->sync_offset = 0;
+			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+			    ("setting to async for DV\n"));
+			/*
+			 * Once we hit async, we don't want to try
+			 * any more settings.
+			 */
+			device->flags |= CAM_DEV_DV_HIT_BOTTOM;
+		} else if (bootverbose) {
+			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+			    ("DV: period 0x%x\n", spi->sync_period));
+			printf("setting period to 0x%x\n", spi->sync_period);
+		}
+		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+		cts.type = CTS_TYPE_CURRENT_SETTINGS;
+		xpt_action((union ccb *)&cts);
+		if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+			break;
+		}
+		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+		    ("DV: failed to set period 0x%x\n", spi->sync_period));
+		if (spi->sync_period == 0) {
+			return (0);
+		}
+	}
+	return (1);
+}
+
+
 static void
 probedone(struct cam_periph *periph, union ccb *done_ccb)
 {
@@ -5608,15 +5754,89 @@
 		break;
 	}
 	case PROBE_TUR_FOR_NEGOTIATION:
+	case PROBE_DV_EXIT:
 		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
 			/* Don't wedge the queue */
 			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
 					 /*run_queue*/TRUE);
 		}
 
-		path->device->flags &= ~CAM_DEV_UNCONFIGURED;
 		xpt_reference_device(path->device);
 
+		/*
+		 * Do Domain Validation for lun 0 on devices that claim
+		 * to support Synchronous Transfer modes.
+		 */
+	 	if (softc->action == PROBE_TUR_FOR_NEGOTIATION
+		 && done_ccb->ccb_h.target_lun == 0
+		 && (path->device->inq_data.flags & SID_Sync) != 0
+                 && (path->device->flags & CAM_DEV_IN_DV) == 0) {
+			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+			    ("Begin Domain Validation\n"));
+			path->device->flags |= CAM_DEV_IN_DV;
+			xpt_release_ccb(done_ccb);
+			softc->action = PROBE_INQUIRY_BASIC_DV1;
+			xpt_schedule(periph, priority);
+			return;
+		}
+		if (softc->action == PROBE_DV_EXIT) {
+			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+			    ("Leave Domain Validation\n"));
+		}
+		path->device->flags &=
+		    ~(CAM_DEV_UNCONFIGURED|CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM);
+
+		if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) {
+			/* Inform the XPT that a new device has been found */
+			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
+			xpt_action(done_ccb);
+			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
+				  done_ccb);
+		}
+		xpt_release_ccb(done_ccb);
+		break;
+	case PROBE_INQUIRY_BASIC_DV1:
+	case PROBE_INQUIRY_BASIC_DV2:
+	{
+		struct scsi_inquiry_data *nbuf;
+		struct ccb_scsiio *csio;
+ 
+		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+			/* Don't wedge the queue */
+			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+					 /*run_queue*/TRUE);
+		}
+		csio = &done_ccb->csio;
+		nbuf = (struct scsi_inquiry_data *)csio->data_ptr;
+		if (bcmp(nbuf, &path->device->inq_data, SHORT_INQUIRY_LENGTH)) {
+			xpt_print_path(path);
+			printf("inquiry fails comparison at DV%d step\n",
+			    softc->action == PROBE_INQUIRY_BASIC_DV1? 1 : 2);
+			if (proberequestbackoff(periph, path->device)) {
+				path->device->flags &= ~CAM_DEV_IN_DV;
+				softc->action = PROBE_TUR_FOR_NEGOTIATION;
+			} else {
+				/* give up */
+				softc->action = PROBE_DV_EXIT;
+			}
+			free(nbuf, M_TEMP);
+			xpt_release_ccb(done_ccb);
+			xpt_schedule(periph, priority);
+			return;
+		}
+		free(nbuf, M_TEMP);
+		if (softc->action == PROBE_INQUIRY_BASIC_DV1) {
+			softc->action = PROBE_INQUIRY_BASIC_DV2;
+			xpt_release_ccb(done_ccb);
+			xpt_schedule(periph, priority);
+			return;
+		}
+		if (softc->action == PROBE_DV_EXIT) {
+			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+			    ("Leave Domain Validation Successfully\n"));
+		}
+		path->device->flags &=
+		    ~(CAM_DEV_UNCONFIGURED|CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM);
 		if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) {
 			/* Inform the XPT that a new device has been found */
 			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
@@ -5627,6 +5847,7 @@
 		xpt_release_ccb(done_ccb);
 		break;
 	}
+	}
 	done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
 	TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe);
 	done_ccb->ccb_h.status = CAM_REQ_CMP;
Common subdirectories: src.old/sys/bus/cam/scsi and src/sys/bus/cam/scsi
