[Midnightbsd-cvs] src: sys/cam: sync changes with FreeBSD 7

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Mon Sep 15 20:27:06 EDT 2008


Log Message:
-----------
sync changes with FreeBSD 7

Modified Files:
--------------
    src/sys/cam:
        cam.c (r1.1.1.1 -> r1.2)
        cam_ccb.h (r1.2 -> r1.3)
        cam_debug.h (r1.1.1.1 -> r1.2)
        cam_periph.c (r1.2 -> r1.3)
        cam_periph.h (r1.1.1.1 -> r1.2)
        cam_sim.c (r1.1.1.1 -> r1.2)
        cam_sim.h (r1.1.1.1 -> r1.2)
        cam_xpt.c (r1.2 -> r1.3)
        cam_xpt.h (r1.1.1.1 -> r1.2)
        cam_xpt_periph.h (r1.1.1.1 -> r1.2)
        cam_xpt_sim.h (r1.1.1.1 -> r1.2)
    src/sys/cam/scsi:
        scsi_all.c (r1.2 -> r1.3)
        scsi_all.h (r1.2 -> r1.3)
        scsi_cd.c (r1.2 -> r1.3)
        scsi_ch.c (r1.1.1.1 -> r1.2)
        scsi_da.c (r1.2 -> r1.3)
        scsi_low.c (r1.1.1.1 -> r1.2)
        scsi_pass.c (r1.2 -> r1.3)
        scsi_pt.c (r1.1.1.1 -> r1.2)
        scsi_sa.c (r1.1.1.2 -> r1.2)
        scsi_ses.c (r1.1.1.1 -> r1.2)
        scsi_ses.h (r1.2 -> r1.3)
        scsi_targ_bh.c (r1.1.1.1 -> r1.2)
        scsi_target.c (r1.1.1.1 -> r1.2)

Added Files:
-----------
    src/sys/cam/scsi:
        scsi_sg.c (r1.1)
        scsi_sg.h (r1.1)

-------------- next part --------------
Index: cam_xpt.c
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_xpt.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/cam/cam_xpt.c -L sys/cam/cam_xpt.c -u -r1.2 -r1.3
--- sys/cam/cam_xpt.c
+++ sys/cam/cam_xpt.c
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/cam_xpt.c,v 1.155.2.8 2006/09/23 18:42:08 mjacob Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/cam_xpt.c,v 1.190.4.1 2008/01/31 14:19:06 brueffer Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -42,10 +42,12 @@
 #include <sys/md5.h>
 #include <sys/interrupt.h>
 #include <sys/sbuf.h>
+#include <sys/taskqueue.h>
 
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/sysctl.h>
+#include <sys/kthread.h>
 
 #ifdef PC98
 #include <pc98/pc98/pc98_machdep.h>	/* geometry translation */
@@ -63,11 +65,19 @@
 #include <cam/scsi/scsi_all.h>
 #include <cam/scsi/scsi_message.h>
 #include <cam/scsi/scsi_pass.h>
+#include <machine/stdarg.h>	/* for xpt_print below */
 #include "opt_cam.h"
 
 /* Datastructures internal to the xpt layer */
 MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers");
 
+/* Object for defering XPT actions to a taskqueue */
+struct xpt_task {
+	struct task	task;
+	void		*data1;
+	uintptr_t	data2;
+};
+
 /*
  * Definition of an async handler callback block.  These are used to add
  * SIMs and peripherals to the async callback lists.
@@ -82,7 +92,6 @@
 
 SLIST_HEAD(async_list, async_node);
 SLIST_HEAD(periph_list, cam_periph);
-static STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq;
 
 /*
  * This is the maximum number of high powered commands (e.g. start unit)
@@ -92,9 +101,6 @@
 #define CAM_MAX_HIGHPOWER  4
 #endif
 
-/* number of high powered commands that can go through right now */
-static int num_highpower = CAM_MAX_HIGHPOWER;
-
 /*
  * Structure for queueing a device in a run queue.
  * There is one run queue for allocating new ccbs,
@@ -115,6 +121,7 @@
 	struct	cam_ed_qinfo alloc_ccb_entry;
 	struct	cam_ed_qinfo send_ccb_entry;
 	struct	cam_et	 *target;
+	struct	cam_sim  *sim;
 	lun_id_t	 lun_id;
 	struct	camq drvq;		/*
 					 * Queue of type drivers wanting to do
@@ -127,12 +134,10 @@
 	struct	cam_periph *owner;	/* Peripheral driver's ownership tag */
 	struct	xpt_quirk_entry *quirk;	/* Oddities about this device */
 					/* Storage for the inquiry data */
-#ifdef CAM_NEW_TRAN_CODE
 	cam_proto	 protocol;
 	u_int		 protocol_version;
 	cam_xport	 transport;
 	u_int		 transport_version;
-#endif /* CAM_NEW_TRAN_CODE */
 	struct		 scsi_inquiry_data inq_data;
 	u_int8_t	 inq_flags;	/*
 					 * Current settings for inquiry flags.
@@ -152,11 +157,13 @@
 #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	 tag_saved_openings;
 	u_int32_t	 refcount;
-	struct		 callout_handle c_handle;
+	struct callout	 callout;
 };
 
 /*
@@ -190,6 +197,7 @@
 #define	CAM_EB_RUNQ_SCHEDULED	0x01
 	u_int32_t	     refcount;
 	u_int		     generation;
+	device_t	     parent_dev;
 };
 
 struct cam_path {
@@ -240,8 +248,24 @@
 } xpt_flags;
 
 struct xpt_softc {
-	xpt_flags	flags;
-	u_int32_t	generation;
+	xpt_flags		flags;
+	u_int32_t		xpt_generation;
+
+	/* number of high powered commands that can go through right now */
+	STAILQ_HEAD(highpowerlist, ccb_hdr)	highpowerq;
+	int			num_highpower;
+
+	/* queue for handling async rescan requests. */
+	TAILQ_HEAD(, ccb_hdr) ccb_scanq;
+
+	/* Registered busses */
+	TAILQ_HEAD(,cam_eb)	xpt_busses;
+	u_int			bus_generation;
+
+	struct intr_config_hook	*xpt_config_hook;
+
+	struct mtx		xpt_topo_lock;
+	struct mtx		xpt_lock;
 };
 
 static const char quantum[] = "QUANTUM";
@@ -387,7 +411,7 @@
 		/*quirks*/0, /*mintags*/0, /*maxtags*/0
 	},
 	{
-		/* Does not support other than LUN 0 */
+		/* This does not support other than LUN 0 */
 		{ T_DIRECT, SIP_MEDIA_FIXED, "VMware*", "*", "*" },
 		CAM_QUIRK_NOLUNS, /*mintags*/2, /*maxtags*/255
 	},
@@ -596,6 +620,18 @@
 		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
 	},
 	{
+		/*
+		 * Western Digital My Book 250GB (USB)
+		 * hangs upon serial number probing.
+		 * PR: 107495
+		 */
+		{
+			T_DIRECT, SIP_MEDIA_FIXED, "WD",
+			"2500JB External", "*"
+		},
+		CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0
+	},
+	{
 		/* Default tagged queuing parameters for all devices */
 		{
 		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
@@ -642,17 +678,12 @@
 
 /* Queues for our software interrupt handler */
 typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t;
-static cam_isrq_t cam_bioq;
-static struct mtx cam_bioq_lock;
+typedef TAILQ_HEAD(cam_simq, cam_sim) cam_simq_t;
+static cam_simq_t cam_simq;
+static struct mtx cam_simq_lock;
 
-/* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */
-static SLIST_HEAD(,ccb_hdr) ccb_freeq;
-static u_int xpt_max_ccbs;	/*
-				 * Maximum size of ccb pool.  Modified as
-				 * devices are added/removed or have their
-				 * opening counts changed.
-				 */
-static u_int xpt_ccb_count;	/* Current count of allocated ccbs */
+/* Pointers to software interrupt handlers */
+static void *cambio_ih;
 
 struct cam_periph *xpt_periph;
 
@@ -682,14 +713,13 @@
 
 static struct cdevsw xpt_cdevsw = {
 	.d_version =	D_VERSION,
-	.d_flags =	D_NEEDGIANT,
+	.d_flags =	0,
 	.d_open =	xptopen,
 	.d_close =	xptclose,
 	.d_ioctl =	xptioctl,
 	.d_name =	"xpt",
 };
 
-static struct intr_config_hook *xpt_config_hook;
 
 static void dead_sim_action(struct cam_sim *sim, union ccb *ccb);
 static void dead_sim_poll(struct cam_sim *sim);
@@ -703,9 +733,6 @@
 
 #define SIM_DEAD(sim)	((sim) == &cam_dead_sim)
 
-/* Registered busses */
-static TAILQ_HEAD(,cam_eb) xpt_busses;
-static u_int bus_generation;
 
 /* Storage for debugging datastructures */
 #ifdef	CAMDEBUG
@@ -714,9 +741,6 @@
 u_int32_t cam_debug_delay;
 #endif
 
-/* Pointers to software interrupt handlers */
-static void *cambio_ih;
-
 #if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG)
 #error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS"
 #endif
@@ -748,7 +772,7 @@
 	NULL
 };
 
-static void	xpt_init(void *);
+static int	xpt_init(void *);
 
 DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND);
 MODULE_VERSION(cam, 1);
@@ -779,7 +803,7 @@
 static void	 xpt_run_dev_allocq(struct cam_eb *bus);
 static void	 xpt_run_dev_sendq(struct cam_eb *bus);
 static timeout_t xpt_release_devq_timeout;
-static timeout_t xpt_release_simq_timeout;
+static void	 xpt_release_simq_timeout(void *arg) __unused;
 static void	 xpt_release_bus(struct cam_eb *bus);
 static void	 xpt_release_devq_device(struct cam_ed *dev, u_int count,
 					 int run_queue);
@@ -811,11 +835,7 @@
 static void	 xptaction(struct cam_sim *sim, union ccb *work_ccb);
 static void	 xptpoll(struct cam_sim *sim);
 static void	 camisr(void *);
-#if 0
-static void	 xptstart(struct cam_periph *periph, union ccb *work_ccb);
-static void	 xptasync(struct cam_periph *periph,
-			  u_int32_t code, cam_path *path);
-#endif
+static void	 camisr_runqueue(void *);
 static dev_match_ret	xptbusmatch(struct dev_match_pattern *patterns,
 				    u_int num_patterns, struct cam_eb *bus);
 static dev_match_ret	xptdevicematch(struct dev_match_pattern *patterns,
@@ -854,16 +874,8 @@
 static xpt_devicefunc_t	xptdefdevicefunc;
 static xpt_periphfunc_t	xptdefperiphfunc;
 static int		xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg);
-#ifdef notusedyet
-static int		xpt_for_all_targets(xpt_targetfunc_t *tr_func,
-					    void *arg);
-#endif
 static int		xpt_for_all_devices(xpt_devicefunc_t *tr_func,
 					    void *arg);
-#ifdef notusedyet
-static int		xpt_for_all_periphs(xpt_periphfunc_t *tr_func,
-					    void *arg);
-#endif
 static xpt_devicefunc_t	xptsetasyncfunc;
 static xpt_busfunc_t	xptsetasyncbusfunc;
 static cam_status	xptregister(struct cam_periph *periph,
@@ -873,12 +885,12 @@
 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);
-#ifdef CAM_NEW_TRAN_CODE
 static void	 xpt_devise_transport(struct cam_path *path);
-#endif /* CAM_NEW_TRAN_CODE */
 static void	 xpt_set_transfer_settings(struct ccb_trans_settings *cts,
 					   struct cam_ed *device,
 					   int async_update);
@@ -994,9 +1006,6 @@
 static int
 xptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
 {
-	int unit;
-
-	unit = minor(dev) & 0xff;
 
 	/*
 	 * Only allow read-write access.
@@ -1008,22 +1017,14 @@
 	 * We don't allow nonblocking access.
 	 */
 	if ((flags & O_NONBLOCK) != 0) {
-		printf("xpt%d: can't do nonblocking access\n", unit);
+		printf("%s: can't do nonblocking access\n", devtoname(dev));
 		return(ENODEV);
 	}
 
-	/*
-	 * We only have one transport layer right now.  If someone accesses
-	 * us via something other than minor number 1, point out their
-	 * mistake.
-	 */
-	if (unit != 0) {
-		printf("xptopen: got invalid xpt unit %d\n", unit);
-		return(ENXIO);
-	}
-
 	/* Mark ourselves open */
+	mtx_lock(&xsoftc.xpt_lock);
 	xsoftc.flags |= XPT_FLAG_OPEN;
+	mtx_unlock(&xsoftc.xpt_lock);
 	
 	return(0);
 }
@@ -1031,43 +1032,27 @@
 static int
 xptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
 {
-	int unit;
-
-	unit = minor(dev) & 0xff;
-
-	/*
-	 * We only have one transport layer right now.  If someone accesses
-	 * us via something other than minor number 1, point out their
-	 * mistake.
-	 */
-	if (unit != 0) {
-		printf("xptclose: got invalid xpt unit %d\n", unit);
-		return(ENXIO);
-	}
 
 	/* Mark ourselves closed */
+	mtx_lock(&xsoftc.xpt_lock);
 	xsoftc.flags &= ~XPT_FLAG_OPEN;
+	mtx_unlock(&xsoftc.xpt_lock);
 
 	return(0);
 }
 
+/*
+ * Don't automatically grab the xpt softc lock here even though this is going
+ * through the xpt device.  The xpt device is really just a back door for
+ * accessing other devices and SIMs, so the right thing to do is to grab
+ * the appropriate SIM lock once the bus/SIM is located.
+ */
 static int
 xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
 {
-	int unit, error;
+	int error;
 
 	error = 0;
-	unit = minor(dev) & 0xff;
-
-	/*
-	 * We only have one transport layer right now.  If someone accesses
-	 * us via something other than minor number 1, point out their
-	 * mistake.
-	 */
-	if (unit != 0) {
-		printf("xptioctl: got invalid xpt unit %d\n", unit);
-		return(ENXIO);
-	}
 
 	switch(cmd) {
 	/*
@@ -1079,9 +1064,16 @@
 	case CAMIOCOMMAND: {
 		union ccb *ccb;
 		union ccb *inccb;
+		struct cam_eb *bus;
 
 		inccb = (union ccb *)addr;
 
+		bus = xpt_find_bus(inccb->ccb_h.path_id);
+		if (bus == NULL) {
+			error = EINVAL;
+			break;
+		}
+
 		switch(inccb->ccb_h.func_code) {
 		case XPT_SCAN_BUS:
 		case XPT_RESET_BUS:
@@ -1097,6 +1089,8 @@
 
 			ccb = xpt_alloc_ccb();
 
+			CAM_SIM_LOCK(bus->sim);
+
 			/*
 			 * Create a path using the bus, target, and lun the
 			 * user passed in.
@@ -1107,6 +1101,7 @@
 					    inccb->ccb_h.target_lun) !=
 					    CAM_REQ_CMP){
 				error = EINVAL;
+				CAM_SIM_UNLOCK(bus->sim);
 				xpt_free_ccb(ccb);
 				break;
 			}
@@ -1119,6 +1114,7 @@
 			bcopy(ccb, inccb, sizeof(union ccb));
 			xpt_free_path(ccb->ccb_h.path);
 			xpt_free_ccb(ccb);
+			CAM_SIM_UNLOCK(bus->sim);
 			break;
 
 		case XPT_DEBUG: {
@@ -1129,6 +1125,8 @@
 			 * allocate it on the stack.
 			 */
 
+			CAM_SIM_LOCK(bus->sim);
+
 			/*
 			 * Create a path using the bus, target, and lun the
 			 * user passed in.
@@ -1147,6 +1145,7 @@
 			xpt_merge_ccb(&ccb, inccb);
 			ccb.ccb_h.cbfcnp = xptdone;
 			xpt_action(&ccb);
+			CAM_SIM_UNLOCK(bus->sim);
 			bcopy(&ccb, inccb, sizeof(union ccb));
 			xpt_free_path(ccb.ccb_h.path);
 			break;
@@ -1211,6 +1210,7 @@
 			error = ENOTSUP;
 			break;
 		}
+		xpt_release_bus(bus);
 		break;
 	}
 	/*
@@ -1224,7 +1224,7 @@
 	 * we never return a status of CAM_GDEVLIST_LIST_CHANGED.  It is
 	 * (or rather should be) impossible for the device peripheral driver
 	 * list to change since we look at the whole thing in one pass, and
-	 * we do it with splcam protection.
+	 * we do it with lock protection.
 	 * 
 	 */
 	case CAMGETPASSTHRU: {
@@ -1236,13 +1236,12 @@
 		u_int cur_generation;
 		int base_periph_found;
 		int splbreaknum;
-		int s;
 
 		ccb = (union ccb *)addr;
 		unit = ccb->cgdl.unit_number;
 		name = ccb->cgdl.periph_name;
 		/*
-		 * Every 100 devices, we want to drop our spl protection to
+		 * Every 100 devices, we want to drop our lock protection to
 		 * give the software interrupt handler a chance to run.
 		 * Most systems won't run into this check, but this should
 		 * avoid starvation in the software interrupt handler in
@@ -1264,9 +1263,9 @@
 		}
 
 		/* Keep the list from changing while we traverse it */
-		s = splcam();
+		mtx_lock(&xsoftc.xpt_topo_lock);
 ptstartover:
-		cur_generation = xsoftc.generation;
+		cur_generation = xsoftc.xpt_generation;
 
 		/* first find our driver in the list of drivers */
 		for (p_drv = periph_drivers; *p_drv != NULL; p_drv++)
@@ -1274,7 +1273,7 @@
 				break;
 
 		if (*p_drv == NULL) {
-			splx(s);
+			mtx_unlock(&xsoftc.xpt_topo_lock);
 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
 			ccb->cgdl.status = CAM_GDEVLIST_ERROR;
 			*ccb->cgdl.periph_name = '\0';
@@ -1296,10 +1295,10 @@
 			if (periph->unit_number == unit) {
 				break;
 			} else if (--splbreaknum == 0) {
-				splx(s);
-				s = splcam();
+				mtx_unlock(&xsoftc.xpt_topo_lock);
+				mtx_lock(&xsoftc.xpt_topo_lock);
 				splbreaknum = 100;
-				if (cur_generation != xsoftc.generation)
+				if (cur_generation != xsoftc.xpt_generation)
 				       goto ptstartover;
 			}
 		}
@@ -1382,11 +1381,11 @@
 			if (base_periph_found == 1) {
 				printf("xptioctl: pass driver is not in the "
 				       "kernel\n");
-				printf("xptioctl: put \"device pass0\" in "
+				printf("xptioctl: put \"device pass\" in "
 				       "your kernel config file\n");
 			}
 		}
-		splx(s);
+		mtx_unlock(&xsoftc.xpt_topo_lock);
 		break;
 		}
 	default:
@@ -1400,33 +1399,102 @@
 static int
 cam_module_event_handler(module_t mod, int what, void *arg)
 {
-	if (what == MOD_LOAD) {
-		xpt_init(NULL);
-	} else if (what == MOD_UNLOAD) {
+	int error;
+
+	switch (what) {
+	case MOD_LOAD:
+		if ((error = xpt_init(NULL)) != 0)
+			return (error);
+		break;
+	case MOD_UNLOAD:
 		return EBUSY;
-	} else {
+	default:
 		return EOPNOTSUPP;
 	}
 
 	return 0;
 }
 
-/* Functions accessed by the peripheral drivers */
+/* thread to handle bus rescans */
 static void
-xpt_init(dummy)
-	void *dummy;
+xpt_scanner_thread(void *dummy)
+{
+	cam_isrq_t	queue;
+	union ccb	*ccb;
+	struct cam_sim	*sim;
+
+	for (;;) {
+		/*
+		 * Wait for a rescan request to come in.  When it does, splice
+		 * it onto a queue from local storage so that the xpt lock
+		 * doesn't need to be held while the requests are being
+		 * processed.
+		 */
+		xpt_lock_buses();
+		msleep(&xsoftc.ccb_scanq, &xsoftc.xpt_topo_lock, PRIBIO,
+		    "ccb_scanq", 0);
+		TAILQ_INIT(&queue);
+		TAILQ_CONCAT(&queue, &xsoftc.ccb_scanq, sim_links.tqe);
+		xpt_unlock_buses();
+
+		while ((ccb = (union ccb *)TAILQ_FIRST(&queue)) != NULL) {
+			TAILQ_REMOVE(&queue, &ccb->ccb_h, sim_links.tqe);
+
+			sim = ccb->ccb_h.path->bus->sim;
+			CAM_SIM_LOCK(sim);
+
+			ccb->ccb_h.func_code = XPT_SCAN_BUS;
+			ccb->ccb_h.cbfcnp = xptdone;
+			xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 5);
+			cam_periph_runccb(ccb, NULL, 0, 0, NULL);
+			xpt_free_path(ccb->ccb_h.path);
+			xpt_free_ccb(ccb);
+			CAM_SIM_UNLOCK(sim);
+		}
+	}
+}
+
+void
+xpt_rescan(union ccb *ccb)
+{
+	struct ccb_hdr *hdr;
+
+	/*
+	 * Don't make duplicate entries for the same paths.
+	 */
+	xpt_lock_buses();
+	TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) {
+		if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) {
+			xpt_unlock_buses();
+			xpt_print(ccb->ccb_h.path, "rescan already queued\n");
+			xpt_free_path(ccb->ccb_h.path);
+			xpt_free_ccb(ccb);
+			return;
+		}
+	}
+	TAILQ_INSERT_TAIL(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe);
+	wakeup(&xsoftc.ccb_scanq);
+	xpt_unlock_buses();
+}
+
+/* Functions accessed by the peripheral drivers */
+static int
+xpt_init(void *dummy)
 {
 	struct cam_sim *xpt_sim;
 	struct cam_path *path;
 	struct cam_devq *devq;
 	cam_status status;
 
-	TAILQ_INIT(&xpt_busses);
-	TAILQ_INIT(&cam_bioq);
-	SLIST_INIT(&ccb_freeq);
-	STAILQ_INIT(&highpowerq);
-
-	mtx_init(&cam_bioq_lock, "CAM BIOQ lock", NULL, MTX_DEF);
+	TAILQ_INIT(&xsoftc.xpt_busses);
+	TAILQ_INIT(&cam_simq);
+	TAILQ_INIT(&xsoftc.ccb_scanq);
+	STAILQ_INIT(&xsoftc.highpowerq);
+	xsoftc.num_highpower = CAM_MAX_HIGHPOWER;
+
+	mtx_init(&cam_simq_lock, "CAM SIMQ lock", NULL, MTX_DEF);
+	mtx_init(&xsoftc.xpt_lock, "XPT lock", NULL, MTX_DEF);
+	mtx_init(&xsoftc.xpt_topo_lock, "XPT topology lock", NULL, MTX_DEF);
 
 	/*
 	 * The xpt layer is, itself, the equivelent of a SIM.
@@ -1440,12 +1508,21 @@
 				"xpt",
 				/*softc*/NULL,
 				/*unit*/0,
+				/*mtx*/&xsoftc.xpt_lock,
 				/*max_dev_transactions*/0,
 				/*max_tagged_dev_transactions*/0,
 				devq);
-	xpt_max_ccbs = 16;
-				
-	xpt_bus_register(xpt_sim, /*bus #*/0);
+	if (xpt_sim == NULL)
+		return (ENOMEM);
+
+	xpt_sim->max_ccbs = 16;
+
+	mtx_lock(&xsoftc.xpt_lock);
+	if ((status = xpt_bus_register(xpt_sim, NULL, 0)) != CAM_SUCCESS) {
+		printf("xpt_init: xpt_bus_register failed with status %#x,"
+		       " failing attach\n", status);
+		return (EINVAL);
+	}
 
 	/*
 	 * Looking at the XPT from the SIM layer, the XPT is
@@ -1457,49 +1534,57 @@
 				      CAM_LUN_WILDCARD)) != CAM_REQ_CMP) {
 		printf("xpt_init: xpt_create_path failed with status %#x,"
 		       " failing attach\n", status);
-		return;
+		return (EINVAL);
 	}
 
 	cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO,
-			 path, NULL, 0, NULL);
+			 path, NULL, 0, xpt_sim);
 	xpt_free_path(path);
-
-	xpt_sim->softc = xpt_periph;
+	mtx_unlock(&xsoftc.xpt_lock);
 
 	/*
 	 * Register a callback for when interrupts are enabled.
 	 */
-	xpt_config_hook =
+	xsoftc.xpt_config_hook =
 	    (struct intr_config_hook *)malloc(sizeof(struct intr_config_hook),
-					      M_TEMP, M_NOWAIT | M_ZERO);
-	if (xpt_config_hook == NULL) {
+					      M_CAMXPT, M_NOWAIT | M_ZERO);
+	if (xsoftc.xpt_config_hook == NULL) {
 		printf("xpt_init: Cannot malloc config hook "
 		       "- failing attach\n");
-		return;
+		return (ENOMEM);
 	}
 
-	xpt_config_hook->ich_func = xpt_config;
-	if (config_intrhook_establish(xpt_config_hook) != 0) {
-		free (xpt_config_hook, M_TEMP);
+	xsoftc.xpt_config_hook->ich_func = xpt_config;
+	if (config_intrhook_establish(xsoftc.xpt_config_hook) != 0) {
+		free (xsoftc.xpt_config_hook, M_CAMXPT);
 		printf("xpt_init: config_intrhook_establish failed "
 		       "- failing attach\n");
 	}
 
+	/* fire up rescan thread */
+	if (kthread_create(xpt_scanner_thread, NULL, NULL, 0, 0, "xpt_thrd")) {
+		printf("xpt_init: failed to create rescan thread\n");
+	}
 	/* Install our software interrupt handlers */
-	swi_add(NULL, "cambio", camisr, &cam_bioq, SWI_CAMBIO, 0, &cambio_ih);
+	swi_add(NULL, "cambio", camisr, NULL, SWI_CAMBIO, INTR_MPSAFE, &cambio_ih);
+
+	return (0);
 }
 
 static cam_status
 xptregister(struct cam_periph *periph, void *arg)
 {
+	struct cam_sim *xpt_sim;
+
 	if (periph == NULL) {
 		printf("xptregister: periph was NULL!!\n");
 		return(CAM_REQ_CMP_ERR);
 	}
 
-	periph->softc = NULL;
-
+	xpt_sim = (struct cam_sim *)arg;
+	xpt_sim->softc = periph;
 	xpt_periph = periph;
+	periph->softc = NULL;
 
 	return(CAM_REQ_CMP);
 }
@@ -1511,7 +1596,7 @@
 	int32_t	 status;
 	struct periph_list *periph_head;
 
-	GIANT_REQUIRED;
+	mtx_assert(periph->sim->mtx, MA_OWNED);
 
 	device = periph->path->device;
 
@@ -1520,25 +1605,22 @@
 	status = CAM_REQ_CMP;
 
 	if (device != NULL) {
-		int s;
-
 		/*
 		 * Make room for this peripheral
 		 * so it will fit in the queue
 		 * when it's scheduled to run
 		 */
-		s = splsoftcam();
 		status = camq_resize(&device->drvq,
 				     device->drvq.array_size + 1);
 
 		device->generation++;
 
 		SLIST_INSERT_HEAD(periph_head, periph, periph_links);
-
-		splx(s);
 	}
 
-	xsoftc.generation++;
+	mtx_lock(&xsoftc.xpt_topo_lock);
+	xsoftc.xpt_generation++;
+	mtx_unlock(&xsoftc.xpt_topo_lock);
 
 	return (status);
 }
@@ -1548,32 +1630,28 @@
 {
 	struct cam_ed *device;
 
-	GIANT_REQUIRED;
+	mtx_assert(periph->sim->mtx, MA_OWNED);
 
 	device = periph->path->device;
 
 	if (device != NULL) {
-		int s;
 		struct periph_list *periph_head;
 
 		periph_head = &device->periphs;
 		
 		/* Release the slot for this peripheral */
-		s = splsoftcam();
 		camq_resize(&device->drvq, device->drvq.array_size - 1);
 
 		device->generation++;
 
 		SLIST_REMOVE(periph_head, periph, cam_periph, periph_links);
-
-		splx(s);
 	}
 
-	xsoftc.generation++;
-
+	mtx_lock(&xsoftc.xpt_topo_lock);
+	xsoftc.xpt_generation++;
+	mtx_unlock(&xsoftc.xpt_topo_lock);
 }
 
-#ifdef CAM_NEW_TRAN_CODE
 
 void
 xpt_announce_periph(struct cam_periph *periph, char *announce_string)
@@ -1584,16 +1662,14 @@
 	u_int	speed;
 	u_int	freq;
 	u_int	mb;
-	int	s;
 
-	GIANT_REQUIRED;
+	mtx_assert(periph->sim->mtx, MA_OWNED);
 
 	path = periph->path;
 	/*
 	 * To ensure that this is printed in one piece,
 	 * mask out CAM interrupts.
 	 */
-	s = splsoftcam();
 	printf("%s%d at %s%d bus %d target %d lun %d\n",
 	       periph->periph_name, periph->unit_number,
 	       path->bus->sim->sim_name,
@@ -1612,6 +1688,9 @@
 	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) {
+		return;
+	}
 
 	/* Ask the SIM for its base transfer speed */
 	xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1);
@@ -1641,6 +1720,13 @@
 		}
 	}
 
+	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SAS) {
+		struct	ccb_trans_settings_sas *sas = &cts.xport_specific.sas;
+		if (sas->valid & CTS_SAS_VALID_SPEED) {
+			speed = sas->bitrate;
+		}
+	}
+
 	mb = speed / 1000;
 	if (mb > 0)
 		printf("%s%d: %d.%03dMB/s transfers",
@@ -1687,7 +1773,7 @@
 
 	if (path->device->inq_flags & SID_CmdQue
 	 || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) {
-		printf("\n%s%d: Tagged Queueing Enabled",
+		printf("\n%s%d: Command Queueing Enabled",
 		       periph->periph_name, periph->unit_number);
 	}
 	printf("\n");
@@ -1699,116 +1785,8 @@
 	if (announce_string != NULL)
 		printf("%s%d: %s\n", periph->periph_name,
 		       periph->unit_number, announce_string);
-	splx(s);
-}
-#else /* CAM_NEW_TRAN_CODE */
-void
-xpt_announce_periph(struct cam_periph *periph, char *announce_string)
-{
-	int s;
-	u_int mb;
-	struct cam_path *path;
-	struct ccb_trans_settings cts;
-
-	GIANT_REQUIRED;
-
-	path = periph->path;
-	/*
-	 * To ensure that this is printed in one piece,
-	 * mask out CAM interrupts.
-	 */
-	s = splsoftcam();
-	printf("%s%d at %s%d bus %d target %d lun %d\n",
-	       periph->periph_name, periph->unit_number,
-	       path->bus->sim->sim_name,
-	       path->bus->sim->unit_number,
-	       path->bus->sim->bus_id,
-	       path->target->target_id,
-	       path->device->lun_id);
-	printf("%s%d: ", periph->periph_name, periph->unit_number);
-	scsi_print_inquiry(&path->device->inq_data);
-	if ((bootverbose)
-	 && (path->device->serial_num_len > 0)) {
-		/* Don't wrap the screen  - print only the first 60 chars */
-		printf("%s%d: Serial Number %.60s\n", periph->periph_name,
-		       periph->unit_number, path->device->serial_num);
-	}
-	xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1);
-	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
-	cts.flags = CCB_TRANS_CURRENT_SETTINGS;
-	xpt_action((union ccb*)&cts);
-	if (cts.ccb_h.status == CAM_REQ_CMP) {
-		u_int speed;
-		u_int freq;
-
-		if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0
-		  && cts.sync_offset != 0) {
-			freq = scsi_calc_syncsrate(cts.sync_period);
-			speed = freq;
-		} else {
-			struct ccb_pathinq cpi;
-
-			/* Ask the SIM for its base transfer speed */
-			xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1);
-			cpi.ccb_h.func_code = XPT_PATH_INQ;
-			xpt_action((union ccb *)&cpi);
-
-			speed = cpi.base_transfer_speed;
-			freq = 0;
-		}
-		if ((cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0)
-			speed *= (0x01 << cts.bus_width);
-		mb = speed / 1000;
-		if (mb > 0)
-			printf("%s%d: %d.%03dMB/s transfers",
-			       periph->periph_name, periph->unit_number,
-			       mb, speed % 1000);
-		else
-			printf("%s%d: %dKB/s transfers", periph->periph_name,
-			       periph->unit_number, speed);
-		if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0
-		 && cts.sync_offset != 0) {
-			printf(" (%d.%03dMHz, offset %d", freq / 1000,
-			       freq % 1000, cts.sync_offset);
-		}
-		if ((cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0
-		 && cts.bus_width > 0) {
-			if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0
-			 && cts.sync_offset != 0) {
-				printf(", ");
-			} else {
-				printf(" (");
-			}
-			printf("%dbit)", 8 * (0x01 << cts.bus_width));
-		} else if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0
-			&& cts.sync_offset != 0) {
-			printf(")");
-		}
-
-		if (path->device->inq_flags & SID_CmdQue
-		 || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) {
-			printf(", Tagged Queueing Enabled");
-		}
-
-		printf("\n");
-	} else if (path->device->inq_flags & SID_CmdQue
-   		|| path->device->flags & CAM_DEV_TAG_AFTER_COUNT) {
-		printf("%s%d: Tagged Queueing Enabled\n",
-		       periph->periph_name, periph->unit_number);
-	}
-
-	/*
-	 * We only want to print the caller's announce string if they've
-	 * passed one in..
-	 */
-	if (announce_string != NULL)
-		printf("%s%d: %s\n", periph->periph_name,
-		       periph->unit_number, announce_string);
-	splx(s);
 }
 
-#endif /* CAM_NEW_TRAN_CODE */
-
 static dev_match_ret
 xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns,
 	    struct cam_eb *bus)
@@ -2194,7 +2172,7 @@
 
 			cdm->pos.cookie.bus = bus;
 			cdm->pos.generations[CAM_BUS_GENERATION]=
-				bus_generation;
+				xsoftc.bus_generation;
 			cdm->status = CAM_DEV_MATCH_MORE;
 			return(0);
 		}
@@ -2326,7 +2304,7 @@
 
 			cdm->pos.cookie.bus = device->target->bus;
 			cdm->pos.generations[CAM_BUS_GENERATION]=
-				bus_generation;
+				xsoftc.bus_generation;
 			cdm->pos.cookie.target = device->target;
 			cdm->pos.generations[CAM_TARGET_GENERATION] =
 				device->target->bus->generation;
@@ -2436,7 +2414,7 @@
 
 			cdm->pos.cookie.bus = periph->path->bus;
 			cdm->pos.generations[CAM_BUS_GENERATION]=
-				bus_generation;
+				xsoftc.bus_generation;
 			cdm->pos.cookie.target = periph->path->target;
 			cdm->pos.generations[CAM_TARGET_GENERATION] =
 				periph->path->bus->generation;
@@ -2481,7 +2459,7 @@
 	 */
 	if ((cdm->pos.position_type & CAM_DEV_POS_BUS)
 	 && (cdm->pos.generations[CAM_BUS_GENERATION] != 0)
-	 && (cdm->pos.generations[CAM_BUS_GENERATION] != bus_generation)) {
+	 && (cdm->pos.generations[CAM_BUS_GENERATION] != xsoftc.bus_generation)) {
 		cdm->status = CAM_DEV_MATCH_LIST_CHANGED;
 		return(0);
 	}
@@ -2680,15 +2658,21 @@
 
 	retval = 1;
 
-	for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xpt_busses));
+	mtx_lock(&xsoftc.xpt_topo_lock);
+	for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xsoftc.xpt_busses));
 	     bus != NULL;
 	     bus = next_bus) {
 		next_bus = TAILQ_NEXT(bus, links);
 
+		mtx_unlock(&xsoftc.xpt_topo_lock);
+		CAM_SIM_LOCK(bus->sim);
 		retval = tr_func(bus, arg);
+		CAM_SIM_UNLOCK(bus->sim);
 		if (retval == 0)
 			return(retval);
+		mtx_lock(&xsoftc.xpt_topo_lock);
 	}
+	mtx_unlock(&xsoftc.xpt_topo_lock);
 
 	return(retval);
 }
@@ -2899,23 +2883,6 @@
 	return(xptbustraverse(NULL, xptdefbusfunc, &tr_config));
 }
 
-#ifdef notusedyet
-/*
- * Execute the given function for every target in the EDT.
- */
-static int
-xpt_for_all_targets(xpt_targetfunc_t *tr_func, void *arg)
-{
-	struct xpt_traverse_config tr_config;
-
-	tr_config.depth = XPT_DEPTH_TARGET;
-	tr_config.tr_func = tr_func;
-	tr_config.tr_arg = arg;
-
-	return(xptbustraverse(NULL, xptdefbusfunc, &tr_config));
-}
-#endif /* notusedyet */
-
 /*
  * Execute the given function for every device in the EDT.
  */
@@ -2931,23 +2898,6 @@
 	return(xptbustraverse(NULL, xptdefbusfunc, &tr_config));
 }
 
-#ifdef notusedyet
-/*
- * Execute the given function for every peripheral in the EDT.
- */
-static int
-xpt_for_all_periphs(xpt_periphfunc_t *tr_func, void *arg)
-{
-	struct xpt_traverse_config tr_config;
-
-	tr_config.depth = XPT_DEPTH_PERIPH;
-	tr_config.tr_func = tr_func;
-	tr_config.tr_arg = arg;
-
-	return(xptbustraverse(NULL, xptdefbusfunc, &tr_config));
-}
-#endif /* notusedyet */
-
 static int
 xptsetasyncfunc(struct cam_ed *device, void *arg)
 {
@@ -3006,24 +2956,47 @@
 	return(1);
 }
 
+static void
+xpt_action_sasync_cb(void *context, int pending)
+{
+	struct async_node *cur_entry;
+	struct xpt_task *task;
+	uint32_t added;
+
+	task = (struct xpt_task *)context;
+	cur_entry = (struct async_node *)task->data1;
+	added = task->data2;
+
+	if ((added & AC_FOUND_DEVICE) != 0) {
+		/*
+		 * Get this peripheral up to date with all
+		 * the currently existing devices.
+		 */
+		xpt_for_all_devices(xptsetasyncfunc, cur_entry);
+	}
+	if ((added & AC_PATH_REGISTERED) != 0) {
+		/*
+		 * Get this peripheral up to date with all
+		 * the currently existing busses.
+		 */
+		xpt_for_all_busses(xptsetasyncbusfunc, cur_entry);
+		}
+
+	free(task, M_CAMXPT);
+}
+
 void
 xpt_action(union ccb *start_ccb)
 {
-	int iopl;
-
-	GIANT_REQUIRED;
 
 	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n"));
 
 	start_ccb->ccb_h.status = CAM_REQ_INPROG;
 
-	iopl = splsoftcam();
 	switch (start_ccb->ccb_h.func_code) {
 	case XPT_SCSI_IO:
 	{
-#ifdef CAM_NEW_TRAN_CODE
 		struct cam_ed *device;
-#endif /* CAM_NEW_TRAN_CODE */
 #ifdef CAMDEBUG
 		char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
 		struct cam_path *path;
@@ -3047,12 +3020,8 @@
 		 * This means that this code will be exercised while probing
 		 * devices with an ANSI revision greater than 2.
 		 */
-#ifdef CAM_NEW_TRAN_CODE
 		device = start_ccb->ccb_h.path->device;
 		if (device->protocol_version <= SCSI_REV_2
-#else /* CAM_NEW_TRAN_CODE */
-		if (SID_ANSI_REV(&start_ccb->ccb_h.path->device->inq_data) <= 2
-#endif /* CAM_NEW_TRAN_CODE */
 		 && start_ccb->ccb_h.target_lun < 8
 		 && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) {
 
@@ -3077,18 +3046,15 @@
 	{
 		struct cam_path *path;
 		struct cam_sim *sim;
-		int s;
 		int runq;
 
 		path = start_ccb->ccb_h.path;
-		s = splsoftcam();
 
 		sim = path->bus->sim;
 		if (SIM_DEAD(sim)) {
 			/* The SIM has gone; just execute the CCB directly. */
 			cam_ccbq_send_ccb(&path->device->ccbq, start_ccb);
 			(*(sim->sim_action))(sim, start_ccb);
-			splx(s);
 			break;
 		}
 
@@ -3097,7 +3063,6 @@
 			runq = xpt_schedule_dev_sendq(path->bus, path->device);
 		else
 			runq = 0;
-		splx(s);
 		if (runq != 0)
 			xpt_run_dev_sendq(path->bus);
 		break;
@@ -3144,7 +3109,6 @@
 	case XPT_ABORT:
 	{
 		union ccb* abort_ccb;
-		int s;				
 
 		abort_ccb = start_ccb->cab.abort_ccb;
 		if (XPT_FC_IS_DEV_QUEUED(abort_ccb)) {
@@ -3157,9 +3121,7 @@
 				abort_ccb->ccb_h.status =
 				    CAM_REQ_ABORTED|CAM_DEV_QFRZN;
 				xpt_freeze_devq(abort_ccb->ccb_h.path, 1);
-				s = splcam();
 				xpt_done(abort_ccb);
-				splx(s);
 				start_ccb->ccb_h.status = CAM_REQ_CMP;
 				break;
 			}
@@ -3222,10 +3184,8 @@
 	case XPT_GDEV_TYPE:
 	{
 		struct cam_ed *dev;
-		int s;
 
 		dev = start_ccb->ccb_h.path->device;
-		s = splcam();
 		if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) {
 			start_ccb->ccb_h.status = CAM_DEV_NOT_THERE;
 		} else {
@@ -3244,16 +3204,13 @@
 				bcopy(dev->serial_num, cgd->serial_num,
 				      dev->serial_num_len);
 		}
-		splx(s);
 		break; 
 	}
 	case XPT_GDEV_STATS:
 	{
 		struct cam_ed *dev;
-		int s;
 
 		dev = start_ccb->ccb_h.path->device;
-		s = splcam();
 		if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) {
 			start_ccb->ccb_h.status = CAM_DEV_NOT_THERE;
 		} else {
@@ -3276,7 +3233,6 @@
 				cgds->last_reset = bus->last_reset;
 			cgds->ccb_h.status = CAM_REQ_CMP;
 		}
-		splx(s);
 		break;
 	}
 	case XPT_GDEVLIST:
@@ -3285,7 +3241,6 @@
 		struct periph_list	*periph_head;
 		struct ccb_getdevlist	*cgdl;
 		u_int			i;
-		int			s;
 		struct cam_ed		*device;
 		int			found;
 
@@ -3295,7 +3250,6 @@
 		/*
 		 * Don't want anyone mucking with our data.
 		 */
-		s = splcam();
 		device = start_ccb->ccb_h.path->device;
 		periph_head = &device->periphs;
 		cgdl = &start_ccb->cgdl;
@@ -3309,7 +3263,6 @@
 		if ((cgdl->index != 0) && 
 		    (cgdl->generation != device->generation)) {
 			cgdl->status = CAM_GDEVLIST_LIST_CHANGED;
-			splx(s);
 			break;
 		}
 
@@ -3330,7 +3283,6 @@
 		}
 		if (found == 0) {
 			cgdl->status = CAM_GDEVLIST_ERROR;
-			splx(s);
 			break;
 		}
 
@@ -3342,23 +3294,17 @@
 		cgdl->index++;
 		cgdl->generation = device->generation;
 
-		splx(s);
 		cgdl->ccb_h.status = CAM_REQ_CMP;
 		break;
 	}
 	case XPT_DEV_MATCH:
 	{
-		int s;
 		dev_pos_type position_type;
 		struct ccb_dev_match *cdm;
 
 		cdm = &start_ccb->cdm;
 
 		/*
-		 * Prevent EDT changes while we traverse it.
-		 */
-		s = splcam();
-		/*
 		 * There are two ways of getting at information in the EDT.
 		 * The first way is via the primary EDT tree.  It starts
 		 * with a list of busses, then a list of targets on a bus,
@@ -3405,8 +3351,6 @@
 			break;
 		}
 
-		splx(s);
-
 		if (cdm->status == CAM_DEV_MATCH_ERROR)
 			start_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
 		else
@@ -3420,7 +3364,6 @@
 		struct async_node *cur_entry;
 		struct async_list *async_head;
 		u_int32_t added;
-		int s;
 
 		csa = &start_ccb->csa;
 		added = csa->event_enable;
@@ -3430,7 +3373,6 @@
 		 * If there is already an entry for us, simply
 		 * update it.
 		 */
-		s = splcam();
 		cur_entry = SLIST_FIRST(async_head);
 		while (cur_entry != NULL) {
 			if ((cur_entry->callback_arg == csa->callback_arg)
@@ -3457,7 +3399,6 @@
 			cur_entry = malloc(sizeof(*cur_entry), M_CAMXPT,
 					   M_NOWAIT);
 			if (cur_entry == NULL) {
-				splx(s);
 				csa->ccb_h.status = CAM_RESRC_UNAVAIL;
 				break;
 			}
@@ -3468,21 +3409,26 @@
 			csa->ccb_h.path->device->refcount++;
 		}
 
-		if ((added & AC_FOUND_DEVICE) != 0) {
-			/*
-			 * Get this peripheral up to date with all
-			 * the currently existing devices.
-			 */
-			xpt_for_all_devices(xptsetasyncfunc, cur_entry);
-		}
-		if ((added & AC_PATH_REGISTERED) != 0) {
-			/*
-			 * Get this peripheral up to date with all
-			 * the currently existing busses.
-			 */
-			xpt_for_all_busses(xptsetasyncbusfunc, cur_entry);
+		/*
+		 * Need to decouple this operation via a taqskqueue so that
+		 * the locking doesn't become a mess.
+		 */
+		if ((added & (AC_FOUND_DEVICE | AC_PATH_REGISTERED)) != 0) {
+			struct xpt_task *task;
+
+			task = malloc(sizeof(struct xpt_task), M_CAMXPT,
+				      M_NOWAIT);
+			if (task == NULL) {
+				csa->ccb_h.status = CAM_RESRC_UNAVAIL;
+				break;
+			}
+
+			TASK_INIT(&task->task, 0, xpt_action_sasync_cb, task);
+			task->data1 = cur_entry;
+			task->data2 = added;
+			taskqueue_enqueue(taskqueue_thread, &task->task);
 		}
-		splx(s);
+
 		start_ccb->ccb_h.status = CAM_REQ_CMP;
 		break;
 	}
@@ -3490,7 +3436,6 @@
 	{
 		struct ccb_relsim *crs;
 		struct cam_ed *dev;
-		int s;
 
 		crs = &start_ccb->crs;
 		dev = crs->ccb_h.path->device;
@@ -3500,8 +3445,6 @@
 			break;
 		}
 
-		s = splcam();
-
 		if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) {
 
  			if (INQ_DATA_TQ_ENABLED(&dev->inq_data)) {
@@ -3511,10 +3454,9 @@
 							    crs->openings);
 
 					if (bootverbose) {
-						xpt_print_path(crs->ccb_h.path);
-						printf("tagged openings "
-						       "now %d\n",
-						       crs->openings);
+						xpt_print(crs->ccb_h.path,
+						    "tagged openings now %d\n",
+						    crs->openings);
 					}
 				}
 			}
@@ -3530,17 +3472,15 @@
 				 * is sufficient for releasing the queue.
 				 */
 				start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE;
-				untimeout(xpt_release_devq_timeout,
-					  dev, dev->c_handle);
+				callout_stop(&dev->callout);
 			} else {
 
 				start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
 			}
 
-			dev->c_handle =
-				timeout(xpt_release_devq_timeout,
-					dev,
-					(crs->release_timeout * hz) / 1000);
+			callout_reset(&dev->callout,
+			    (crs->release_timeout * hz) / 1000,
+			    xpt_release_devq_timeout, dev);
 
 			dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING;
 
@@ -3574,8 +3514,7 @@
 				start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
 			}
 		}
-		splx(s);
-		
+
 		if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) {
 
 			xpt_release_devq(crs->ccb_h.path, /*count*/1,
@@ -3595,9 +3534,6 @@
 		break;
 	case XPT_DEBUG: {
 #ifdef CAMDEBUG
-		int s;
-		
-		s = splcam();
 #ifdef CAM_DEBUG_DELAY
 		cam_debug_delay = CAM_DEBUG_DELAY;
 #endif
@@ -3617,14 +3553,13 @@
 				cam_dflags = CAM_DEBUG_NONE;
 			} else {
 				start_ccb->ccb_h.status = CAM_REQ_CMP;
-				xpt_print_path(cam_dpath);
-				printf("debugging flags now %x\n", cam_dflags);
+				xpt_print(cam_dpath, "debugging flags now %x\n",
+				    cam_dflags);
 			}
 		} else {
 			cam_dpath = NULL;
 			start_ccb->ccb_h.status = CAM_REQ_CMP;
 		}
-		splx(s);
 #else /* !CAMDEBUG */
 		start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
 #endif /* CAMDEBUG */
@@ -3643,26 +3578,23 @@
 		start_ccb->ccb_h.status = CAM_PROVIDE_FAIL;
 		break;
 	}
-	splx(iopl);
 }
 
 void
 xpt_polled_action(union ccb *start_ccb)
 {
-	int	  s;
 	u_int32_t timeout;
 	struct	  cam_sim *sim;	
 	struct	  cam_devq *devq;
 	struct	  cam_ed *dev;
 
-	GIANT_REQUIRED;
 
 	timeout = start_ccb->ccb_h.timeout;
 	sim = start_ccb->ccb_h.path->bus->sim;
 	devq = sim->devq;
 	dev = start_ccb->ccb_h.path->device;
 
-	s = splcam();
+	mtx_assert(sim->mtx, MA_OWNED);
 
 	/*
 	 * Steal an opening so that no other queued requests
@@ -3675,7 +3607,7 @@
 	   dev->ccbq.dev_openings < 0) && (--timeout > 0)) {
 		DELAY(1000);
 		(*(sim->sim_poll))(sim);
-		camisr(&cam_bioq);
+		camisr_runqueue(&sim->sim_doneq);
 	}
 	
 	dev->ccbq.devq_openings++;
@@ -3685,7 +3617,7 @@
 		xpt_action(start_ccb);
 		while(--timeout > 0) {
 			(*(sim->sim_poll))(sim);
-			camisr(&cam_bioq);
+			camisr_runqueue(&sim->sim_doneq);
 			if ((start_ccb->ccb_h.status  & CAM_STATUS_MASK)
 			    != CAM_REQ_INPROG)
 				break;
@@ -3703,7 +3635,6 @@
 	} else {
 		start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 	}
-	splx(s);
 }
 	
 /*
@@ -3715,14 +3646,12 @@
 {
 	struct cam_ed *device;
 	union ccb *work_ccb;
-	int s;
 	int runq;
 
-	GIANT_REQUIRED;
+	mtx_assert(perph->sim->mtx, MA_OWNED);
 
 	CAM_DEBUG(perph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n"));
 	device = perph->path->device;
-	s = splsoftcam();
 	if (periph_is_queued(perph)) {
 		/* Simply reorder based on new priority */
 		CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE,
@@ -3736,7 +3665,6 @@
 	} else if (SIM_DEAD(perph->path->bus->sim)) {
 		/* The SIM is gone so just call periph_start directly. */
 		work_ccb = xpt_get_ccb(perph->path->device);
-		splx(s);
 		if (work_ccb == NULL)
 			return; /* XXX */
 		xpt_setup_ccb(&work_ccb->ccb_h, perph->path, new_priority);
@@ -3752,7 +3680,6 @@
 		camq_insert(&device->drvq, &perph->pinfo);
 		runq = xpt_schedule_dev_allocq(perph->path->bus, device);
 	}
-	splx(s);
 	if (runq != 0) {
 		CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE,
 			  ("   calling xpt_run_devq\n"));
@@ -3767,8 +3694,7 @@
  * return 1 meaning the device queue should be run. If we
  * were already queued, implying someone else has already
  * started the queue, return 0 so the caller doesn't attempt
- * to run the queue.  Must be run at either splsoftcam
- * (or splcam since that encompases splsoftcam).
+ * to run the queue.
  */
 static int
 xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo,
@@ -3812,7 +3738,6 @@
 xpt_run_dev_allocq(struct cam_eb *bus)
 {
 	struct	cam_devq *devq;
-	int	s;
 
 	CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_allocq\n"));
 	devq = bus->sim->devq;
@@ -3825,7 +3750,6 @@
 			 devq->alloc_openings,
 			 devq->alloc_active));
 
-	s = splsoftcam();
 	devq->alloc_queue.qfrozen_cnt++;
 	while ((devq->alloc_queue.entries > 0)
 	    && (devq->alloc_openings > 0)
@@ -3855,7 +3779,6 @@
 			devq->alloc_openings--;
 			devq->alloc_active++;
 			drv = (struct cam_periph*)camq_remove(drvq, CAMQ_HEAD);
-			splx(s);
 			xpt_setup_ccb(&work_ccb->ccb_h, drv->path,
 				      drv->pinfo.priority);
 			CAM_DEBUG_PRINT(CAM_DEBUG_XPT,
@@ -3874,43 +3797,32 @@
 			break;
 		}
 	
-		/* Raise IPL for possible insertion and test at top of loop */
-		s = splsoftcam();
-
 		if (drvq->entries > 0) {
 			/* We have more work.  Attempt to reschedule */
 			xpt_schedule_dev_allocq(bus, device);
 		}
 	}
 	devq->alloc_queue.qfrozen_cnt--;
-	splx(s);
 }
 
 static void
 xpt_run_dev_sendq(struct cam_eb *bus)
 {
 	struct	cam_devq *devq;
-	int	s;
 
 	CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_sendq\n"));
 	
 	devq = bus->sim->devq;
 
-	s = splcam();
 	devq->send_queue.qfrozen_cnt++;
-	splx(s);
-	s = splsoftcam();
 	while ((devq->send_queue.entries > 0)
 	    && (devq->send_openings > 0)) {
 		struct	cam_ed_qinfo *qinfo;
 		struct	cam_ed *device;
 		union ccb *work_ccb;
 		struct	cam_sim *sim;
-		int	ospl;
 
-		ospl = splcam();
 	    	if (devq->send_queue.qfrozen_cnt > 1) {
-			splx(ospl);
 			break;
 		}
 
@@ -3923,7 +3835,6 @@
 		 * to run it.
 		 */
 		if (device->qfrozen_cnt > 0) {
-			splx(ospl);
 			continue;
 		}
 
@@ -3933,13 +3844,13 @@
 		work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD);
 		if (work_ccb == NULL) {
 			printf("device on run queue with no ccbs???\n");
-			splx(ospl);
 			continue;
 		}
 
 		if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) {
 
-		 	if (num_highpower <= 0) {
+			mtx_lock(&xsoftc.xpt_lock);
+		 	if (xsoftc.num_highpower <= 0) {
 				/*
 				 * We got a high power command, but we
 				 * don't have any available slots.  Freeze
@@ -3947,25 +3858,24 @@
 				 * available.
 				 */
 				device->qfrozen_cnt++;
-				STAILQ_INSERT_TAIL(&highpowerq, 
+				STAILQ_INSERT_TAIL(&xsoftc.highpowerq, 
 						   &work_ccb->ccb_h, 
 						   xpt_links.stqe);
 
-				splx(ospl);
 				continue;
 			} else {
 				/*
 				 * Consume a high power slot while
 				 * this ccb runs.
 				 */
-				num_highpower--;
+				xsoftc.num_highpower--;
 			}
+			mtx_unlock(&xsoftc.xpt_lock);
 		}
 		devq->active_dev = device;
 		cam_ccbq_remove_ccb(&device->ccbq, work_ccb);
 
 		cam_ccbq_send_ccb(&device->ccbq, work_ccb);
-		splx(ospl);
 
 		devq->send_openings--;
 		devq->send_active++;		
@@ -3978,12 +3888,8 @@
 			 * The client wants to freeze the queue
 			 * after this CCB is sent.
 			 */
-			ospl = splcam();
 			device->qfrozen_cnt++;
-			splx(ospl);
 		}
-		
-		splx(s);
 
 		/* In Target mode, the peripheral driver knows best... */
 		if (work_ccb->ccb_h.func_code == XPT_SCSI_IO) {
@@ -4007,16 +3913,9 @@
 		sim = work_ccb->ccb_h.path->bus->sim;
 		(*(sim->sim_action))(sim, work_ccb);
 
-		ospl = splcam();
 		devq->active_dev = NULL;
-		splx(ospl);
-		/* Raise IPL for possible insertion and test at top of loop */
-		s = splsoftcam();
 	}
-	splx(s);
-	s = splcam();
 	devq->send_queue.qfrozen_cnt--;
-	splx(s);
 }
 
 /*
@@ -4026,7 +3925,6 @@
 void
 xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb)
 {
-	GIANT_REQUIRED;
 
 	/*
 	 * Pull fields that are valid for peripheral drivers to set
@@ -4043,7 +3941,6 @@
 void
 xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority)
 {
-	GIANT_REQUIRED;
 
 	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n"));
 	ccb_h->pinfo.priority = priority;
@@ -4071,8 +3968,6 @@
 	struct	   cam_path *path;
 	cam_status status;
 
-	GIANT_REQUIRED;
-
 	path = (struct cam_path *)malloc(sizeof(*path), M_CAMXPT, M_NOWAIT);
 
 	if (path == NULL) {
@@ -4088,6 +3983,36 @@
 	return (status);
 }
 
+cam_status
+xpt_create_path_unlocked(struct cam_path **new_path_ptr,
+			 struct cam_periph *periph, path_id_t path_id,
+			 target_id_t target_id, lun_id_t lun_id)
+{
+	struct	   cam_path *path;
+	struct	   cam_eb *bus = NULL;
+	cam_status status;
+	int	   need_unlock = 0;
+
+	path = (struct cam_path *)malloc(sizeof(*path), M_CAMXPT, M_WAITOK);
+
+	if (path_id != CAM_BUS_WILDCARD) {
+		bus = xpt_find_bus(path_id);
+		if (bus != NULL) {
+			need_unlock = 1;
+			CAM_SIM_LOCK(bus->sim);
+		}
+	}
+	status = xpt_compile_path(path, periph, path_id, target_id, lun_id);
+	if (need_unlock)
+		CAM_SIM_UNLOCK(bus->sim);
+	if (status != CAM_REQ_CMP) {
+		free(path, M_CAMXPT);
+		path = NULL;
+	}
+	*new_path_ptr = path;
+	return (status);
+}
+
 static cam_status
 xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph,
 		 path_id_t path_id, target_id_t target_id, lun_id_t lun_id)
@@ -4096,7 +4021,6 @@
 	struct	     cam_et *target;
 	struct	     cam_ed *device;
 	cam_status   status;
-	int	     s;
 
 	status = CAM_REQ_CMP;	/* Completed without error */
 	target = NULL;		/* Wildcarded */
@@ -4106,7 +4030,6 @@
 	 * We will potentially modify the EDT, so block interrupts
 	 * that may attempt to create cam paths.
 	 */
-	s = splcam();
 	bus = xpt_find_bus(path_id);
 	if (bus == NULL) {
 		status = CAM_PATH_INVALID;
@@ -4140,7 +4063,6 @@
 			}
 		}
 	}
-	splx(s);
 
 	/*
 	 * Only touch the user's data if we are successful.
@@ -4183,7 +4105,6 @@
 void
 xpt_free_path(struct cam_path *path)
 {
-	GIANT_REQUIRED;
 
 	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n"));
 	xpt_release_path(path);
@@ -4198,8 +4119,6 @@
 int
 xpt_path_comp(struct cam_path *path1, struct cam_path *path2)
 {
-	GIANT_REQUIRED;
-
 	int retval = 0;
 
 	if (path1->bus != path2->bus) {
@@ -4234,7 +4153,6 @@
 void
 xpt_print_path(struct cam_path *path)
 {
-	GIANT_REQUIRED;
 
 	if (path == NULL)
 		printf("(nopath): ");
@@ -4264,12 +4182,22 @@
 	}
 }
 
+void
+xpt_print(struct cam_path *path, const char *fmt, ...)
+{
+	va_list ap;
+	xpt_print_path(path);
+	va_start(ap, fmt);
+	vprintf(fmt, ap);
+	va_end(ap);
+}
+
 int
 xpt_path_string(struct cam_path *path, char *str, size_t str_len)
 {
 	struct sbuf sb;
 
-	GIANT_REQUIRED;
+	mtx_assert(path->bus->sim->mtx, MA_OWNED);
 
 	sbuf_new(&sb, str, str_len, 0);
 
@@ -4307,7 +4235,7 @@
 path_id_t
 xpt_path_path_id(struct cam_path *path)
 {
-	GIANT_REQUIRED;
+	mtx_assert(path->bus->sim->mtx, MA_OWNED);
 
 	return(path->bus->path_id);
 }
@@ -4315,7 +4243,7 @@
 target_id_t
 xpt_path_target_id(struct cam_path *path)
 {
-	GIANT_REQUIRED;
+	mtx_assert(path->bus->sim->mtx, MA_OWNED);
 
 	if (path->target != NULL)
 		return (path->target->target_id);
@@ -4326,7 +4254,7 @@
 lun_id_t
 xpt_path_lun_id(struct cam_path *path)
 {
-	GIANT_REQUIRED;
+	mtx_assert(path->bus->sim->mtx, MA_OWNED);
 
 	if (path->device != NULL)
 		return (path->device->lun_id);
@@ -4337,7 +4265,6 @@
 struct cam_sim *
 xpt_path_sim(struct cam_path *path)
 {
-	GIANT_REQUIRED;
 
 	return (path->bus->sim);
 }
@@ -4345,7 +4272,7 @@
 struct cam_periph*
 xpt_path_periph(struct cam_path *path)
 {
-	GIANT_REQUIRED;
+	mtx_assert(path->bus->sim->mtx, MA_OWNED);
 
 	return (path->periph);
 }
@@ -4359,38 +4286,38 @@
 void
 xpt_release_ccb(union ccb *free_ccb)
 {
-	int	 s;
 	struct	 cam_path *path;
 	struct	 cam_ed *device;
 	struct	 cam_eb *bus;
-
-	GIANT_REQUIRED;
+	struct   cam_sim *sim;
 
 	CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n"));
 	path = free_ccb->ccb_h.path;
 	device = path->device;
 	bus = path->bus;
-	s = splsoftcam();
+	sim = bus->sim;
+
+	mtx_assert(sim->mtx, MA_OWNED);
+
 	cam_ccbq_release_opening(&device->ccbq);
-	if (xpt_ccb_count > xpt_max_ccbs) {
+	if (sim->ccb_count > sim->max_ccbs) {
 		xpt_free_ccb(free_ccb);
-		xpt_ccb_count--;
+		sim->ccb_count--;
 	} else {
-		SLIST_INSERT_HEAD(&ccb_freeq, &free_ccb->ccb_h, xpt_links.sle);
+		SLIST_INSERT_HEAD(&sim->ccb_freeq, &free_ccb->ccb_h,
+		    xpt_links.sle);
 	}
-	if (bus->sim->devq == NULL) {
-		splx(s);
+	if (sim->devq == NULL) {
 		return;
 	}
-	bus->sim->devq->alloc_openings++;
-	bus->sim->devq->alloc_active--;
+	sim->devq->alloc_openings++;
+	sim->devq->alloc_active--;
 	/* XXX Turn this into an inline function - xpt_run_device?? */
 	if ((device_is_alloc_queued(device) == 0)
 	 && (device->drvq.entries > 0)) {
 		xpt_schedule_dev_allocq(bus, device);
 	}
-	splx(s);
-	if (dev_allocq_is_runnable(bus->sim->devq))
+	if (dev_allocq_is_runnable(sim->devq))
 		xpt_run_dev_allocq(bus);
 }
 
@@ -4406,14 +4333,13 @@
  * availible, the bus will be probed.
  */
 int32_t
-xpt_bus_register(struct cam_sim *sim, u_int32_t bus)
+xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus)
 {
 	struct cam_eb *new_bus;
 	struct cam_eb *old_bus;
 	struct ccb_pathinq cpi;
-	int s;
 
-	GIANT_REQUIRED;
+	mtx_assert(sim->mtx, MA_OWNED);
 
 	sim->bus_id = bus;
 	new_bus = (struct cam_eb *)malloc(sizeof(*new_bus),
@@ -4436,17 +4362,17 @@
 	new_bus->flags = 0;
 	new_bus->refcount = 1;	/* Held until a bus_deregister event */
 	new_bus->generation = 0;
-	s = splcam();
-	old_bus = TAILQ_FIRST(&xpt_busses);
+	mtx_lock(&xsoftc.xpt_topo_lock);
+	old_bus = TAILQ_FIRST(&xsoftc.xpt_busses);
 	while (old_bus != NULL
 	    && old_bus->path_id < new_bus->path_id)
 		old_bus = TAILQ_NEXT(old_bus, links);
 	if (old_bus != NULL)
 		TAILQ_INSERT_BEFORE(old_bus, new_bus, links);
 	else
-		TAILQ_INSERT_TAIL(&xpt_busses, new_bus, links);
-	bus_generation++;
-	splx(s);
+		TAILQ_INSERT_TAIL(&xsoftc.xpt_busses, new_bus, links);
+	xsoftc.bus_generation++;
+	mtx_unlock(&xsoftc.xpt_topo_lock);
 
 	/* Notify interested parties */
 	if (sim->path_id != CAM_XPT_PATH_ID) {
@@ -4475,7 +4401,6 @@
 	union ccb *work_ccb;
 	cam_status status;
 
-	GIANT_REQUIRED;
 
 	status = xpt_compile_path(&bus_path, NULL, pathid,
 				  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
@@ -4487,6 +4412,7 @@
 
 	/* The SIM may be gone, so use a dummy SIM for any stray operations. */
 	devq = bus_path.bus->sim->devq;
+	ccbsim = bus_path.bus->sim;
 	bus_path.bus->sim = &cam_dead_sim;
 
 	/* Execute any pending operations now. */
@@ -4501,7 +4427,6 @@
 				devq->active_dev = device;
 				cam_ccbq_remove_ccb(&device->ccbq, work_ccb);
 				cam_ccbq_send_ccb(&device->ccbq, work_ccb);
-				ccbsim = work_ccb->ccb_h.path->bus->sim;
 				(*(ccbsim->sim_action))(ccbsim, work_ccb);
 			}
 
@@ -4513,8 +4438,8 @@
 	}
 
 	/* Make sure all completed CCBs are processed. */
-	while (!TAILQ_EMPTY(&cam_bioq)) {
-		camisr(&cam_bioq);
+	while (!TAILQ_EMPTY(&ccbsim->sim_doneq)) {
+		camisr_runqueue(&ccbsim->sim_doneq);
 
 		/* Repeat the async's for the benefit of any new devices. */
 		xpt_async(AC_LOST_DEVICE, &bus_path, NULL);
@@ -4525,10 +4450,6 @@
 	xpt_release_bus(bus_path.bus);
 	xpt_release_path(&bus_path);
 
-	/* Recheck for more completed CCBs. */
-	while (!TAILQ_EMPTY(&cam_bioq))
-		camisr(&cam_bioq);
-
 	return (CAM_REQ_CMP);
 }
 
@@ -4540,15 +4461,16 @@
 	const char *strval;
 
 	pathid = 0;
-	bus = TAILQ_FIRST(&xpt_busses);
+	mtx_lock(&xsoftc.xpt_topo_lock);
+	bus = TAILQ_FIRST(&xsoftc.xpt_busses);
 retry:
 	/* Find an unoccupied pathid */
-	while (bus != NULL
-	    && bus->path_id <= pathid) {
+	while (bus != NULL && bus->path_id <= pathid) {
 		if (bus->path_id == pathid)
 			pathid++;
 		bus = TAILQ_NEXT(bus, links);
 	}
+	mtx_unlock(&xsoftc.xpt_topo_lock);
 
 	/*
 	 * Ensure that this pathid is not reserved for
@@ -4557,6 +4479,7 @@
 	if (resource_string_value("scbus", pathid, "at", &strval) == 0) {
 		++pathid;
 		/* Start the search over */
+		mtx_lock(&xsoftc.xpt_topo_lock);
 		goto retry;
 	}
 	return (pathid);
@@ -4611,9 +4534,8 @@
 	struct cam_eb *bus;
 	struct cam_et *target, *next_target;
 	struct cam_ed *device, *next_device;
-	int s;
 
-	GIANT_REQUIRED;
+	mtx_assert(path->bus->sim->mtx, MA_OWNED);
 
 	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_async\n"));
 
@@ -4621,20 +4543,14 @@
 	 * Most async events come from a CAM interrupt context.  In
 	 * a few cases, the error recovery code at the peripheral layer,
 	 * which may run from our SWI or a process context, may signal
-	 * deferred events with a call to xpt_async. Ensure async
-	 * notifications are serialized by blocking cam interrupts.
+	 * deferred events with a call to xpt_async.
 	 */
-	s = splcam();
 
 	bus = path->bus;
 
 	if (async_code == AC_BUS_RESET) { 
-		int s;
-
-		s = splclock();
 		/* Update our notion of when the last reset occurred */
 		microtime(&bus->last_reset);
-		splx(s);
 	}
 
 	for (target = TAILQ_FIRST(&bus->et_entries);
@@ -4649,12 +4565,8 @@
 			continue;
 
 		if (async_code == AC_SENT_BDR) {
-			int s;
-
 			/* Update our notion of when the last reset occurred */
-			s = splclock();
 			microtime(&path->target->last_reset);
-			splx(s);
 		}
 
 		for (device = TAILQ_FIRST(&target->ed_entries);
@@ -4683,7 +4595,6 @@
 	if (bus != xpt_periph->path->bus)
 		xpt_async_bcast(&xpt_periph->path->device->asyncs, async_code,
 				path, async_arg);
-	splx(s);
 }
 
 static void
@@ -4777,12 +4688,10 @@
 u_int32_t
 xpt_freeze_devq(struct cam_path *path, u_int count)
 {
-	int s;
 	struct ccb_hdr *ccbh;
 
-	GIANT_REQUIRED;
+	mtx_assert(path->bus->sim->mtx, MA_OWNED);
 
-	s = splcam();
 	path->device->qfrozen_cnt += count;
 
 	/*
@@ -4794,21 +4703,20 @@
 	 * freezes the queue.  To completly close the
 	 * hole, controller drives must check to see
 	 * if a ccb's status is still CAM_REQ_INPROG
-	 * under spl protection just before they queue
+	 * just before they queue
 	 * the CCB.  See ahc_action/ahc_freeze_devq for
 	 * an example.
 	 */
 	ccbh = TAILQ_LAST(&path->device->ccbq.active_ccbs, ccb_hdr_tailq);
 	if (ccbh && ccbh->status == CAM_REQ_INPROG)
 		ccbh->status = CAM_REQUEUE_REQ;
-	splx(s);
 	return (path->device->qfrozen_cnt);
 }
 
 u_int32_t
 xpt_freeze_simq(struct cam_sim *sim, u_int count)
 {
-	GIANT_REQUIRED;
+	mtx_assert(sim->mtx, MA_OWNED);
 
 	sim->devq->send_queue.qfrozen_cnt += count;
 	if (sim->devq->active_dev != NULL) {
@@ -4835,7 +4743,7 @@
 void
 xpt_release_devq(struct cam_path *path, u_int count, int run_queue)
 {
-	GIANT_REQUIRED;
+	mtx_assert(path->bus->sim->mtx, MA_OWNED);
 
 	xpt_release_devq_device(path->device, count, run_queue);
 }
@@ -4844,11 +4752,8 @@
 xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue)
 {
 	int	rundevq;
-	int	s0, s1;
 
 	rundevq = 0;
-	s0 = splsoftcam();
-	s1 = splcam();
 	if (dev->qfrozen_cnt > 0) {
 
 		count = (count > dev->qfrozen_cnt) ? dev->qfrozen_cnt : count;
@@ -4866,8 +4771,7 @@
 			 * to release this queue.
 			 */
 			if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) {
-				untimeout(xpt_release_devq_timeout, dev,
-					  dev->c_handle);
+				callout_stop(&dev->callout);
 				dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING;
 			}
 
@@ -4883,22 +4787,18 @@
 			}
 		}
 	}
-	splx(s1);
 	if (rundevq != 0)
 		xpt_run_dev_sendq(dev->target->bus);
-	splx(s0);
 }
 
 void
 xpt_release_simq(struct cam_sim *sim, int run_queue)
 {
-	int	s;
 	struct	camq *sendq;
 
-	GIANT_REQUIRED;
+	mtx_assert(sim->mtx, MA_OWNED);
 
 	sendq = &(sim->devq->send_queue);
-	s = splcam();
 	if (sendq->qfrozen_cnt > 0) {
 
 		sendq->qfrozen_cnt--;
@@ -4911,12 +4811,10 @@
 			 * already at 0.
 			 */
 			if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){
-				untimeout(xpt_release_simq_timeout, sim,
-					  sim->c_handle);
+				callout_stop(&sim->callout);
 				sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING;
 			}
 			bus = xpt_find_bus(sim->path_id);
-			splx(s);
 
 			if (run_queue) {
 				/*
@@ -4925,13 +4823,14 @@
 				xpt_run_dev_sendq(bus);
 			}
 			xpt_release_bus(bus);
-		} else
-			splx(s);
-	} else
-		splx(s);
+		}
+	}
 }
 
-static void
+/*
+ * XXX Appears to be unused.
+ */
+static void
 xpt_release_simq_timeout(void *arg)
 {
 	struct cam_sim *sim;
@@ -4943,9 +4842,7 @@
 void
 xpt_done(union ccb *done_ccb)
 {
-	int s;
-
-	s = splcam();
+	struct cam_sim *sim;
 
 	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done\n"));
 	if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0) {
@@ -4953,21 +4850,28 @@
 		 * Queue up the request for handling by our SWI handler
 		 * any of the "non-immediate" type of ccbs.
 		 */
+		sim = done_ccb->ccb_h.path->bus->sim;
 		switch (done_ccb->ccb_h.path->periph->type) {
 		case CAM_PERIPH_BIO:
-			mtx_lock(&cam_bioq_lock);
-			TAILQ_INSERT_TAIL(&cam_bioq, &done_ccb->ccb_h,
+			TAILQ_INSERT_TAIL(&sim->sim_doneq, &done_ccb->ccb_h,
 					  sim_links.tqe);
 			done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX;
-			mtx_unlock(&cam_bioq_lock);
-			swi_sched(cambio_ih, 0);
+			if ((sim->flags & CAM_SIM_ON_DONEQ) == 0) {
+				mtx_lock(&cam_simq_lock);
+				TAILQ_INSERT_TAIL(&cam_simq, sim,
+						  links);
+				sim->flags |= CAM_SIM_ON_DONEQ;
+				mtx_unlock(&cam_simq_lock);
+			}
+			if ((done_ccb->ccb_h.path->periph->flags &
+			    CAM_PERIPH_POLLED) == 0)
+				swi_sched(cambio_ih, 0);
 			break;
 		default:
 			panic("unknown periph type %d",
 			    done_ccb->ccb_h.path->periph->type);
 		}
 	}
-	splx(s);
 }
 
 union ccb *
@@ -4975,9 +4879,7 @@
 {
 	union ccb *new_ccb;
 
-	GIANT_REQUIRED;
-
-	new_ccb = malloc(sizeof(*new_ccb), M_CAMXPT, M_WAITOK);
+	new_ccb = malloc(sizeof(*new_ccb), M_CAMXPT, M_ZERO|M_WAITOK);
 	return (new_ccb);
 }
 
@@ -4986,9 +4888,7 @@
 {
 	union ccb *new_ccb;
 
-	GIANT_REQUIRED;
-
-	new_ccb = malloc(sizeof(*new_ccb), M_CAMXPT, M_NOWAIT);
+	new_ccb = malloc(sizeof(*new_ccb), M_CAMXPT, M_ZERO|M_NOWAIT);
 	return (new_ccb);
 }
 
@@ -5013,40 +4913,37 @@
 xpt_get_ccb(struct cam_ed *device)
 {
 	union ccb *new_ccb;
-	int s;
+	struct cam_sim *sim;
 
-	s = splsoftcam();
-	if ((new_ccb = (union ccb *)SLIST_FIRST(&ccb_freeq)) == NULL) {
+	sim = device->sim;
+	if ((new_ccb = (union ccb *)SLIST_FIRST(&sim->ccb_freeq)) == NULL) {
 		new_ccb = xpt_alloc_ccb_nowait();
                 if (new_ccb == NULL) {
-			splx(s);
 			return (NULL);
 		}
-		callout_handle_init(&new_ccb->ccb_h.timeout_ch);
-		SLIST_INSERT_HEAD(&ccb_freeq, &new_ccb->ccb_h,
+		if ((sim->flags & CAM_SIM_MPSAFE) == 0)
+			callout_handle_init(&new_ccb->ccb_h.timeout_ch);
+		SLIST_INSERT_HEAD(&sim->ccb_freeq, &new_ccb->ccb_h,
 				  xpt_links.sle);
-		xpt_ccb_count++;
+		sim->ccb_count++;
 	}
 	cam_ccbq_take_opening(&device->ccbq);
-	SLIST_REMOVE_HEAD(&ccb_freeq, xpt_links.sle);
-	splx(s);
+	SLIST_REMOVE_HEAD(&sim->ccb_freeq, xpt_links.sle);
 	return (new_ccb);
 }
 
 static void
 xpt_release_bus(struct cam_eb *bus)
 {
-	int s;
 
-	s = splcam();
 	if ((--bus->refcount == 0)
 	 && (TAILQ_FIRST(&bus->et_entries) == NULL)) {
-		TAILQ_REMOVE(&xpt_busses, bus, links);
-		bus_generation++;
-		splx(s);
+		mtx_lock(&xsoftc.xpt_topo_lock);
+		TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links);
+		xsoftc.bus_generation++;
+		mtx_unlock(&xsoftc.xpt_topo_lock);
 		free(bus, M_CAMXPT);
-	} else
-		splx(s);
+	}
 }
 
 static struct cam_et *
@@ -5088,26 +4985,20 @@
 static void
 xpt_release_target(struct cam_eb *bus, struct cam_et *target)
 {
-	int s;
 
-	s = splcam();
 	if ((--target->refcount == 0)
 	 && (TAILQ_FIRST(&target->ed_entries) == NULL)) {
 		TAILQ_REMOVE(&bus->et_entries, target, links);
 		bus->generation++;
-		splx(s);
 		free(target, M_CAMXPT);
 		xpt_release_bus(bus);
-	} else
-		splx(s);
+	}
 }
 
 static struct cam_ed *
 xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
 {
-#ifdef CAM_NEW_TRAN_CODE
 	struct	   cam_path path;
-#endif /* CAM_NEW_TRAN_CODE */
 	struct	   cam_ed *device;
 	struct	   cam_devq *devq;
 	cam_status status;
@@ -5135,6 +5026,7 @@
 		device->send_ccb_entry.device = device;
 		device->target = target;
 		device->lun_id = lun_id;
+		device->sim = bus->sim;
 		/* Initialize our queues */
 		if (camq_init(&device->drvq, 0) != 0) {
 			free(device, M_CAMXPT);
@@ -5165,7 +5057,10 @@
 		device->tag_delay_count = 0;
 		device->tag_saved_openings = 0;
 		device->refcount = 1;
-		callout_handle_init(&device->c_handle);
+		if (bus->sim->flags & CAM_SIM_MPSAFE)
+			callout_init_mtx(&device->callout, bus->sim->mtx, 0);
+		else
+			callout_init_mtx(&device->callout, &Giant, 0);
 
 		/*
 		 * Hold a reference to our parent target so it
@@ -5177,7 +5072,7 @@
 		 * XXX should be limited by number of CCBs this bus can
 		 * do.
 		 */
-		xpt_max_ccbs += device->ccbq.devq_openings;
+		bus->sim->max_ccbs += device->ccbq.devq_openings;
 		/* Insertion sort into our target's device list */
 		cur_device = TAILQ_FIRST(&target->ed_entries);
 		while (cur_device != NULL && cur_device->lun_id < lun_id)
@@ -5188,7 +5083,6 @@
 			TAILQ_INSERT_TAIL(&target->ed_entries, device, links);
 		}
 		target->generation++;
-#ifdef CAM_NEW_TRAN_CODE
 		if (lun_id != CAM_LUN_WILDCARD) {
 			xpt_compile_path(&path,
 					 NULL,
@@ -5198,7 +5092,6 @@
 			xpt_devise_transport(&path);
 			xpt_release_path(&path);
 		}
-#endif /* CAM_NEW_TRAN_CODE */
 	}
 	return (device);
 }
@@ -5207,9 +5100,7 @@
 xpt_release_device(struct cam_eb *bus, struct cam_et *target,
 		   struct cam_ed *device)
 {
-	int s;
 
-	s = splcam();
 	if ((--device->refcount == 0)
 	 && ((device->flags & CAM_DEV_UNCONFIGURED) != 0)) {
 		struct cam_devq *devq;
@@ -5219,36 +5110,31 @@
 			panic("Removing device while still queued for ccbs");
 
 		if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0)
-				untimeout(xpt_release_devq_timeout, device,
-					  device->c_handle);
+				callout_stop(&device->callout);
 
 		TAILQ_REMOVE(&target->ed_entries, device,links);
 		target->generation++;
-		xpt_max_ccbs -= device->ccbq.devq_openings;
+		bus->sim->max_ccbs -= device->ccbq.devq_openings;
 		if (!SIM_DEAD(bus->sim)) {
 			/* Release our slot in the devq */
 			devq = bus->sim->devq;
 			cam_devq_resize(devq, devq->alloc_queue.array_size - 1);
 		}
-		splx(s);
 		camq_fini(&device->drvq);
 		camq_fini(&device->ccbq.queue);
 		free(device, M_CAMXPT);
 		xpt_release_target(bus, target);
-	} else
-		splx(s);
+	}
 }
 
 static u_int32_t
 xpt_dev_ccbq_resize(struct cam_path *path, int newopenings)
 {
-	int	s;
 	int	diff;
 	int	result;
 	struct	cam_ed *dev;
 
 	dev = path->device;
-	s = splsoftcam();
 
 	diff = newopenings - (dev->ccbq.dev_active + dev->ccbq.dev_openings);
 	result = cam_ccbq_resize(&dev->ccbq, newopenings);
@@ -5259,8 +5145,7 @@
 	 || (dev->inq_flags & SID_CmdQue) != 0)
 		dev->tag_saved_openings = newopenings;
 	/* Adjust the global limit */
-	xpt_max_ccbs += diff;
-	splx(s);
+	dev->sim->max_ccbs += diff;
 	return (result);
 }
 
@@ -5269,7 +5154,8 @@
 {
 	struct cam_eb *bus;
 
-	for (bus = TAILQ_FIRST(&xpt_busses);
+	mtx_lock(&xsoftc.xpt_topo_lock);
+	for (bus = TAILQ_FIRST(&xsoftc.xpt_busses);
 	     bus != NULL;
 	     bus = TAILQ_NEXT(bus, links)) {
 		if (bus->path_id == path_id) {
@@ -5277,6 +5163,7 @@
 			break;
 		}
 	}
+	mtx_unlock(&xsoftc.xpt_topo_lock);
 	return (bus);
 }
 
@@ -5318,6 +5205,11 @@
 	int	counter;
 } xpt_scan_bus_info;
 
+/*
+ * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
+ * As the scan progresses, xpt_scan_bus is used as the
+ * callback on completion function.
+ */
 static void
 xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
 {
@@ -5329,14 +5221,19 @@
 		xpt_scan_bus_info *scan_info;
 		union	ccb *work_ccb;
 		struct	cam_path *path;
-		u_int i;
-		u_int max_target;
-		u_int initiator_id;
+		u_int	i;
+		u_int	max_target;
+		u_int	initiator_id;
 
 		/* Find out the characteristics of the bus */
-		work_ccb = xpt_alloc_ccb();
+		work_ccb = xpt_alloc_ccb_nowait();
+		if (work_ccb == NULL) {
+			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+			xpt_done(request_ccb);
+			return;
+		}
 		xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
-		    request_ccb->ccb_h.pinfo.priority);
+			      request_ccb->ccb_h.pinfo.priority);
 		work_ccb->ccb_h.func_code = XPT_PATH_INQ;
 		xpt_action(work_ccb);
 		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
@@ -5359,7 +5256,7 @@
 
 		/* Save some state for use while we probe for devices */
 		scan_info = (xpt_scan_bus_info *)
-		    malloc(sizeof(xpt_scan_bus_info), M_TEMP, M_WAITOK);
+		    malloc(sizeof(xpt_scan_bus_info), M_CAMXPT, M_NOWAIT);
 		scan_info->request_ccb = request_ccb;
 		scan_info->cpi = &work_ccb->cpi;
 
@@ -5387,21 +5284,28 @@
 				continue;
 
 			status = xpt_create_path(&path, xpt_periph,
-			                         request_ccb->ccb_h.path_id,
-                                                 i, 0);
+						 request_ccb->ccb_h.path_id,
+						 i, 0);
 			if (status != CAM_REQ_CMP) {
 				printf("xpt_scan_bus: xpt_create_path failed"
 				       " with status %#x, bus scan halted\n",
 				       status);
-				free(scan_info, M_TEMP);
+				free(scan_info, M_CAMXPT);
 				request_ccb->ccb_h.status = status;
 				xpt_free_ccb(work_ccb);
 				xpt_done(request_ccb);
 				break;
 			}
-			work_ccb = xpt_alloc_ccb();
+			work_ccb = xpt_alloc_ccb_nowait();
+			if (work_ccb == NULL) {
+				free(scan_info, M_CAMXPT);
+				xpt_free_path(path);
+				request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+				xpt_done(request_ccb);
+				break;
+			}
 			xpt_setup_ccb(&work_ccb->ccb_h, path,
-			    request_ccb->ccb_h.pinfo.priority);
+				      request_ccb->ccb_h.pinfo.priority);
 			work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
 			work_ccb->ccb_h.cbfcnp = xpt_scan_bus;
 			work_ccb->ccb_h.ppriv_ptr0 = scan_info;
@@ -5422,7 +5326,7 @@
 		/* Reuse the same CCB to query if a device was really found */
 		scan_info = (xpt_scan_bus_info *)request_ccb->ccb_h.ppriv_ptr0;
 		xpt_setup_ccb(&request_ccb->ccb_h, request_ccb->ccb_h.path,
-		    request_ccb->ccb_h.pinfo.priority);
+			      request_ccb->ccb_h.pinfo.priority);
 		request_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
 
 		path_id = request_ccb->ccb_h.path_id;
@@ -5433,7 +5337,7 @@
 		if (request_ccb->ccb_h.status != CAM_REQ_CMP) {
 			struct cam_ed *device;
 			struct cam_et *target;
-			int s, phl;
+			int phl;
 
 			/*
 			 * If we already probed lun 0 successfully, or
@@ -5450,14 +5354,12 @@
 			 * path in the request ccb.
 			 */
 			phl = 0;
-			s = splcam();
 			device = TAILQ_FIRST(&target->ed_entries);
 			if (device != NULL) {
 				phl = CAN_SRCH_HI_SPARSE(device);
 				if (device->lun_id == 0)
 					device = TAILQ_NEXT(device, links);
 			}
-			splx(s);
 			if ((lun_id != 0) || (device != NULL)) {
 				if (lun_id < (CAM_SCSI2_MAXLUN-1) || phl)
 					lun_id++;
@@ -5509,7 +5411,7 @@
 				xpt_free_ccb(request_ccb);
 				xpt_free_ccb((union ccb *)scan_info->cpi);
 				request_ccb = scan_info->request_ccb;
-				free(scan_info, M_TEMP);
+				free(scan_info, M_CAMXPT);
 				request_ccb->ccb_h.status = CAM_REQ_CMP;
 				xpt_done(request_ccb);
 				break;
@@ -5528,7 +5430,7 @@
 				xpt_free_ccb(request_ccb);
 				xpt_free_ccb((union ccb *)scan_info->cpi);
 				request_ccb = scan_info->request_ccb;
-				free(scan_info, M_TEMP);
+				free(scan_info, M_CAMXPT);
 				request_ccb->ccb_h.status = status;
 				xpt_done(request_ccb);
 				break;
@@ -5542,7 +5444,7 @@
 			    scan_info->request_ccb->crcn.flags;
 		} else {
 			status = xpt_create_path(&path, xpt_periph,
-			    path_id, target_id, lun_id);
+						 path_id, target_id, lun_id);
 			if (status != CAM_REQ_CMP) {
 				printf("xpt_scan_bus: xpt_create_path failed "
 				       "with status %#x, halting LUN scan\n",
@@ -5550,7 +5452,7 @@
 				goto hop_again;
 			}
 			xpt_setup_ccb(&request_ccb->ccb_h, path,
-			      request_ccb->ccb_h.pinfo.priority);
+				      request_ccb->ccb_h.pinfo.priority);
 			request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
 			request_ccb->ccb_h.cbfcnp = xpt_scan_bus;
 			request_ccb->ccb_h.ppriv_ptr0 = scan_info;
@@ -5567,11 +5469,14 @@
 
 typedef enum {
 	PROBE_TUR,
-	PROBE_INQUIRY,
+	PROBE_INQUIRY,	/* this counts as DV0 for Basic Domain Validation */
 	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 {
@@ -5597,8 +5502,7 @@
 	cam_status status;
 	struct cam_path *new_path;
 	struct cam_periph *old_periph;
-	int s;
-	
+
 	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
 		  ("xpt_scan_lun\n"));
 	
@@ -5627,19 +5531,17 @@
 	}
 
 	if (request_ccb == NULL) {
-		request_ccb = malloc(sizeof(union ccb), M_TEMP, M_NOWAIT);
+		request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT);
 		if (request_ccb == NULL) {
-			xpt_print_path(path);
-			printf("xpt_scan_lun: can't allocate CCB, can't "
-			       "continue\n");
+			xpt_print(path, "xpt_scan_lun: can't allocate CCB, "
+			    "can't continue\n");
 			return;
 		}
-		new_path = malloc(sizeof(*new_path), M_TEMP, M_NOWAIT);
+		new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT);
 		if (new_path == NULL) {
-			xpt_print_path(path);
-			printf("xpt_scan_lun: can't allocate path, can't "
-			       "continue\n");
-			free(request_ccb, M_TEMP);
+			xpt_print(path, "xpt_scan_lun: can't allocate path, "
+			    "can't continue\n");
+			free(request_ccb, M_CAMXPT);
 			return;
 		}
 		status = xpt_compile_path(new_path, xpt_periph,
@@ -5648,11 +5550,10 @@
 					  path->device->lun_id);
 
 		if (status != CAM_REQ_CMP) {
-			xpt_print_path(path);
-			printf("xpt_scan_lun: can't compile path, can't "
-			       "continue\n");
-			free(request_ccb, M_TEMP);
-			free(new_path, M_TEMP);
+			xpt_print(path, "xpt_scan_lun: can't compile path, "
+			    "can't continue\n");
+			free(request_ccb, M_CAMXPT);
+			free(new_path, M_CAMXPT);
 			return;
 		}
 		xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1);
@@ -5661,7 +5562,6 @@
 		request_ccb->crcn.flags = flags;
 	}
 
-	s = splsoftcam();
 	if ((old_periph = cam_periph_find(path, "probe")) != NULL) {
 		probe_softc *softc;
 
@@ -5676,28 +5576,27 @@
 					  request_ccb);
 
 		if (status != CAM_REQ_CMP) {
-			xpt_print_path(path);
-			printf("xpt_scan_lun: cam_alloc_periph returned an "
-			       "error, can't continue probe\n");
+			xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
+			    "returned an error, can't continue probe\n");
 			request_ccb->ccb_h.status = status;
 			xpt_done(request_ccb);
 		}
 	}
-	splx(s);
 }
 
 static void
 xptscandone(struct cam_periph *periph, union ccb *done_ccb)
 {
 	xpt_release_path(done_ccb->ccb_h.path);
-	free(done_ccb->ccb_h.path, M_TEMP);
-	free(done_ccb, M_TEMP);
+	free(done_ccb->ccb_h.path, M_CAMXPT);
+	free(done_ccb, M_CAMXPT);
 }
 
 static cam_status
 proberegister(struct cam_periph *periph, void *arg)
 {
 	union ccb *request_ccb;	/* CCB representing the probe request */
+	cam_status status;
 	probe_softc *softc;
 
 	request_ccb = (union ccb *)arg;
@@ -5712,7 +5611,7 @@
 		return(CAM_REQ_CMP_ERR);
 	}
 
-	softc = (probe_softc *)malloc(sizeof(*softc), M_TEMP, M_NOWAIT);
+	softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT);
 
 	if (softc == NULL) {
 		printf("proberegister: Unable to probe new device. "
@@ -5724,7 +5623,12 @@
 			  periph_links.tqe);
 	softc->flags = 0;
 	periph->softc = softc;
-	cam_periph_acquire(periph);
+	status = cam_periph_acquire(periph);
+	if (status != CAM_REQ_CMP) {
+		return (status);
+	}
+
+
 	/*
 	 * Ensure we've waited at least a bus settle
 	 * delay before attempting to probe the device.
@@ -5802,6 +5706,7 @@
 	switch (softc->action) {
 	case PROBE_TUR:
 	case PROBE_TUR_FOR_NEGOTIATION:
+	case PROBE_DV_EXIT:
 	{
 		scsi_test_unit_ready(csio,
 				     /*retries*/4,
@@ -5813,11 +5718,14 @@
 	}
 	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;
 
 		inq_buf = &periph->path->device->inq_data;
+
 		/*
 		 * If the device is currently configured, we calculate an
 		 * MD5 checksum of the inquiry data, and if the serial number
@@ -5844,9 +5752,7 @@
 		if (softc->action == PROBE_INQUIRY)
 			inquiry_len = SHORT_INQUIRY_LENGTH;
 		else
-			inquiry_len = inq_buf->additional_length
-				    + offsetof(struct scsi_inquiry_data,
-                                               additional_length) + 1;
+			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
 
 		/*
 		 * Some parallel SCSI devices fail to send an
@@ -5856,6 +5762,22 @@
 		 */
 		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_CAMXPT, M_NOWAIT);
+		}
+		if (inq_buf == NULL) {
+			xpt_print(periph->path, "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,
@@ -5876,7 +5798,7 @@
 		mode_buf_len = sizeof(struct scsi_mode_header_6)
 			     + sizeof(struct scsi_mode_blk_desc)
 			     + sizeof(struct scsi_control_page);
-		mode_buf = malloc(mode_buf_len, M_TEMP, M_NOWAIT);
+		mode_buf = malloc(mode_buf_len, M_CAMXPT, M_NOWAIT);
 		if (mode_buf != NULL) {
 	                scsi_mode_sense(csio,
 					/*retries*/4,
@@ -5891,8 +5813,8 @@
 					/*timeout*/60000);
 			break;
 		}
-		xpt_print_path(periph->path);
-		printf("Unable to mode sense control page - malloc failure\n");
+		xpt_print(periph->path, "Unable to mode sense control page - "
+		    "malloc failure\n");
 		softc->action = PROBE_SERIAL_NUM;
 	}
 	/* FALLTHROUGH */
@@ -5908,7 +5830,7 @@
 
 		if ((device->quirk->quirks & CAM_QUIRK_NOSERIAL) == 0)
 			serial_buf = (struct scsi_vpd_unit_serial_number *)
-				malloc(sizeof(*serial_buf), M_TEMP,
+				malloc(sizeof(*serial_buf), M_CAMXPT,
 					M_NOWAIT | M_ZERO);
 
 		if (serial_buf != NULL) {
@@ -5943,22 +5865,121 @@
 
 	xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1);
 	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
-#ifdef CAM_NEW_TRAN_CODE
 	cts.type = CTS_TYPE_USER_SETTINGS;
-#else /* CAM_NEW_TRAN_CODE */
-	cts.flags = CCB_TRANS_USER_SETTINGS;
-#endif /* CAM_NEW_TRAN_CODE */
 	xpt_action((union ccb *)&cts);
+	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+		return;
+	}
 	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
-#ifdef CAM_NEW_TRAN_CODE
 	cts.type = CTS_TYPE_CURRENT_SETTINGS;
-#else /* CAM_NEW_TRAN_CODE */
-	cts.flags &= ~CCB_TRANS_USER_SETTINGS;
-	cts.flags |= CCB_TRANS_CURRENT_SETTINGS;
-#endif /* CAM_NEW_TRAN_CODE */
 	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(periph->path,
+			    "failed to get current device settings\n");
+		}
+		return (0);
+	}
+	if (cts.transport != XPORT_SPI) {
+		if (bootverbose) {
+			xpt_print(periph->path, "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(periph->path, "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(periph->path, "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)
 {
@@ -6031,9 +6052,7 @@
 
 				xpt_find_quirk(path->device);
 
-#ifdef CAM_NEW_TRAN_CODE
 				xpt_devise_transport(path);
-#endif /* CAM_NEW_TRAN_CODE */
 				if (INQ_DATA_TQ_ENABLED(inq_buf))
 					softc->action = PROBE_MODE_SENSE;
 				else
@@ -6101,7 +6120,7 @@
 					 /*count*/1, /*run_queue*/TRUE);
 		}
 		xpt_release_ccb(done_ccb);
-		free(mode_hdr, M_TEMP);
+		free(mode_hdr, M_CAMXPT);
 		softc->action = PROBE_SERIAL_NUM;
 		xpt_schedule(periph, priority);
 		return;
@@ -6188,7 +6207,7 @@
 				xpt_async(AC_LOST_DEVICE, path, NULL);
 		}
 		if (serial_buf != NULL)
-			free(serial_buf, M_TEMP);
+			free(serial_buf, M_CAMXPT);
 
 		if (changed != 0) {
 			/*
@@ -6197,7 +6216,7 @@
 			 * negotiations... Controllers don't perform
 			 * any negotiation or tagged queuing until
 			 * after the first XPT_SET_TRAN_SETTINGS ccb is
-			 * received.  So, on a new device, just retreive
+			 * received.  So, on a new device, just retrieve
 			 * the user settings, and set them as the current
 			 * settings to set the device up.
 			 */
@@ -6216,25 +6235,96 @@
 		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;
-
+		/*
+		 * 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,
+			    "inquiry data 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_CAMXPT);
+			xpt_release_ccb(done_ccb);
+			xpt_schedule(periph, priority);
+			return;
+		}
+		free(nbuf, M_CAMXPT);
+		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;
+			xpt_action(done_ccb);
 			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
 				  done_ccb);
 		}
 		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;
@@ -6250,7 +6340,7 @@
 static void
 probecleanup(struct cam_periph *periph)
 {
-	free(periph->softc, M_TEMP);
+	free(periph->softc, M_CAMXPT);
 }
 
 static void
@@ -6275,7 +6365,7 @@
 	int error, bool;
 
 	bool = cam_srch_hi;
-	error = sysctl_handle_int(oidp, &bool, sizeof(bool), req);
+	error = sysctl_handle_int(oidp, &bool, 0, req);
 	if (error != 0 || req->newptr == NULL)
 		return (error);
 	if (bool == 0 || bool == 1) {
@@ -6286,7 +6376,6 @@
 	}
 }
 
-#ifdef CAM_NEW_TRAN_CODE
 
 static void
 xpt_devise_transport(struct cam_path *path)
@@ -6396,17 +6485,16 @@
 		cts->protocol_version = device->protocol_version;
 
 	if (cts->protocol != device->protocol) {
-		xpt_print_path(cts->ccb_h.path);
-		printf("Uninitialized Protocol %x:%x?\n",
+		xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n",
 		       cts->protocol, device->protocol);
 		cts->protocol = device->protocol;
 	}
 
 	if (cts->protocol_version > device->protocol_version) {
 		if (bootverbose) {
-			xpt_print_path(cts->ccb_h.path);
-			printf("Down reving Protocol Version from %d to %d?\n",
-			       cts->protocol_version, device->protocol_version);
+			xpt_print(cts->ccb_h.path, "Down reving Protocol "
+			    "Version from %d to %d?\n", cts->protocol_version,
+			    device->protocol_version);
 		}
 		cts->protocol_version = device->protocol_version;
 	}
@@ -6422,18 +6510,16 @@
 		cts->transport_version = device->transport_version;
 
 	if (cts->transport != device->transport) {
-		xpt_print_path(cts->ccb_h.path);
-		printf("Uninitialized Transport %x:%x?\n",
-		       cts->transport, device->transport);
+		xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n",
+		    cts->transport, device->transport);
 		cts->transport = device->transport;
 	}
 
 	if (cts->transport_version > device->transport_version) {
 		if (bootverbose) {
-			xpt_print_path(cts->ccb_h.path);
-			printf("Down reving Transport Version from %d to %d?\n",
-			       cts->transport_version,
-			       device->transport_version);
+			xpt_print(cts->ccb_h.path, "Down reving Transport "
+			    "Version from %d to %d?\n", cts->transport_version,
+			    device->transport_version);
 		}
 		cts->transport_version = device->transport_version;
 	}
@@ -6478,7 +6564,9 @@
 		cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 		cur_cts.type = cts->type;
 		xpt_action((union ccb *)&cur_cts);
-
+		if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+			return;
+		}
 		cur_scsi = &cur_cts.proto_specific.scsi;
 		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
 			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
@@ -6525,8 +6613,8 @@
 		  && (inq_data->flags & SID_Sync) == 0
 		  && cts->type == CTS_TYPE_CURRENT_SETTINGS)
 		 || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0)
-		 || (cur_spi->sync_offset == 0)
-		 || (cur_spi->sync_period == 0)) {
+		 || (spi->sync_offset == 0)
+		 || (spi->sync_period == 0)) {
 			/* Force async */
 			spi->sync_period = 0;
 			spi->sync_offset = 0;
@@ -6656,194 +6744,6 @@
 		(*(sim->sim_action))(sim, (union ccb *)cts);
 }
 
-#else /* CAM_NEW_TRAN_CODE */
-
-static void
-xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
-			  int async_update)
-{
-	struct	cam_sim *sim;
-	int	qfrozen;
-
-	sim = cts->ccb_h.path->bus->sim;
-	if (async_update == FALSE) {
-		struct	scsi_inquiry_data *inq_data;
-		struct	ccb_pathinq cpi;
-		struct	ccb_trans_settings cur_cts;
-
-		if (device == NULL) {
-			cts->ccb_h.status = CAM_PATH_INVALID;
-			xpt_done((union ccb *)cts);
-			return;
-		}
-
-		/*
-		 * Perform sanity checking against what the
-		 * controller and device can do.
-		 */
-		xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1);
-		cpi.ccb_h.func_code = XPT_PATH_INQ;
-		xpt_action((union ccb *)&cpi);
-		xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1);
-		cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
-		cur_cts.flags = CCB_TRANS_CURRENT_SETTINGS;
-		xpt_action((union ccb *)&cur_cts);
-		inq_data = &device->inq_data;
-
-		/* Fill in any gaps in what the user gave us */
-		if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0)
-			cts->sync_period = cur_cts.sync_period;
-		if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0)
-			cts->sync_offset = cur_cts.sync_offset;
-		if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) == 0)
-			cts->bus_width = cur_cts.bus_width;
-		if ((cts->valid & CCB_TRANS_DISC_VALID) == 0) {
-			cts->flags &= ~CCB_TRANS_DISC_ENB;
-			cts->flags |= cur_cts.flags & CCB_TRANS_DISC_ENB;
-		}
-		if ((cts->valid & CCB_TRANS_TQ_VALID) == 0) {
-			cts->flags &= ~CCB_TRANS_TAG_ENB;
-			cts->flags |= cur_cts.flags & CCB_TRANS_TAG_ENB;
-		}
-
-		if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
-		  && (inq_data->flags & SID_Sync) == 0)
-		 || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0)
-		 || (cts->sync_offset == 0)
-		 || (cts->sync_period == 0)) {
-			/* Force async */
-			cts->sync_period = 0;
-			cts->sync_offset = 0;
-		} else if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
-			&& (inq_data->spi3data & SID_SPI_CLOCK_DT) == 0
-			&& cts->sync_period <= 0x9) {
-			/*
-			 * Don't allow DT transmission rates if the
-			 * device does not support it.
-			 */
-			cts->sync_period = 0xa;
-		}
-
-		switch (cts->bus_width) {
-		case MSG_EXT_WDTR_BUS_32_BIT:
-			if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
-			  || (inq_data->flags & SID_WBus32) != 0)
-			 && (cpi.hba_inquiry & PI_WIDE_32) != 0)
-				break;
-			/* FALLTHROUGH to 16-bit */
-		case MSG_EXT_WDTR_BUS_16_BIT:
-			if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
-			  || (inq_data->flags & SID_WBus16) != 0)
-			 && (cpi.hba_inquiry & PI_WIDE_16) != 0) {
-				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
-				break;
-			}
-			/* FALLTHROUGH to 8-bit */
-		default: /* New bus width?? */
-		case MSG_EXT_WDTR_BUS_8_BIT:
-			/* All targets can do this */
-			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-			break;
-		}
-
-		if ((cts->flags & CCB_TRANS_DISC_ENB) == 0) {
-			/*
-			 * Can't tag queue without disconnection.
-			 */
-			cts->flags &= ~CCB_TRANS_TAG_ENB;
-			cts->valid |= CCB_TRANS_TQ_VALID;
-		}
-
-		if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
-	 	 || (INQ_DATA_TQ_ENABLED(inq_data)) == 0
-		 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
-		 || (device->quirk->mintags == 0)) {
-			/*
-			 * Can't tag on hardware that doesn't support,
-			 * doesn't have it enabled, or has broken tag support.
-			 */
-			cts->flags &= ~CCB_TRANS_TAG_ENB;
-		}
-	}
-
-	qfrozen = FALSE;
-	if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
-		int device_tagenb;
-
-		/*
-		 * If we are transitioning from tags to no-tags or
-		 * vice-versa, we need to carefully freeze and restart
-		 * the queue so that we don't overlap tagged and non-tagged
-		 * commands.  We also temporarily stop tags if there is
-		 * a change in transfer negotiation settings to allow
-		 * "tag-less" negotiation.
-		 */
-		if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
-		 || (device->inq_flags & SID_CmdQue) != 0)
-			device_tagenb = TRUE;
-		else
-			device_tagenb = FALSE;
-
-		if (((cts->flags & CCB_TRANS_TAG_ENB) != 0
-		  && device_tagenb == FALSE)
-		 || ((cts->flags & CCB_TRANS_TAG_ENB) == 0
-		  && device_tagenb == TRUE)) {
-
-			if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
-				/*
-				 * Delay change to use tags until after a
-				 * few commands have gone to this device so
-				 * the controller has time to perform transfer
-				 * negotiations without tagged messages getting
-				 * in the way.
-				 */
-				device->tag_delay_count = CAM_TAG_DELAY_COUNT;
-				device->flags |= CAM_DEV_TAG_AFTER_COUNT;
-			} else {
-				xpt_freeze_devq(cts->ccb_h.path, /*count*/1);
-				qfrozen = TRUE;
-		  		device->inq_flags &= ~SID_CmdQue;
-				xpt_dev_ccbq_resize(cts->ccb_h.path,
-						    sim->max_dev_openings);
-				device->flags &= ~CAM_DEV_TAG_AFTER_COUNT;
-				device->tag_delay_count = 0;
-			}
-		}
-	}
-
-	if (async_update == FALSE) {
-		/*
-		 * If we are currently performing tagged transactions to
-		 * this device and want to change its negotiation parameters,
-		 * go non-tagged for a bit to give the controller a chance to
-		 * negotiate unhampered by tag messages.
-		 */
-		if ((device->inq_flags & SID_CmdQue) != 0
-		 && (cts->flags & (CCB_TRANS_SYNC_RATE_VALID|
-				   CCB_TRANS_SYNC_OFFSET_VALID|
-				   CCB_TRANS_BUS_WIDTH_VALID)) != 0)
-			xpt_toggle_tags(cts->ccb_h.path);
-
-		(*(sim->sim_action))(sim, (union ccb *)cts);
-	}
-
-	if (qfrozen) {
-		struct ccb_relsim crs;
-
-		xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path,
-			      /*priority*/1);
-		crs.ccb_h.func_code = XPT_REL_SIMQ;
-		crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY;
-		crs.openings
-		    = crs.release_timeout 
-		    = crs.qfrozen_cnt
-		    = 0;
-		xpt_action((union ccb *)&crs);
-	}
-}
-
-
-#endif /* CAM_NEW_TRAN_CODE */
 
 static void
 xpt_toggle_tags(struct cam_path *path)
@@ -6864,24 +6764,15 @@
 		struct ccb_trans_settings cts;
 
 		xpt_setup_ccb(&cts.ccb_h, path, 1);
-#ifdef CAM_NEW_TRAN_CODE
 		cts.protocol = PROTO_SCSI;
 		cts.protocol_version = PROTO_VERSION_UNSPECIFIED;
 		cts.transport = XPORT_UNSPECIFIED;
 		cts.transport_version = XPORT_VERSION_UNSPECIFIED;
 		cts.proto_specific.scsi.flags = 0;
 		cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
-#else /* CAM_NEW_TRAN_CODE */
-		cts.flags = 0;
-		cts.valid = CCB_TRANS_TQ_VALID;
-#endif /* CAM_NEW_TRAN_CODE */
 		xpt_set_transfer_settings(&cts, path->device,
 					  /*async_update*/TRUE);
-#ifdef CAM_NEW_TRAN_CODE
 		cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
-#else /* CAM_NEW_TRAN_CODE */
-		cts.flags = CCB_TRANS_TAG_ENB;
-#endif /* CAM_NEW_TRAN_CODE */
 		xpt_set_transfer_settings(&cts, path->device,
 					  /*async_update*/TRUE);
 	}
@@ -6922,6 +6813,9 @@
 static int
 xptconfigbuscountfunc(struct cam_eb *bus, void *arg)
 {
+
+	mtx_assert(bus->sim->mtx, MA_OWNED);
+
 	if (bus->path_id != CAM_XPT_PATH_ID) {
 		struct cam_path path;
 		struct ccb_pathinq cpi;
@@ -6950,11 +6844,18 @@
 	struct	cam_path *path;
 	union	ccb *work_ccb;
 
+	mtx_assert(bus->sim->mtx, MA_OWNED);
+
 	if (bus->path_id != CAM_XPT_PATH_ID) {
 		cam_status status;
 		int can_negotiate;
 
-		work_ccb = xpt_alloc_ccb();
+		work_ccb = xpt_alloc_ccb_nowait();
+		if (work_ccb == NULL) {
+			busses_to_config--;
+			xpt_finishconfig(xpt_periph, NULL);
+			return(0);
+		}
 		if ((status = xpt_create_path(&path, xpt_periph, bus->path_id,
 					      CAM_TARGET_WILDCARD,
 					      CAM_LUN_WILDCARD)) !=CAM_REQ_CMP){
@@ -7014,6 +6915,11 @@
 #endif /* CAM_DEBUG_FLAGS */
 #ifdef CAM_DEBUG_BUS
 	if (cam_dflags != CAM_DEBUG_NONE) {
+		/*
+		 * Locking is specifically omitted here.  No SIMs have
+		 * registered yet, so xpt_create_path will only be searching
+		 * empty lists of targets and devices.
+		 */
 		if (xpt_create_path(&cam_dpath, xpt_periph,
 				    CAM_DEBUG_BUS, CAM_DEBUG_TARGET,
 				    CAM_DEBUG_LUN) != CAM_REQ_CMP) {
@@ -7069,11 +6975,40 @@
 }
 
 static void
-xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb)
+xpt_finishconfig_task(void *context, int pending)
 {
 	struct	periph_driver **p_drv;
 	int	i;
 
+	if (busses_to_config == 0) {
+		/* Register all the peripheral drivers */
+		/* XXX This will have to change when we have loadable modules */
+		p_drv = periph_drivers;
+		for (i = 0; p_drv[i] != NULL; i++) {
+			(*p_drv[i]->init)();
+		}
+
+		/*
+		 * Check for devices with no "standard" peripheral driver
+		 * attached.  For any devices like that, announce the
+		 * passthrough driver so the user will see something.
+		 */
+		xpt_for_all_devices(xptpassannouncefunc, NULL);
+
+		/* Release our hook so that the boot can continue. */
+		config_intrhook_disestablish(xsoftc.xpt_config_hook);
+		free(xsoftc.xpt_config_hook, M_CAMXPT);
+		xsoftc.xpt_config_hook = NULL;
+	}
+
+	free(context, M_CAMXPT);
+}
+
+static void
+xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb)
+{
+	struct	xpt_task *task;
+
 	if (done_ccb != NULL) {
 		CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE,
 			  ("xpt_finishconfig\n"));
@@ -7096,29 +7031,50 @@
 	}
 
 	if (busses_to_config == 0) {
-		/* Register all the peripheral drivers */
-		/* XXX This will have to change when we have loadable modules */
-		p_drv = periph_drivers;
-		for (i = 0; p_drv[i] != NULL; i++) {
-			(*p_drv[i]->init)();
+		task = malloc(sizeof(struct xpt_task), M_CAMXPT, M_NOWAIT);
+		if (task != NULL) {
+			TASK_INIT(&task->task, 0, xpt_finishconfig_task, task);
+			taskqueue_enqueue(taskqueue_thread, &task->task);
 		}
-
-		/*
-		 * Check for devices with no "standard" peripheral driver
-		 * attached.  For any devices like that, announce the
-		 * passthrough driver so the user will see something.
-		 */
-		xpt_for_all_devices(xptpassannouncefunc, NULL);
-
-		/* Release our hook so that the boot can continue. */
-		config_intrhook_disestablish(xpt_config_hook);
-		free(xpt_config_hook, M_TEMP);
-		xpt_config_hook = NULL;
 	}
+
 	if (done_ccb != NULL)
 		xpt_free_ccb(done_ccb);
 }
 
+cam_status
+xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg,
+		   struct cam_path *path)
+{
+	struct ccb_setasync csa;
+	cam_status status;
+	int xptpath = 0;
+
+	if (path == NULL) {
+		mtx_lock(&xsoftc.xpt_lock);
+		status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
+					 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
+		if (status != CAM_REQ_CMP) {
+			mtx_unlock(&xsoftc.xpt_lock);
+			return (status);
+		}
+		xptpath = 1;
+	}
+
+	xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
+	csa.ccb_h.func_code = XPT_SASYNC_CB;
+	csa.event_enable = event;
+	csa.callback = cbfunc;
+	csa.callback_arg = cbarg;
+	xpt_action((union ccb *)&csa);
+	status = csa.ccb_h.status;
+	if (xptpath) {
+		xpt_free_path(path);
+		mtx_unlock(&xsoftc.xpt_lock);
+	}
+	return (status);
+}
+
 static void
 xptaction(struct cam_sim *sim, union ccb *work_ccb)
 {
@@ -7145,12 +7101,10 @@
 		cpi->unit_number = sim->unit_number;
 		cpi->bus_id = sim->bus_id;
 		cpi->base_transfer_speed = 0;
-#ifdef CAM_NEW_TRAN_CODE
 		cpi->protocol = PROTO_UNSPECIFIED;
 		cpi->protocol_version = PROTO_VERSION_UNSPECIFIED;
 		cpi->transport = XPORT_UNSPECIFIED;
 		cpi->transport_version = XPORT_VERSION_UNSPECIFIED;
-#endif /* CAM_NEW_TRAN_CODE */
 		cpi->ccb_h.status = CAM_REQ_CMP;
 		xpt_done(work_ccb);
 		break;
@@ -7171,31 +7125,49 @@
 {
 }
 
+void
+xpt_lock_buses(void)
+{
+	mtx_lock(&xsoftc.xpt_topo_lock);
+}
+
+void
+xpt_unlock_buses(void)
+{
+	mtx_unlock(&xsoftc.xpt_topo_lock);
+}
+
 static void
-camisr(void *V_queue)
+camisr(void *dummy)
 {
-	cam_isrq_t *oqueue = V_queue;
-	cam_isrq_t queue;
-	int	s;
-	struct	ccb_hdr *ccb_h;
+	cam_simq_t queue;
+	struct cam_sim *sim;
 
-	/*
-	 * Transfer the ccb_bioq list to a temporary list so we can operate
-	 * on it without needing to lock/unlock on every loop.  The concat
-	 * function with re-init the real list for us.
-	 */
-	s = splcam();
-	mtx_lock(&cam_bioq_lock);
+	mtx_lock(&cam_simq_lock);
 	TAILQ_INIT(&queue);
-	TAILQ_CONCAT(&queue, oqueue, sim_links.tqe);
-	mtx_unlock(&cam_bioq_lock);
+	TAILQ_CONCAT(&queue, &cam_simq, links);
+	mtx_unlock(&cam_simq_lock);
 
-	while ((ccb_h = TAILQ_FIRST(&queue)) != NULL) {
+	while ((sim = TAILQ_FIRST(&queue)) != NULL) {
+		TAILQ_REMOVE(&queue, sim, links);
+		CAM_SIM_LOCK(sim);
+		sim->flags &= ~CAM_SIM_ON_DONEQ;
+		camisr_runqueue(&sim->sim_doneq);
+		CAM_SIM_UNLOCK(sim);
+	}
+}
+
+static void
+camisr_runqueue(void *V_queue)
+{
+	cam_isrq_t *queue = V_queue;
+	struct	ccb_hdr *ccb_h;
+
+	while ((ccb_h = TAILQ_FIRST(queue)) != NULL) {
 		int	runq;
 
-		TAILQ_REMOVE(&queue, ccb_h, sim_links.tqe);
+		TAILQ_REMOVE(queue, ccb_h, sim_links.tqe);
 		ccb_h->pinfo.index = CAM_UNQUEUED_INDEX;
-		splx(s);
 
 		CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE,
 			  ("camisr\n"));
@@ -7206,14 +7178,15 @@
 			struct highpowerlist	*hphead;
 			union ccb		*send_ccb;
 
-			hphead = &highpowerq;
+			mtx_lock(&xsoftc.xpt_lock);
+			hphead = &xsoftc.highpowerq;
 
 			send_ccb = (union ccb *)STAILQ_FIRST(hphead);
 
 			/*
 			 * Increment the count since this command is done.
 			 */
-			num_highpower++;
+			xsoftc.num_highpower++;
 
 			/* 
 			 * Any high powered commands queued up?
@@ -7221,24 +7194,25 @@
 			if (send_ccb != NULL) {
 
 				STAILQ_REMOVE_HEAD(hphead, xpt_links.stqe);
+				mtx_unlock(&xsoftc.xpt_lock);
 
 				xpt_release_devq(send_ccb->ccb_h.path,
 						 /*count*/1, /*runqueue*/TRUE);
-			}
+			} else
+				mtx_unlock(&xsoftc.xpt_lock);
 		}
+
 		if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) {
 			struct cam_ed *dev;
 
 			dev = ccb_h->path->device;
 
-			s = splcam();
 			cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h);
 
 			if (!SIM_DEAD(ccb_h->path->bus->sim)) {
 				ccb_h->path->bus->sim->devq->send_active--;
 				ccb_h->path->bus->sim->devq->send_openings++;
 			}
-			splx(s);
 			
 			if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0
 			  && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ)
@@ -7279,11 +7253,7 @@
 
 		/* Call the peripheral driver's callback */
 		(*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h);
-
-		/* Raise IPL for while test */
-		s = splcam();
 	}
-	splx(s);
 }
 
 static void
Index: cam_sim.h
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_sim.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/cam_sim.h -L sys/cam/cam_sim.h -u -r1.1.1.1 -r1.2
--- sys/cam/cam_sim.h
+++ sys/cam/cam_sim.h
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/cam/cam_sim.h,v 1.6 2005/01/05 22:34:34 imp Exp $
+ * $FreeBSD: src/sys/cam/cam_sim.h,v 1.8 2007/04/19 14:28:43 scottl Exp $
  */
 
 #ifndef _CAM_CAM_SIM_H
@@ -56,6 +56,7 @@
 				const char *sim_name,
 				void *softc,
 				u_int32_t unit,
+				struct mtx *mtx,
 				int max_dev_transactions,
 				int max_tagged_dev_transactions,
 				struct cam_devq *queue);
@@ -90,17 +91,36 @@
 	sim_poll_func		sim_poll;
 	const char		*sim_name;
 	void			*softc;
+	struct mtx		*mtx;
+	TAILQ_HEAD(, ccb_hdr)	sim_doneq;
+	TAILQ_ENTRY(cam_sim)	links;
 	u_int32_t		path_id;/* The Boot device may set this to 0? */
 	u_int32_t		unit_number;
 	u_int32_t		bus_id;
 	int			max_tagged_dev_openings;
 	int			max_dev_openings;
 	u_int32_t		flags;
-#define		CAM_SIM_REL_TIMEOUT_PENDING	0x01
-	struct callout_handle	c_handle;
+#define	CAM_SIM_REL_TIMEOUT_PENDING	0x01
+#define	CAM_SIM_MPSAFE			0x02
+#define CAM_SIM_ON_DONEQ		0x04
+	struct callout		callout;
 	struct cam_devq 	*devq;	/* Device Queue to use for this SIM */
+
+	/* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */
+	SLIST_HEAD(,ccb_hdr)	ccb_freeq;
+	/*
+	 * Maximum size of ccb pool.  Modified as devices are added/removed
+	 * or have their * opening counts changed.
+	 */
+	u_int			max_ccbs;
+	/* Current count of allocated ccbs */
+	u_int			ccb_count;
+
 };
 
+#define CAM_SIM_LOCK(sim)	mtx_lock((sim)->mtx);
+#define CAM_SIM_UNLOCK(sim)	mtx_unlock((sim)->mtx);
+
 static __inline u_int32_t
 cam_sim_path(struct cam_sim *sim)
 {
Index: cam.c
===================================================================
RCS file: /home/cvs/src/sys/cam/cam.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/cam.c -L sys/cam/cam.c -u -r1.1.1.1 -r1.2
--- sys/cam/cam.c
+++ sys/cam/cam.c
@@ -27,11 +27,10 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/cam.c,v 1.9 2005/01/05 22:34:34 imp Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/cam.c,v 1.11 2007/05/23 13:27:37 cognet Exp $");
 
 #include <sys/param.h>
 #ifdef _KERNEL
-#include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/sysctl.h>
@@ -373,7 +372,16 @@
 {
 	uint32_t size_mb, secs_per_cylinder;
 
-	size_mb = ccg->volume_size / ((1024L * 1024L) / ccg->block_size);
+	if (ccg->block_size == 0) {
+		ccg->ccb_h.status = CAM_REQ_CMP_ERR;
+		return;
+	}
+	size_mb = (1024L * 1024L) / ccg->block_size;
+	if (size_mb == 0) {
+		ccg->ccb_h.status = CAM_REQ_CMP_ERR;
+		return;
+	}
+	size_mb = ccg->volume_size / size_mb;
 	if (size_mb > 1024 && extended) {
 		ccg->heads = 255;
 		ccg->secs_per_track = 63;
@@ -382,6 +390,10 @@
 		ccg->secs_per_track = 32;
 	}
 	secs_per_cylinder = ccg->heads * ccg->secs_per_track;
+	if (secs_per_cylinder == 0) {
+		ccg->ccb_h.status = CAM_REQ_CMP_ERR;
+		return;
+	}
 	ccg->cylinders = ccg->volume_size / secs_per_cylinder;
 	ccg->ccb_h.status = CAM_REQ_CMP;
 }
Index: cam_xpt_sim.h
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_xpt_sim.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/cam_xpt_sim.h -L sys/cam/cam_xpt_sim.h -u -r1.1.1.1 -r1.2
--- sys/cam/cam_xpt_sim.h
+++ sys/cam/cam_xpt_sim.h
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/cam/cam_xpt_sim.h,v 1.8 2005/01/05 22:34:34 imp Exp $
+ * $FreeBSD: src/sys/cam/cam_xpt_sim.h,v 1.9 2007/06/17 05:55:53 scottl Exp $
  */
 
 #ifndef _CAM_CAM_XPT_SIM_H
@@ -37,7 +37,8 @@
 
 /* Functions accessed by SIM drivers */
 #ifdef _KERNEL
-int32_t		xpt_bus_register(struct cam_sim *sim, u_int32_t bus);
+int32_t		xpt_bus_register(struct cam_sim *sim, device_t parent,
+				 u_int32_t bus);
 int32_t		xpt_bus_deregister(path_id_t path_id);
 u_int32_t	xpt_freeze_simq(struct cam_sim *sim, u_int count);
 void		xpt_release_simq(struct cam_sim *sim, int run_queue);
Index: cam_ccb.h
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_ccb.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/cam/cam_ccb.h -L sys/cam/cam_ccb.h -u -r1.2 -r1.3
--- sys/cam/cam_ccb.h
+++ sys/cam/cam_ccb.h
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/cam/cam_ccb.h,v 1.28.2.1 2006/06/08 17:51:27 mjacob Exp $
+ * $FreeBSD: src/sys/cam/cam_ccb.h,v 1.35 2007/04/15 08:49:09 scottl Exp $
  */
 
 #ifndef _CAM_CAM_CCB_H
@@ -34,9 +34,7 @@
 #include <sys/queue.h>
 #include <sys/cdefs.h>
 #include <sys/time.h>
-#ifdef CAM_NEW_TRAN_CODE
 #include <sys/limits.h>
-#endif /* CAM_NEW_TRAN_CODE */
 #ifndef _KERNEL
 #include <sys/callout.h>
 #endif
@@ -209,7 +207,6 @@
 #define XPT_FC_IS_QUEUED(ccb) 	\
     (((ccb)->ccb_h.func_code & XPT_FC_QUEUED) != 0)
 
-#ifdef CAM_NEW_TRAN_CODE
 typedef enum {
 	PROTO_UNKNOWN,
 	PROTO_UNSPECIFIED,
@@ -226,14 +223,14 @@
 	XPORT_SSA,	/* Serial Storage Architecture */
 	XPORT_USB,	/* Universal Serial Bus */
 	XPORT_PPB,	/* Parallel Port Bus */
-	XPORT_ATA	/* AT Attachment */
+	XPORT_ATA,	/* AT Attachment */
+	XPORT_SAS,	/* Serial Attached SCSI */
 } cam_xport;
 
-#define PROTO_VERSION_UNKNOWN (UINT_MAX - 1) 
-#define PROTO_VERSION_UNSPECIFIED UINT_MAX 
-#define XPORT_VERSION_UNKNOWN (UINT_MAX - 1) 
-#define XPORT_VERSION_UNSPECIFIED UINT_MAX 
-#endif /* CAM_NEW_TRAN_CODE */
+#define PROTO_VERSION_UNKNOWN (UINT_MAX - 1)
+#define PROTO_VERSION_UNSPECIFIED UINT_MAX
+#define XPORT_VERSION_UNKNOWN (UINT_MAX - 1)
+#define XPORT_VERSION_UNSPECIFIED UINT_MAX
 
 typedef union {
 	LIST_ENTRY(ccb_hdr) le;
@@ -245,8 +242,7 @@
 typedef union {
 	void		*ptr;
 	u_long		field;
-	u_int8_t	bytes[sizeof(void *) > sizeof(u_long)
-			      ? sizeof(void *) : sizeof(u_long)];
+	u_int8_t	bytes[sizeof(uintptr_t)];
 } ccb_priv_entry;
 
 typedef union {
@@ -277,8 +273,12 @@
 	ccb_ppriv_area	periph_priv;
 	ccb_spriv_area	sim_priv;
 	u_int32_t	timeout;	/* Timeout value */
+
+	/*
+	 * Deprecated, only for use by non-MPSAFE SIMs.  All others must
+	 * allocate and initialize their own callout storage.
+	 */
 	struct		callout_handle timeout_ch;
-					/* Callout handle used for timeouts */
 };
 
 /* Get Device Information CCB */
@@ -517,7 +517,6 @@
 	PIM_SEQSCAN	= 0x04	/* Do bus scans sequentially, not in parallel */
 } pi_miscflag;
 
-#ifdef CAM_NEW_TRAN_CODE
 /* Path Inquiry CCB */
 struct ccb_pathinq_settings_spi {
 	u_int8_t ppr_options;
@@ -528,8 +527,10 @@
 	u_int32_t port;		/* 24 bit port id, if known */
 	u_int32_t bitrate;	/* Mbps */
 };
+struct ccb_pathinq_settings_sas {
+	u_int32_t bitrate;	/* Mbps */
+};
 #define	PATHINQ_SETTINGS_SIZE	128
-#endif /* CAM_NEW_TRAN_CODE */
 
 struct ccb_pathinq {
 	struct 	    ccb_hdr ccb_h;
@@ -551,7 +552,6 @@
 	u_int32_t   unit_number;	/* Unit number for SIM */
 	u_int32_t   bus_id;		/* Bus ID for SIM */
 	u_int32_t   base_transfer_speed;/* Base bus speed in KB/sec */
-#ifdef CAM_NEW_TRAN_CODE
 	cam_proto   protocol;
 	u_int	    protocol_version;
 	cam_xport   transport;
@@ -559,9 +559,9 @@
 	union {
 		struct ccb_pathinq_settings_spi spi;
 		struct ccb_pathinq_settings_fc fc;
+		struct ccb_pathinq_settings_sas sas;
 		char ccb_pathinq_settings_opaque[PATHINQ_SETTINGS_SIZE];
 	} xport_specific;
-#endif /* CAM_NEW_TRAN_CODE */
 };
 
 /* Path Statistics CCB */
@@ -699,27 +699,6 @@
 	union	ccb *termio_ccb;	/* Pointer to CCB to terminate */
 };
 
-#ifndef CAM_NEW_TRAN_CODE
-/* Get/Set transfer rate/width/disconnection/tag queueing settings */
-struct ccb_trans_settings {
-	struct	ccb_hdr ccb_h;
-	u_int	valid;  /* Which fields to honor */
-#define		CCB_TRANS_SYNC_RATE_VALID	0x01
-#define		CCB_TRANS_SYNC_OFFSET_VALID	0x02
-#define		CCB_TRANS_BUS_WIDTH_VALID	0x04
-#define		CCB_TRANS_DISC_VALID		0x08
-#define		CCB_TRANS_TQ_VALID		0x10
-	u_int	flags;
-#define		CCB_TRANS_CURRENT_SETTINGS	0x01
-#define		CCB_TRANS_USER_SETTINGS		0x02
-#define		CCB_TRANS_DISC_ENB		0x04
-#define		CCB_TRANS_TAG_ENB		0x08
-	u_int	sync_period;
-	u_int	sync_offset;
-	u_int	bus_width;
-};
-
-#else /* CAM_NEW_TRAN_CODE */
 typedef enum {
 	CTS_TYPE_CURRENT_SETTINGS,
 	CTS_TYPE_USER_SETTINGS
@@ -743,7 +722,6 @@
 #define CTS_SPI_VALID_PPR_OPTIONS	0x10
 	u_int	flags;
 #define	CTS_SPI_FLAGS_DISC_ENB		0x01
-#define	CTS_SPI_FLAGS_TAG_ENB		0x02
 	u_int	sync_period;
 	u_int	sync_offset;
 	u_int	bus_width;
@@ -762,6 +740,13 @@
 	u_int32_t 	bitrate;	/* Mbps */
 };
 
+struct ccb_trans_settings_sas {
+	u_int     	valid;		/* Which fields to honor */
+#define	CTS_SAS_VALID_SPEED		0x1000
+	u_int32_t 	bitrate;	/* Mbps */
+};
+
+
 /* Get/Set transfer rate/width/disconnection/tag queueing settings */
 struct ccb_trans_settings {
 	struct	  ccb_hdr ccb_h;
@@ -778,10 +763,10 @@
 		u_int  valid;	/* Which fields to honor */
 		struct ccb_trans_settings_spi spi;
 		struct ccb_trans_settings_fc fc;
+		struct ccb_trans_settings_sas sas;
 	} xport_specific;
 };
 
-#endif /* CAM_NEW_TRAN_CODE */
 
 /*
  * Calculate the geometry parameters for a device
Index: cam_periph.c
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_periph.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/cam/cam_periph.c -L sys/cam/cam_periph.c -u -r1.2 -r1.3
--- sys/cam/cam_periph.c
+++ sys/cam/cam_periph.c
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/cam_periph.c,v 1.60.2.1 2006/02/26 22:38:39 iedowse Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/cam_periph.c,v 1.69 2007/05/14 21:48:52 scottl Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -51,6 +51,7 @@
 #include <cam/cam_xpt_periph.h>
 #include <cam/cam_periph.h>
 #include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
 
 #include <cam/scsi/scsi_all.h>
 #include <cam/scsi/scsi_message.h>
@@ -86,6 +87,14 @@
 
 MALLOC_DEFINE(M_CAMPERIPH, "CAM periph", "CAM peripheral buffers");
 
+static int periph_selto_delay = 1000;
+TUNABLE_INT("kern.cam.periph_selto_delay", &periph_selto_delay);
+static int periph_noresrc_delay = 500;
+TUNABLE_INT("kern.cam.periph_noresrc_delay", &periph_noresrc_delay);
+static int periph_busy_delay = 500;
+TUNABLE_INT("kern.cam.periph_busy_delay", &periph_busy_delay);
+
+
 void
 periphdriver_register(void *data)
 {
@@ -93,7 +102,8 @@
 	int ndrivers;
 
 	ndrivers = nperiph_drivers + 2;
-	newdrivers = malloc(sizeof(*newdrivers) * ndrivers, M_TEMP, M_WAITOK);
+	newdrivers = malloc(sizeof(*newdrivers) * ndrivers, M_CAMPERIPH,
+			    M_WAITOK);
 	if (periph_drivers)
 		bcopy(periph_drivers, newdrivers,
 		      sizeof(*newdrivers) * nperiph_drivers);
@@ -102,7 +112,7 @@
 	old = periph_drivers;
 	periph_drivers = newdrivers;
 	if (old)
-		free(old, M_TEMP);
+		free(old, M_CAMPERIPH);
 	nperiph_drivers++;
 }
 
@@ -114,6 +124,7 @@
 		 ac_callback_t *ac_callback, ac_code code, void *arg)
 {
 	struct		periph_driver **p_drv;
+	struct		cam_sim *sim;
 	struct		cam_periph *periph;
 	struct		cam_periph *cur_periph;
 	path_id_t	path_id;
@@ -121,7 +132,6 @@
 	lun_id_t	lun_id;
 	cam_status	status;
 	u_int		init_level;
-	int s;
 
 	init_level = 0;
 	/*
@@ -155,11 +165,14 @@
 	
 	init_level++;
 
+	xpt_lock_buses();
 	for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) {
 		if (strcmp((*p_drv)->driver_name, name) == 0)
 			break;
 	}
-	
+	xpt_unlock_buses();
+
+	sim = xpt_path_sim(path);
 	path_id = xpt_path_path_id(path);
 	target_id = xpt_path_target_id(path);
 	lun_id = xpt_path_lun_id(path);
@@ -173,6 +186,7 @@
 	periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id);
 	periph->immediate_priority = CAM_PRIORITY_NONE;
 	periph->refcount = 0;
+	periph->sim = sim;
 	SLIST_INIT(&periph->ccb_list);
 	status = xpt_create_path(&path, periph, path_id, target_id, lun_id);
 	if (status != CAM_REQ_CMP)
@@ -186,7 +200,6 @@
 	if (status != CAM_REQ_CMP)
 		goto failure;
 
-	s = splsoftcam();
 	cur_periph = TAILQ_FIRST(&(*p_drv)->units);
 	while (cur_periph != NULL
 	    && cur_periph->unit_number < periph->unit_number)
@@ -199,8 +212,6 @@
 		(*p_drv)->generation++;
 	}
 
-	splx(s);
-
 	init_level++;
 
 	status = periph_ctor(periph, arg);
@@ -214,9 +225,7 @@
 		/* Initialized successfully */
 		break;
 	case 3:
-		s = splsoftcam();
 		TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
-		splx(s);
 		xpt_remove_periph(periph);
 		/* FALLTHROUGH */
 	case 2:
@@ -244,38 +253,38 @@
 {
 	struct periph_driver **p_drv;
 	struct cam_periph *periph;
-	int s;
 
+	xpt_lock_buses();
 	for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) {
 
 		if (name != NULL && (strcmp((*p_drv)->driver_name, name) != 0))
 			continue;
 
-		s = splsoftcam();
 		TAILQ_FOREACH(periph, &(*p_drv)->units, unit_links) {
 			if (xpt_path_comp(periph->path, path) == 0) {
-				splx(s);
+				xpt_unlock_buses();
 				return(periph);
 			}
 		}
-		splx(s);
-		if (name != NULL)
+		if (name != NULL) {
+			xpt_unlock_buses();
 			return(NULL);
+		}
 	}
+	xpt_unlock_buses();
 	return(NULL);
 }
 
 cam_status
 cam_periph_acquire(struct cam_periph *periph)
 {
-	int s;
 
 	if (periph == NULL)
 		return(CAM_REQ_CMP_ERR);
 
-	s = splsoftcam();
+	xpt_lock_buses();
 	periph->refcount++;
-	splx(s);
+	xpt_unlock_buses();
 
 	return(CAM_REQ_CMP);
 }
@@ -283,20 +292,68 @@
 void
 cam_periph_release(struct cam_periph *periph)
 {
-	int s;
 
 	if (periph == NULL)
 		return;
 
-	s = splsoftcam();
+	xpt_lock_buses();
 	if ((--periph->refcount == 0)
 	 && (periph->flags & CAM_PERIPH_INVALID)) {
 		camperiphfree(periph);
 	}
-	splx(s);
+	xpt_unlock_buses();
 
 }
 
+int
+cam_periph_hold(struct cam_periph *periph, int priority)
+{
+	struct mtx *mtx;
+	int error;
+
+	mtx_assert(periph->sim->mtx, MA_OWNED);
+
+	/*
+	 * Increment the reference count on the peripheral
+	 * while we wait for our lock attempt to succeed
+	 * to ensure the peripheral doesn't disappear out
+	 * from user us while we sleep.
+	 */
+
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+		return (ENXIO);
+
+	mtx = periph->sim->mtx;
+	if (mtx == &Giant)
+		mtx = NULL;
+
+	while ((periph->flags & CAM_PERIPH_LOCKED) != 0) {
+		periph->flags |= CAM_PERIPH_LOCK_WANTED;
+		if ((error = msleep(periph, mtx, priority, "caplck", 0)) != 0) {
+			cam_periph_release(periph);
+			return (error);
+		}
+	}
+
+	periph->flags |= CAM_PERIPH_LOCKED;
+	return (0);
+}
+
+void
+cam_periph_unhold(struct cam_periph *periph)
+{
+
+	mtx_assert(periph->sim->mtx, MA_OWNED);
+
+	periph->flags &= ~CAM_PERIPH_LOCKED;
+	if ((periph->flags & CAM_PERIPH_LOCK_WANTED) != 0) {
+		periph->flags &= ~CAM_PERIPH_LOCK_WANTED;
+		wakeup(periph);
+	}
+
+	cam_periph_release(periph);
+}
+
 /*
  * Look for the next unit number that is not currently in use for this
  * peripheral type starting at "newunit".  Also exclude unit numbers that
@@ -311,11 +368,9 @@
 {
 	struct	cam_periph *periph;
 	char	*periph_name;
-	int	s;
 	int	i, val, dunit, r;
 	const char *dname, *strval;
 
-	s = splsoftcam();
 	periph_name = p_drv->driver_name;
 	for (;;newunit++) {
 
@@ -326,12 +381,12 @@
 
 		if (periph != NULL && periph->unit_number == newunit) {
 			if (wired != 0) {
-				xpt_print_path(periph->path);
-				printf("Duplicate Wired Device entry!\n");
-				xpt_print_path(periph->path);
-				printf("Second device (%s device at scbus%d "
-				       "target %d lun %d) will not be wired\n",
-				       periph_name, pathid, target, lun);
+				xpt_print(periph->path, "Duplicate Wired "
+				    "Device entry!\n");
+				xpt_print(periph->path, "Second device (%s "
+				    "device at scbus%d target %d lun %d) will "
+				    "not be wired\n", periph_name, pathid,
+				    target, lun);
 				wired = 0;
 			}
 			continue;
@@ -361,7 +416,6 @@
 		if (r != 0)
 			break;
 	}
-	splx(s);
 	return (newunit);
 }
 
@@ -416,13 +470,10 @@
 void
 cam_periph_invalidate(struct cam_periph *periph)
 {
-	int s;
 
-	s = splsoftcam();
 	/*
 	 * We only call this routine the first time a peripheral is
-	 * invalidated.  The oninvalidate() routine is always called at
-	 * splsoftcam().
+	 * invalidated.
 	 */
 	if (((periph->flags & CAM_PERIPH_INVALID) == 0)
 	 && (periph->periph_oninval != NULL))
@@ -431,17 +482,17 @@
 	periph->flags |= CAM_PERIPH_INVALID;
 	periph->flags &= ~CAM_PERIPH_NEW_DEV_FOUND;
 
+	xpt_lock_buses();
 	if (periph->refcount == 0)
 		camperiphfree(periph);
 	else if (periph->refcount < 0)
 		printf("cam_invalidate_periph: refcount < 0!!\n");
-	splx(s);
+	xpt_unlock_buses();
 }
 
 static void
 camperiphfree(struct cam_periph *periph)
 {
-	int s;
 	struct periph_driver **p_drv;
 
 	for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) {
@@ -452,15 +503,13 @@
 		printf("camperiphfree: attempt to free non-existant periph\n");
 		return;
 	}
-	
-	if (periph->periph_dtor != NULL)
-		periph->periph_dtor(periph);
-	
-	s = splsoftcam();
+
 	TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
 	(*p_drv)->generation++;
-	splx(s);
+	xpt_unlock_buses();
 
+	if (periph->periph_dtor != NULL)
+		periph->periph_dtor(periph);
 	xpt_remove_periph(periph);
 
 	if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) {
@@ -489,50 +538,7 @@
 	}
 	xpt_free_path(periph->path);
 	free(periph, M_CAMPERIPH);
-}
-
-/*
- * Wait interruptibly for an exclusive lock.
- */
-int
-cam_periph_lock(struct cam_periph *periph, int priority)
-{
-	int error;
-
-	/*
-	 * Increment the reference count on the peripheral
-	 * while we wait for our lock attempt to succeed
-	 * to ensure the peripheral doesn't disappear out
-	 * from under us while we sleep.
-	 */
-	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
-		return(ENXIO);
-
-	while ((periph->flags & CAM_PERIPH_LOCKED) != 0) {
-		periph->flags |= CAM_PERIPH_LOCK_WANTED;
-		if ((error = tsleep(periph, priority, "caplck", 0)) != 0) {
-			cam_periph_release(periph);
-			return error;
-		}
-	}
-
-	periph->flags |= CAM_PERIPH_LOCKED;
-	return 0;
-}
-
-/*
- * Unlock and wake up any waiters.
- */
-void
-cam_periph_unlock(struct cam_periph *periph)
-{
-	periph->flags &= ~CAM_PERIPH_LOCKED;
-	if ((periph->flags & CAM_PERIPH_LOCK_WANTED) != 0) {
-		periph->flags &= ~CAM_PERIPH_LOCK_WANTED;
-		wakeup(periph);
-	}
-
-	cam_periph_release(periph);
+	xpt_lock_buses();
 }
 
 /*
@@ -673,6 +679,16 @@
 		mapinfo->num_bufs_used++;
 	}
 
+	/*
+	 * Now that we've gotten this far, change ownership to the kernel
+	 * of the buffers so that we don't run afoul of returning to user
+	 * space with locks (on the buffer) held.
+	 */
+	for (i = 0; i < numbufs; i++) {
+		BUF_KERNPROC(mapinfo->bp[i]);
+	}
+
+
 	return(0);
 }
 
@@ -734,12 +750,11 @@
 cam_periph_getccb(struct cam_periph *periph, u_int32_t priority)
 {
 	struct ccb_hdr *ccb_h;
-	int s;
+	struct mtx *mtx;
 
+	mtx_assert(periph->sim->mtx, MA_OWNED);
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdgetccb\n"));
 
-	s = splsoftcam();
-	
 	while (SLIST_FIRST(&periph->ccb_list) == NULL) {
 		if (periph->immediate_priority > priority)
 			periph->immediate_priority = priority;
@@ -747,26 +762,33 @@
 		if ((SLIST_FIRST(&periph->ccb_list) != NULL)
 		 && (SLIST_FIRST(&periph->ccb_list)->pinfo.priority == priority))
 			break;
-		tsleep(&periph->ccb_list, PRIBIO, "cgticb", 0);
+		mtx_assert(periph->sim->mtx, MA_OWNED);
+		if (periph->sim->mtx == &Giant)
+			mtx = NULL;
+		else
+			mtx = periph->sim->mtx;
+		msleep(&periph->ccb_list, mtx, PRIBIO, "cgticb", 0);
 	}
 
 	ccb_h = SLIST_FIRST(&periph->ccb_list);
 	SLIST_REMOVE_HEAD(&periph->ccb_list, periph_links.sle);
-	splx(s);
 	return ((union ccb *)ccb_h);
 }
 
 void
 cam_periph_ccbwait(union ccb *ccb)
 {
-	int s;
+	struct mtx *mtx;
+	struct cam_sim *sim;
 
-	s = splsoftcam();
+	sim = xpt_path_sim(ccb->ccb_h.path);
+	if (sim->mtx == &Giant)
+		mtx = NULL;
+	else
+		mtx = sim->mtx;
 	if ((ccb->ccb_h.pinfo.index != CAM_UNQUEUED_INDEX)
 	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG))
-		tsleep(&ccb->ccb_h.cbfcnp, PRIBIO, "cbwait", 0);
-
-	splx(s);
+		msleep(&ccb->ccb_h.cbfcnp, mtx, PRIBIO, "cbwait", 0);
 }
 
 int
@@ -839,10 +861,13 @@
 		  cam_flags camflags, u_int32_t sense_flags,
 		  struct devstat *ds)
 {
+	struct cam_sim *sim;
 	int error;
  
 	error = 0;
-        
+	sim = xpt_path_sim(ccb->ccb_h.path);
+	mtx_assert(sim->mtx, MA_OWNED);
+
 	/*
 	 * If the user has supplied a stats structure, and if we understand
 	 * this particular type of ccb, record the transaction start.
@@ -977,8 +1002,8 @@
 					saved_ccb->ccb_h.status |=
 					    CAM_AUTOSNS_VALID;
 #if 0
-					xpt_print_path(saved_ccb->ccb_h.path);
-					printf("Recovered Sense\n");
+					xpt_print(saved_ccb->ccb_h.path,
+					    "Recovered Sense\n");
 					scsi_sense_print(&saved_ccb->csio);
 					cam_error_print(saved_ccb, CAM_ESF_ALL,
 							CAM_EPF_ALL);
@@ -1168,11 +1193,8 @@
 {
 	struct timeval delta;
 	struct timeval duration_tv;
-	int s;
 
-	s = splclock();
 	microtime(&delta);
-	splx(s);
 	timevalsub(&delta, event_time);
 	duration_tv.tv_sec = duration_ms / 1000;
 	duration_tv.tv_usec = (duration_ms % 1000) * 1000;
@@ -1269,8 +1291,7 @@
 			*timeout = 0;
 			error = ERESTART;
 			if (bootverbose) {
-				xpt_print_path(ccb->ccb_h.path);
-				printf("Queue Full\n");
+				xpt_print(ccb->ccb_h.path, "Queue Full\n");
 			}
 			break;
 		}
@@ -1282,8 +1303,7 @@
 		 * command completes or a 1 second timeout.
 		 */
 		if (bootverbose) {
-			xpt_print_path(ccb->ccb_h.path);
-			printf("Device Busy\n");
+			xpt_print(ccb->ccb_h.path, "Device Busy\n");
 		}
 	 	if (ccb->ccb_h.retry_count > 0) {
 	 		ccb->ccb_h.retry_count--;
@@ -1296,13 +1316,12 @@
 		}
 		break;
 	case SCSI_STATUS_RESERV_CONFLICT:
-		xpt_print_path(ccb->ccb_h.path);
-		printf("Reservation Conflict\n");
+		xpt_print(ccb->ccb_h.path, "Reservation Conflict\n");
 		error = EIO;
 		break;
 	default:
-		xpt_print_path(ccb->ccb_h.path);
-		printf("SCSI Status 0x%x\n", ccb->csio.scsi_status);
+		xpt_print(ccb->ccb_h.path, "SCSI Status 0x%x\n",
+		    ccb->csio.scsi_status);
 		error = EIO;
 		break;
 	}
@@ -1534,7 +1553,7 @@
 	int	    error, printed = 0;
 	int         openings;
 	u_int32_t   relsim_flags;
-	u_int32_t   timeout;
+	u_int32_t   timeout = 0;
 	
 	action_string = NULL;
 	status = ccb->ccb_h.status;
@@ -1556,42 +1575,38 @@
 						 &timeout);
 		break;
 	case CAM_AUTOSENSE_FAIL:
-		xpt_print_path(ccb->ccb_h.path);
-		printf("AutoSense Failed\n");
+		xpt_print(ccb->ccb_h.path, "AutoSense Failed\n");
 		error = EIO;	/* we have to kill the command */
 		break;
 	case CAM_REQ_CMP_ERR:
 		if (bootverbose && printed == 0) {
-			xpt_print_path(ccb->ccb_h.path);
-			printf("Request completed with CAM_REQ_CMP_ERR\n");
+			xpt_print(ccb->ccb_h.path,
+			    "Request completed with CAM_REQ_CMP_ERR\n");
 			printed++;
 		}
 		/* FALLTHROUGH */
 	case CAM_CMD_TIMEOUT:
 		if (bootverbose && printed == 0) {
-			xpt_print_path(ccb->ccb_h.path);
-			printf("Command timed out\n");
+			xpt_print(ccb->ccb_h.path, "Command timed out\n");
 			printed++;
 		}
 		/* FALLTHROUGH */
 	case CAM_UNEXP_BUSFREE:
 		if (bootverbose && printed == 0) {
-			xpt_print_path(ccb->ccb_h.path);
-			printf("Unexpected Bus Free\n");
+			xpt_print(ccb->ccb_h.path, "Unexpected Bus Free\n");
 			printed++;
 		}
 		/* FALLTHROUGH */
 	case CAM_UNCOR_PARITY:
 		if (bootverbose && printed == 0) {
-			xpt_print_path(ccb->ccb_h.path);
-			printf("Uncorrected Parity Error\n");
+			xpt_print(ccb->ccb_h.path,
+			    "Uncorrected Parity Error\n");
 			printed++;
 		}
 		/* FALLTHROUGH */
 	case CAM_DATA_RUN_ERR:
 		if (bootverbose && printed == 0) {
-			xpt_print_path(ccb->ccb_h.path);
-			printf("Data Overrun\n");
+			xpt_print(ccb->ccb_h.path, "Data Overrun\n");
 			printed++;
 		}
 		error = EIO;	/* we have to kill the command */
@@ -1620,17 +1635,17 @@
 				ccb->ccb_h.retry_count--;
 				error = ERESTART;
 				if (bootverbose && printed == 0) {
-					xpt_print_path(ccb->ccb_h.path);
-					printf("Selection Timeout\n");
+					xpt_print(ccb->ccb_h.path,
+					    "Selection Timeout\n");
 					printed++;
 				}
 
 				/*
-				 * Wait a second to give the device
+				 * Wait a bit to give the device
 				 * time to recover before we try again.
 				 */
 				relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT;
-				timeout = 1000;
+				timeout = periph_selto_delay;
 				break;
 			}
 		}
@@ -1683,22 +1698,29 @@
 		/* Unconditional requeue */
 		error = ERESTART;
 		if (bootverbose && printed == 0) {
-			xpt_print_path(ccb->ccb_h.path);
-			printf("Request Requeued\n");
+			xpt_print(ccb->ccb_h.path, "Request Requeued\n");
 			printed++;
 		}
 		break;
 	case CAM_RESRC_UNAVAIL:
+		/* Wait a bit for the resource shortage to abate. */
+		timeout = periph_noresrc_delay;
+		/* FALLTHROUGH */
 	case CAM_BUSY:
-		/* timeout??? */
+		if (timeout == 0) {
+			/* Wait a bit for the busy condition to abate. */
+			timeout = periph_busy_delay;
+		}
+		relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT;
+		/* FALLTHROUGH */
 	default:
 		/* decrement the number of retries */
 		if (ccb->ccb_h.retry_count > 0) {
 			ccb->ccb_h.retry_count--;
 			error = ERESTART;
 			if (bootverbose && printed == 0) {
-				xpt_print_path(ccb->ccb_h.path);
-				printf("CAM Status 0x%x\n", status);
+				xpt_print(ccb->ccb_h.path, "CAM Status 0x%x\n",
+				    status);
 				printed++;
 			}
 		} else {
@@ -1737,11 +1759,9 @@
 		if (action_string == NULL)
 			action_string = "Unretryable Error";
 		if (error != ERESTART) {
-			xpt_print_path(ccb->ccb_h.path);
-			printf("error %d\n", error);
+			xpt_print(ccb->ccb_h.path, "error %d\n", error);
 		}
-		xpt_print_path(ccb->ccb_h.path);
-		printf("%s\n", action_string);
+		xpt_print(ccb->ccb_h.path, "%s\n", action_string);
 	}
 
 	return (error);
Index: cam_xpt.h
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_xpt.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/cam_xpt.h -L sys/cam/cam_xpt.h -u -r1.1.1.1 -r1.2
--- sys/cam/cam_xpt.h
+++ sys/cam/cam_xpt.h
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/cam/cam_xpt.h,v 1.5 2005/01/05 22:34:34 imp Exp $
+ * $FreeBSD: src/sys/cam/cam_xpt.h,v 1.9 2007/05/16 16:54:23 scottl Exp $
  */
 
 #ifndef _CAM_CAM_XPT_H
@@ -58,10 +58,15 @@
 					struct cam_periph *perph,
 					path_id_t path_id,
 					target_id_t target_id, lun_id_t lun_id);
+cam_status		xpt_create_path_unlocked(struct cam_path **new_path_ptr,
+					struct cam_periph *perph,
+					path_id_t path_id,
+					target_id_t target_id, lun_id_t lun_id);
 void			xpt_free_path(struct cam_path *path);
 int			xpt_path_comp(struct cam_path *path1,
 				      struct cam_path *path2);
 void			xpt_print_path(struct cam_path *path);
+void			xpt_print(struct cam_path *path, const char *fmt, ...);
 int			xpt_path_string(struct cam_path *path, char *str,
 					size_t str_len);
 path_id_t		xpt_path_path_id(struct cam_path *path);
@@ -71,6 +76,11 @@
 struct cam_periph	*xpt_path_periph(struct cam_path *path);
 void			xpt_async(u_int32_t async_code, struct cam_path *path,
 				  void *async_arg);
+void			xpt_rescan(union ccb *ccb);
+void			xpt_lock_buses(void);
+void			xpt_unlock_buses(void);
+cam_status		xpt_register_async(int event, ac_callback_t *cbfunc,
+					   void *cbarg, struct cam_path *path);
 #endif /* _KERNEL */
 
 #endif /* _CAM_CAM_XPT_H */
Index: cam_xpt_periph.h
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_xpt_periph.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/cam_xpt_periph.h -L sys/cam/cam_xpt_periph.h -u -r1.1.1.1 -r1.2
--- sys/cam/cam_xpt_periph.h
+++ sys/cam/cam_xpt_periph.h
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/cam/cam_xpt_periph.h,v 1.5 2005/07/01 15:21:29 avatar Exp $
+ * $FreeBSD: src/sys/cam/cam_xpt_periph.h,v 1.7 2007/04/18 04:58:52 scottl Exp $
  */
 
 #ifndef _CAM_CAM_XPT_PERIPH_H
Index: cam_debug.h
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_debug.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/cam_debug.h -L sys/cam/cam_debug.h -u -r1.1.1.1 -r1.2
--- sys/cam/cam_debug.h
+++ sys/cam/cam_debug.h
@@ -25,15 +25,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/cam/cam_debug.h,v 1.8 2005/01/05 22:34:34 imp Exp $
+ * $FreeBSD: src/sys/cam/cam_debug.h,v 1.9 2006/05/16 14:37:57 phk Exp $
  */
 #ifndef	_CAM_CAM_DEBUG_H
 #define _CAM_CAM_DEBUG_H 1
 
-#if defined(CAMDEBUG) && defined(_KERNEL)
-#include <machine/clock.h>
-#endif /* CAMDEBUG && _KERNEL */
-
 /*
  * Debugging flags.
  */
Index: cam_periph.h
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_periph.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/cam_periph.h -L sys/cam/cam_periph.h -u -r1.1.1.1 -r1.2
--- sys/cam/cam_periph.h
+++ sys/cam/cam_periph.h
@@ -25,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/cam/cam_periph.h,v 1.16 2005/01/05 22:34:34 imp Exp $
+ * $FreeBSD: src/sys/cam/cam_periph.h,v 1.18 2007/04/19 22:46:26 scottl Exp $
  */
 
 #ifndef _CAM_CAM_PERIPH_H
 #define _CAM_CAM_PERIPH_H 1
 
 #include <sys/queue.h>
+#include <cam/cam_sim.h>
 
 #ifdef _KERNEL
 
@@ -104,6 +105,7 @@
 	char			*periph_name;
 	struct cam_path		*path;	/* Compiled path to device */
 	void			*softc;
+	struct cam_sim		*sim;
 	u_int32_t		 unit_number;
 	cam_periph_type		 type;
 	u_int32_t		 flags;
@@ -113,6 +115,7 @@
 #define CAM_PERIPH_INVALID		0x08
 #define CAM_PERIPH_NEW_DEV_FOUND	0x10
 #define CAM_PERIPH_RECOVERY_INPROG	0x20
+#define CAM_PERIPH_POLLED		0x40
 	u_int32_t		 immediate_priority;
 	u_int32_t		 refcount;
 	SLIST_HEAD(, ccb_hdr)	 ccb_list;	/* For "immediate" requests */
@@ -136,10 +139,10 @@
 			    char *name, cam_periph_type type, struct cam_path *,
 			    ac_callback_t *, ac_code, void *arg);
 struct cam_periph *cam_periph_find(struct cam_path *path, char *name);
-int		cam_periph_lock(struct cam_periph *periph, int priority);
-void		cam_periph_unlock(struct cam_periph *periph);
 cam_status	cam_periph_acquire(struct cam_periph *periph);
 void		cam_periph_release(struct cam_periph *periph);
+int		cam_periph_hold(struct cam_periph *periph, int priority);
+void		cam_periph_unhold(struct cam_periph *periph);
 void		cam_periph_invalidate(struct cam_periph *periph);
 int		cam_periph_mapmem(union ccb *ccb,
 				  struct cam_periph_map_info *mapinfo);
@@ -173,5 +176,17 @@
 int		cam_periph_error(union ccb *ccb, cam_flags camflags,
 				 u_int32_t sense_flags, union ccb *save_ccb);
 
+static __inline void
+cam_periph_lock(struct cam_periph *periph)
+{
+	mtx_lock(periph->sim->mtx);
+}
+
+static __inline void
+cam_periph_unlock(struct cam_periph *periph)
+{
+	mtx_unlock(periph->sim->mtx);
+}
+
 #endif /* _KERNEL */
 #endif /* _CAM_CAM_PERIPH_H */
Index: cam_sim.c
===================================================================
RCS file: /home/cvs/src/sys/cam/cam_sim.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/cam_sim.c -L sys/cam/cam_sim.c -u -r1.1.1.1 -r1.2
--- sys/cam/cam_sim.c
+++ sys/cam/cam_sim.c
@@ -27,12 +27,14 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/cam_sim.c,v 1.9 2005/07/01 15:21:29 avatar Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/cam_sim.c,v 1.11 2007/04/19 14:28:43 scottl Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 
 #include <cam/cam.h>
 #include <cam/cam_ccb.h>
@@ -58,39 +60,43 @@
 struct cam_sim *
 cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll,
 	      const char *sim_name, void *softc, u_int32_t unit,
-	      int max_dev_transactions,
+	      struct mtx *mtx, int max_dev_transactions,
 	      int max_tagged_dev_transactions, struct cam_devq *queue)
 {
 	struct cam_sim *sim;
 
-	/*
-	 * If this is the xpt layer creating a sim, then it's OK
-	 * to wait for an allocation.
-	 *
-	 * XXX Should we pass in a flag to indicate that wait is OK?
-	 */
-	if (strcmp(sim_name, "xpt") == 0)
-		sim = (struct cam_sim *)malloc(sizeof(struct cam_sim),
-					       M_CAMSIM, M_WAITOK);
-	else
-		sim = (struct cam_sim *)malloc(sizeof(struct cam_sim),
-					       M_CAMSIM, M_NOWAIT);
-
-	if (sim != NULL) {
-		sim->sim_action = sim_action;
-		sim->sim_poll = sim_poll;
-		sim->sim_name = sim_name;
-		sim->softc = softc;
-		sim->path_id = CAM_PATH_ANY;
-		sim->unit_number = unit;
-		sim->bus_id = 0;	/* set in xpt_bus_register */
-		sim->max_tagged_dev_openings = max_tagged_dev_transactions;
-		sim->max_dev_openings = max_dev_transactions;
-		sim->flags = 0;
-		callout_handle_init(&sim->c_handle);
-		sim->devq = queue;
+	if (mtx == NULL)
+		return (NULL);
+
+	sim = (struct cam_sim *)malloc(sizeof(struct cam_sim),
+	    M_CAMSIM, M_NOWAIT);
+
+	if (sim == NULL)
+		return (NULL);
+
+	sim->sim_action = sim_action;
+	sim->sim_poll = sim_poll;
+	sim->sim_name = sim_name;
+	sim->softc = softc;
+	sim->path_id = CAM_PATH_ANY;
+	sim->unit_number = unit;
+	sim->bus_id = 0;	/* set in xpt_bus_register */
+	sim->max_tagged_dev_openings = max_tagged_dev_transactions;
+	sim->max_dev_openings = max_dev_transactions;
+	sim->flags = 0;
+	sim->devq = queue;
+	sim->mtx = mtx;
+	if (mtx == &Giant) {
+		sim->flags |= 0;
+		callout_init(&sim->callout, 0);
+	} else {
+		sim->flags |= CAM_SIM_MPSAFE;
+		callout_init(&sim->callout, 1);
 	}
 
+	SLIST_INIT(&sim->ccb_freeq);
+	TAILQ_INIT(&sim->sim_doneq);
+
 	return (sim);
 }
 
Index: scsi_pass.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_pass.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/cam/scsi/scsi_pass.c -L sys/cam/scsi/scsi_pass.c -u -r1.2 -r1.3
--- sys/cam/scsi/scsi_pass.c
+++ sys/cam/scsi/scsi_pass.c
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_pass.c,v 1.43.2.1 2006/08/17 19:55:35 jhb Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_pass.c,v 1.48 2007/05/16 16:54:23 scottl Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -46,6 +46,7 @@
 #include <cam/cam_queue.h>
 #include <cam/cam_xpt_periph.h>
 #include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
 
 #include <cam/scsi/scsi_all.h>
 #include <cam/scsi/scsi_pass.h>
@@ -106,7 +107,7 @@
 
 static struct cdevsw pass_cdevsw = {
 	.d_version =	D_VERSION,
-	.d_flags =	D_NEEDGIANT,
+	.d_flags =	0,
 	.d_open =	passopen,
 	.d_close =	passclose,
 	.d_ioctl =	passioctl,
@@ -117,27 +118,12 @@
 passinit(void)
 {
 	cam_status status;
-	struct cam_path *path;
 
 	/*
 	 * Install a global async callback.  This callback will
 	 * receive async callbacks like "new device found".
 	 */
-	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
-				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
-
-	if (status == CAM_REQ_CMP) {
-		struct ccb_setasync csa;
-
-                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
-                csa.ccb_h.func_code = XPT_SASYNC_CB;
-                csa.event_enable = AC_FOUND_DEVICE;
-                csa.callback = passasync;
-                csa.callback_arg = NULL;
-                xpt_action((union ccb *)&csa);
-		status = csa.ccb_h.status;
-                xpt_free_path(path);
-        }
+	status = xpt_register_async(AC_FOUND_DEVICE, passasync, NULL, NULL);
 
 	if (status != CAM_REQ_CMP) {
 		printf("pass: Failed to attach master async callback "
@@ -150,20 +136,13 @@
 passoninvalidate(struct cam_periph *periph)
 {
 	struct pass_softc *softc;
-	struct ccb_setasync csa;
 
 	softc = (struct pass_softc *)periph->softc;
 
 	/*
 	 * De-register any async callbacks.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path,
-		      /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = 0;
-	csa.callback = passasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(0, passasync, periph, periph->path);
 
 	softc->flags |= PASS_FLAG_INVALID;
 
@@ -174,8 +153,7 @@
 	 */
 
 	if (bootverbose) {
-		xpt_print_path(periph->path);
-		printf("lost device\n");
+		xpt_print(periph->path, "lost device\n");
 	}
 
 }
@@ -192,8 +170,7 @@
 	destroy_dev(softc->dev);
 
 	if (bootverbose) {
-		xpt_print_path(periph->path);
-		printf("removing device entry\n");
+		xpt_print(periph->path, "removing device entry\n");
 	}
 	free(softc, M_DEVBUF);
 }
@@ -203,6 +180,7 @@
 	  struct cam_path *path, void *arg)
 {
 	struct cam_periph *periph;
+	struct cam_sim *sim;
 
 	periph = (struct cam_periph *)callback_arg;
 
@@ -221,6 +199,7 @@
 		 * this device and start the probe
 		 * process.
 		 */
+		sim = xpt_path_sim(cgd->ccb_h.path);
 		status = cam_periph_alloc(passregister, passoninvalidate,
 					  passcleanup, passstart, "pass",
 					  CAM_PERIPH_BIO, cgd->ccb_h.path,
@@ -249,7 +228,6 @@
 passregister(struct cam_periph *periph, void *arg)
 {
 	struct pass_softc *softc;
-	struct ccb_setasync csa;
 	struct ccb_getdev *cgd;
 	int    no_tags;
 
@@ -284,6 +262,7 @@
 	 * know what the blocksize of this device is, if 
 	 * it even has a blocksize.
 	 */
+	mtx_unlock(periph->sim->mtx);
 	no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0;
 	softc->device_stats = devstat_new_entry("pass",
 			  unit2minor(periph->unit_number), 0,
@@ -298,18 +277,14 @@
 	softc->dev = make_dev(&pass_cdevsw, unit2minor(periph->unit_number),
 			      UID_ROOT, GID_OPERATOR, 0600, "%s%d",
 			      periph->periph_name, periph->unit_number);
+	mtx_lock(periph->sim->mtx);
 	softc->dev->si_drv1 = periph;
 
 	/*
 	 * Add an async callback so that we get
 	 * notified if this device goes away.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = AC_LOST_DEVICE;
-	csa.callback = passasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(AC_LOST_DEVICE, passasync, periph, periph->path);
 
 	if (bootverbose)
 		xpt_announce_periph(periph, NULL);
@@ -323,19 +298,20 @@
 	struct cam_periph *periph;
 	struct pass_softc *softc;
 	int error;
-	int s;
 
 	error = 0; /* default to no error */
 
 	periph = (struct cam_periph *)dev->si_drv1;
-	if (periph == NULL)
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
 		return (ENXIO);
 
+	cam_periph_lock(periph);
+
 	softc = (struct pass_softc *)periph->softc;
 
-	s = splsoftcam();
 	if (softc->flags & PASS_FLAG_INVALID) {
-		splx(s);
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return(ENXIO);
 	}
 
@@ -344,7 +320,8 @@
 	 */
 	error = securelevel_gt(td->td_ucred, 1);
 	if (error) {
-		splx(s);
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return(error);
 	}
 
@@ -352,7 +329,8 @@
 	 * Only allow read-write access.
 	 */
 	if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) {
-		splx(s);
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return(EPERM);
 	}
 
@@ -360,23 +338,17 @@
 	 * We don't allow nonblocking access.
 	 */
 	if ((flags & O_NONBLOCK) != 0) {
-		xpt_print_path(periph->path);
-		printf("can't do nonblocking access\n");
-		splx(s);
+		xpt_print(periph->path, "can't do nonblocking access\n");
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return(EINVAL);
 	}
 
-	if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) {
-		splx(s);
-		return (error);
-	}
-
-	splx(s);
-
 	if ((softc->flags & PASS_FLAG_OPEN) == 0) {
-		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
-			return(ENXIO);
 		softc->flags |= PASS_FLAG_OPEN;
+	} else {
+		/* Device closes aren't symmertical, so fix up the refcount */
+		cam_periph_release(periph);
 	}
 
 	cam_periph_unlock(periph);
@@ -389,17 +361,14 @@
 {
 	struct 	cam_periph *periph;
 	struct	pass_softc *softc;
-	int	error;
 
 	periph = (struct cam_periph *)dev->si_drv1;
 	if (periph == NULL)
 		return (ENXIO);	
 
-	softc = (struct pass_softc *)periph->softc;
-
-	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
-		return (error);
+	cam_periph_lock(periph);
 
+	softc = (struct pass_softc *)periph->softc;
 	softc->flags &= ~PASS_FLAG_OPEN;
 
 	cam_periph_unlock(periph);
@@ -412,18 +381,15 @@
 passstart(struct cam_periph *periph, union ccb *start_ccb)
 {
 	struct pass_softc *softc;
-	int s;
 
 	softc = (struct pass_softc *)periph->softc;
 
 	switch (softc->state) {
 	case PASS_STATE_NORMAL:
-		s = splbio();
 		start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING;			
 		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
 				  periph_links.sle);
 		periph->immediate_priority = CAM_PRIORITY_NONE;
-		splx(s);
 		wakeup(&periph->ccb_list);
 		break;
 	}
@@ -457,6 +423,7 @@
 	if (periph == NULL)
 		return(ENXIO);
 
+	cam_periph_lock(periph);
 	softc = (struct pass_softc *)periph->softc;
 
 	error = 0;
@@ -476,9 +443,9 @@
 		 * through the transport layer device.
 		 */
 		if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {
-			xpt_print_path(periph->path);
-			printf("CCB function code %#x is restricted to the "
-			       "XPT device\n", inccb->ccb_h.func_code);
+			xpt_print(periph->path, "CCB function code %#x is "
+			    "restricted to the XPT device\n",
+			    inccb->ccb_h.func_code);
 			error = ENODEV;
 			break;
 		}
@@ -495,7 +462,7 @@
 						inccb->ccb_h.pinfo.priority);
 			ccb_malloced = 0;
 		} else {
-			ccb = xpt_alloc_ccb();
+			ccb = xpt_alloc_ccb_nowait();
 
 			if (ccb != NULL)
 				xpt_setup_ccb(&ccb->ccb_h, periph->path,
@@ -504,8 +471,7 @@
 		}
 
 		if (ccb == NULL) {
-			xpt_print_path(periph->path);
-			printf("unable to allocate CCB\n");
+			xpt_print(periph->path, "unable to allocate CCB\n");
 			error = ENOMEM;
 			break;
 		}
@@ -524,6 +490,7 @@
 		break;
 	}
 
+	cam_periph_unlock(periph);
 	return(error);
 }
 
@@ -572,7 +539,14 @@
 
 		bzero(&mapinfo, sizeof(mapinfo));
 
+		/*
+		 * cam_periph_mapmem calls into proc and vm functions that can
+		 * sleep as well as trigger I/O, so we can't hold the lock.
+		 * Dropping it here is reasonably safe.
+		 */
+		cam_periph_unlock(periph);
 		error = cam_periph_mapmem(ccb, &mapinfo); 
+		cam_periph_lock(periph);
 
 		/*
 		 * cam_periph_mapmem returned an error, we can't continue.
Index: scsi_pt.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_pt.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/scsi/scsi_pt.c -L sys/cam/scsi/scsi_pt.c -u -r1.1.1.1 -r1.2
--- sys/cam/scsi/scsi_pt.c
+++ sys/cam/scsi/scsi_pt.c
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_pt.c,v 1.43 2005/01/05 22:34:34 imp Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_pt.c,v 1.47 2007/05/16 16:54:23 scottl Exp $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -119,7 +119,7 @@
 
 static struct cdevsw pt_cdevsw = {
 	.d_version =	D_VERSION,
-	.d_flags =	D_NEEDGIANT,
+	.d_flags =	0,
 	.d_open =	ptopen,
 	.d_close =	ptclose,
 	.d_read =	physread,
@@ -138,40 +138,30 @@
 {
 	struct cam_periph *periph;
 	struct pt_softc *softc;
-	int unit;
-	int error;
-	int s;
+	int error = 0;
 
-	unit = minor(dev);
 	periph = (struct cam_periph *)dev->si_drv1;
-	if (periph == NULL)
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
 		return (ENXIO);	
 
 	softc = (struct pt_softc *)periph->softc;
 
-	s = splsoftcam();
+	cam_periph_lock(periph);
 	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
-		splx(s);
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return(ENXIO);
 	}
 
-	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
-	    ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit));
-
-	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
-		splx(s);
-		return (error); /* error code from tsleep */
+	if ((softc->flags & PT_FLAG_OPEN) == 0)
+		softc->flags |= PT_FLAG_OPEN;
+	else {
+		error = EBUSY;
+		cam_periph_release(periph);
 	}
 
-	splx(s);
-
-	if ((softc->flags & PT_FLAG_OPEN) == 0) {
-		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
-			error = ENXIO;
-		else
-			softc->flags |= PT_FLAG_OPEN;
-	} else
-		error = EBUSY;
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
+	    ("ptopen: dev=%s\n", devtoname(dev)));
 
 	cam_periph_unlock(periph);
 	return (error);
@@ -182,7 +172,6 @@
 {
 	struct	cam_periph *periph;
 	struct	pt_softc *softc;
-	int	error;
 
 	periph = (struct cam_periph *)dev->si_drv1;
 	if (periph == NULL)
@@ -190,8 +179,7 @@
 
 	softc = (struct pt_softc *)periph->softc;
 
-	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
-		return (error); /* error code from tsleep */
+	cam_periph_lock(periph);
 
 	softc->flags &= ~PT_FLAG_OPEN;
 	cam_periph_unlock(periph);
@@ -209,7 +197,6 @@
 {
 	struct cam_periph *periph;
 	struct pt_softc *softc;
-	int    s;
 	
 	periph = (struct cam_periph *)bp->bio_dev->si_drv1;
 	bp->bio_resid = bp->bio_bcount;
@@ -217,20 +204,14 @@
 		biofinish(bp, NULL, ENXIO);
 		return;
 	}
+	cam_periph_lock(periph);
 	softc = (struct pt_softc *)periph->softc;
 
 	/*
-	 * Mask interrupts so that the pack cannot be invalidated until
-	 * after we are in the queue.  Otherwise, we might not properly
-	 * clean up one of the buffers.
-	 */
-	s = splbio();
-	
-	/*
 	 * If the device has been made invalid, error out
 	 */
 	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
-		splx(s);
+		cam_periph_unlock(periph);
 		biofinish(bp, NULL, ENXIO);
 		return;
 	}
@@ -240,12 +221,11 @@
 	 */
 	bioq_insert_tail(&softc->bio_queue, bp);
 
-	splx(s);
-	
 	/*
 	 * Schedule ourselves for performing the work.
 	 */
 	xpt_schedule(periph, /* XXX priority */1);
+	cam_periph_unlock(periph);
 
 	return;
 }
@@ -254,27 +234,12 @@
 ptinit(void)
 {
 	cam_status status;
-	struct cam_path *path;
 
 	/*
 	 * Install a global async callback.  This callback will
 	 * receive async callbacks like "new device found".
 	 */
-	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
-				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
-
-	if (status == CAM_REQ_CMP) {
-		struct ccb_setasync csa;
-
-                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
-                csa.ccb_h.func_code = XPT_SASYNC_CB;
-                csa.event_enable = AC_FOUND_DEVICE;
-                csa.callback = ptasync;
-                csa.callback_arg = NULL;
-                xpt_action((union ccb *)&csa);
-		status = csa.ccb_h.status;
-                xpt_free_path(path);
-        }
+	status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL);
 
 	if (status != CAM_REQ_CMP) {
 		printf("pt: Failed to attach master async callback "
@@ -286,7 +251,6 @@
 ptctor(struct cam_periph *periph, void *arg)
 {
 	struct pt_softc *softc;
-	struct ccb_setasync csa;
 	struct ccb_getdev *cgd;
 
 	cgd = (struct ccb_getdev *)arg;
@@ -317,6 +281,7 @@
 
 	periph->softc = softc;
 	
+	cam_periph_unlock(periph);
 	softc->device_stats = devstat_new_entry("pt",
 			  periph->unit_number, 0,
 			  DEVSTAT_NO_BLOCKSIZE,
@@ -326,6 +291,7 @@
 	softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
 			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
 			      periph->unit_number);
+	cam_periph_lock(periph);
 	softc->dev->si_drv1 = periph;
 
 	/*
@@ -336,12 +302,8 @@
 	 * them and the only alternative would be to
 	 * not attach the device on failure.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
-	csa.callback = ptasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
+			   ptasync, periph, periph->path);
 
 	/* Tell the user we've attached to the device */
 	xpt_announce_periph(periph, NULL);
@@ -352,43 +314,25 @@
 static void
 ptoninvalidate(struct cam_periph *periph)
 {
-	int s;
 	struct pt_softc *softc;
-	struct ccb_setasync csa;
 
 	softc = (struct pt_softc *)periph->softc;
 
 	/*
 	 * De-register any async callbacks.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path,
-		      /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = 0;
-	csa.callback = ptasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(0, ptasync, periph, periph->path);
 
 	softc->flags |= PT_FLAG_DEVICE_INVALID;
 
 	/*
-	 * Although the oninvalidate() routines are always called at
-	 * splsoftcam, we need to be at splbio() here to keep the buffer
-	 * queue from being modified while we traverse it.
-	 */
-	s = splbio();
-
-	/*
 	 * Return all queued I/O with ENXIO.
 	 * XXX Handle any transactions queued to the card
 	 *     with XPT_ABORT_CCB.
 	 */
 	bioq_flush(&softc->bio_queue, NULL, ENXIO);
 
-	splx(s);
-
-	xpt_print_path(periph->path);
-	printf("lost device\n");
+	xpt_print(periph->path, "lost device\n");
 }
 
 static void
@@ -402,8 +346,7 @@
 
 	destroy_dev(softc->dev);
 
-	xpt_print_path(periph->path);
-	printf("removing device entry\n");
+	xpt_print(periph->path, "removing device entry\n");
 	free(softc, M_DEVBUF);
 }
 
@@ -447,10 +390,8 @@
 	{
 		struct pt_softc *softc;
 		struct ccb_hdr *ccbh;
-		int s;
 
 		softc = (struct pt_softc *)periph->softc;
-		s = splsoftcam();
 		/*
 		 * Don't fail on the expected unit attention
 		 * that will occur.
@@ -458,7 +399,6 @@
 		softc->flags |= PT_FLAG_RETRY_UA;
 		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
 			ccbh->ccb_state |= PT_CCB_RETRY_UA;
-		splx(s);
 	}
 	/* FALLTHROUGH */
 	default:
@@ -472,14 +412,12 @@
 {
 	struct pt_softc *softc;
 	struct bio *bp;
-	int s;
 
 	softc = (struct pt_softc *)periph->softc;
 
 	/*
 	 * See if there is a buf with work for us to do..
 	 */
-	s = splbio();
 	bp = bioq_first(&softc->bio_queue);
 	if (periph->immediate_priority <= periph->pinfo.priority) {
 		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
@@ -488,14 +426,10 @@
 		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
 				  periph_links.sle);
 		periph->immediate_priority = CAM_PRIORITY_NONE;
-		splx(s);
 		wakeup(&periph->ccb_list);
 	} else if (bp == NULL) {
-		splx(s);
 		xpt_release_ccb(start_ccb);
 	} else {
-		int oldspl;
-
 		bioq_remove(&softc->bio_queue, bp);
 
 		devstat_start_transaction_bio(softc->device_stats, bp);
@@ -517,14 +451,11 @@
 		 * Block out any asyncronous callbacks
 		 * while we touch the pending ccb list.
 		 */
-		oldspl = splcam();
 		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
 				 periph_links.le);
-		splx(oldspl);
 
 		start_ccb->ccb_h.ccb_bp = bp;
 		bp = bioq_first(&softc->bio_queue);
-		splx(s);
 
 		xpt_action(start_ccb);
 		
@@ -548,12 +479,10 @@
 	case PT_CCB_BUFFER_IO_UA:
 	{
 		struct bio *bp;
-		int    oldspl;
 
 		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
 			int error;
-			int s;
 			int sf;
 			
 			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
@@ -570,15 +499,13 @@
 				return;
 			}
 			if (error != 0) {
-				s = splbio();
-
 				if (error == ENXIO) {
 					/*
 					 * Catastrophic error.  Mark our device
 					 * as invalid.
 					 */
-					xpt_print_path(periph->path);
-					printf("Invalidating device\n");
+					xpt_print(periph->path,
+					    "Invalidating device\n");
 					softc->flags |= PT_FLAG_DEVICE_INVALID;
 				}
 
@@ -588,7 +515,6 @@
 				 * proper order should it attempt to recover.
 				 */
 				bioq_flush(&softc->bio_queue, NULL, EIO);
-				splx(s);
 				bp->bio_error = error;
 				bp->bio_resid = bp->bio_bcount;
 				bp->bio_flags |= BIO_ERROR;
@@ -616,9 +542,7 @@
 		 * Block out any asyncronous callbacks
 		 * while we touch the pending ccb list.
 		 */
-		oldspl = splcam();
 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
-		splx(oldspl);
 
 		biofinish(bp, softc->device_stats, 0);
 		break;
@@ -649,7 +573,7 @@
 {
 	struct cam_periph *periph;
 	struct pt_softc *softc;
-	int error;
+	int error = 0;
 
 	periph = (struct cam_periph *)dev->si_drv1;
 	if (periph == NULL)
@@ -657,9 +581,7 @@
 
 	softc = (struct pt_softc *)periph->softc;
 
-	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
-		return (error); /* error code from tsleep */
-	}	
+	cam_periph_lock(periph);
 
 	switch(cmd) {
 	case PTIOCGETTIMEOUT:
@@ -669,20 +591,14 @@
 			*(int *)addr = 0;
 		break;
 	case PTIOCSETTIMEOUT:
-	{
-		int s;
-
 		if (*(int *)addr < 1) {
 			error = EINVAL;
 			break;
 		}
 
-		s = splsoftcam();
 		softc->io_timeout = *(int *)addr * 1000;
-		splx(s);
 
 		break;
-	}
 	default:
 		error = cam_periph_ioctl(periph, cmd, addr, pterror);
 		break;
Index: scsi_ch.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_ch.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/scsi/scsi_ch.c -L sys/cam/scsi/scsi_ch.c -u -r1.1.1.1 -r1.2
--- sys/cam/scsi/scsi_ch.c
+++ sys/cam/scsi/scsi_ch.c
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_ch.c,v 1.42 2005/03/26 04:21:11 ken Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_ch.c,v 1.46 2007/05/16 16:54:23 scottl Exp $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -173,8 +173,6 @@
 	int		sc_settledelay;	/* delay for settle */
 };
 
-#define CHUNIT(x)       (minor((x)))
-
 static	d_open_t	chopen;
 static	d_close_t	chclose;
 static	d_ioctl_t	chioctl;
@@ -213,38 +211,25 @@
 
 static struct cdevsw ch_cdevsw = {
 	.d_version =	D_VERSION,
-	.d_flags =	D_NEEDGIANT,
+	.d_flags =	0,
 	.d_open =	chopen,
 	.d_close =	chclose,
 	.d_ioctl =	chioctl,
 	.d_name =	"ch",
 };
 
+MALLOC_DEFINE(M_SCSICH, "scsi_ch", "scsi_ch buffers");
+
 static void
 chinit(void)
 {
 	cam_status status;
-	struct cam_path *path;
 
 	/*
 	 * Install a global async callback.  This callback will
 	 * receive async callbacks like "new device found".
 	 */
-	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
-				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
-
-	if (status == CAM_REQ_CMP) {
-		struct ccb_setasync csa;
-
-                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
-                csa.ccb_h.func_code = XPT_SASYNC_CB;
-                csa.event_enable = AC_FOUND_DEVICE;
-                csa.callback = chasync;
-                csa.callback_arg = NULL;
-                xpt_action((union ccb *)&csa);
-		status = csa.ccb_h.status;
-                xpt_free_path(path);
-        }
+	status = xpt_register_async(AC_FOUND_DEVICE, chasync, NULL, NULL);
 
 	if (status != CAM_REQ_CMP) {
 		printf("ch: Failed to attach master async callback "
@@ -256,25 +241,17 @@
 choninvalidate(struct cam_periph *periph)
 {
 	struct ch_softc *softc;
-	struct ccb_setasync csa;
 
 	softc = (struct ch_softc *)periph->softc;
 
 	/*
 	 * De-register any async callbacks.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path,
-		      /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = 0;
-	csa.callback = chasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(0, chasync, periph, periph->path);
 
 	softc->flags |= CH_FLAG_INVALID;
 
-	xpt_print_path(periph->path);
-	printf("lost device\n");
+	xpt_print(periph->path, "lost device\n");
 
 }
 
@@ -287,8 +264,7 @@
 
 	devstat_remove_entry(softc->device_stats);
 	destroy_dev(softc->dev);
-	xpt_print_path(periph->path);
-	printf("removing device entry\n");
+	xpt_print(periph->path, "removing device entry\n");
 	free(softc, M_DEVBUF);
 }
 
@@ -340,7 +316,6 @@
 chregister(struct cam_periph *periph, void *arg)
 {
 	struct ch_softc *softc;
-	struct ccb_setasync csa;
 	struct ccb_getdev *cgd;
 
 	cgd = (struct ccb_getdev *)arg;
@@ -371,6 +346,7 @@
 	 * Changers don't have a blocksize, and obviously don't support
 	 * tagged queueing.
 	 */
+	cam_periph_unlock(periph);
 	softc->device_stats = devstat_new_entry("ch",
 			  periph->unit_number, 0,
 			  DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,
@@ -381,24 +357,20 @@
 	softc->dev = make_dev(&ch_cdevsw, periph->unit_number, UID_ROOT,
 			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
 			      periph->unit_number);
+	cam_periph_lock(periph);
 	softc->dev->si_drv1 = periph;
 
 	/*
 	 * Add an async callback so that we get
 	 * notified if this device goes away.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = AC_LOST_DEVICE;
-	csa.callback = chasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(AC_LOST_DEVICE, chasync, periph, periph->path);
 
 	/*
-	 * Lock this peripheral until we are setup.
+	 * Lock this periph until we are setup.
 	 * This first call can't block
 	 */
-	(void)cam_periph_lock(periph, PRIBIO);
+	(void)cam_periph_hold(periph, PRIBIO);
 	xpt_schedule(periph, /*priority*/5);
 
 	return(CAM_REQ_CMP);
@@ -410,31 +382,30 @@
 	struct cam_periph *periph;
 	struct ch_softc *softc;
 	int error;
-	int s;
 
 	periph = (struct cam_periph *)dev->si_drv1;
-	if (periph == NULL)
-		return(ENXIO);
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+		return (ENXIO);
 
 	softc = (struct ch_softc *)periph->softc;
 
-	s = splsoftcam();
+	cam_periph_lock(periph);
+	
 	if (softc->flags & CH_FLAG_INVALID) {
-		splx(s);
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return(ENXIO);
 	}
 
-	if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) {
-		splx(s);
-		return (error);
-	}
-	
-	splx(s);
-
-	if ((softc->flags & CH_FLAG_OPEN) == 0) {
-		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
-			return(ENXIO);
+	if ((softc->flags & CH_FLAG_OPEN) == 0)
 		softc->flags |= CH_FLAG_OPEN;
+	else
+		cam_periph_release(periph);
+
+	if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
+		return (error);
 	}
 
 	/*
@@ -447,6 +418,7 @@
 		return(error);
 	}
 
+	cam_periph_unhold(periph);
 	cam_periph_unlock(periph);
 
 	return(error);
@@ -467,8 +439,7 @@
 
 	softc = (struct ch_softc *)periph->softc;
 
-	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
-		return(error);
+	cam_periph_lock(periph);
 
 	softc->flags &= ~CH_FLAG_OPEN;
 
@@ -482,24 +453,20 @@
 chstart(struct cam_periph *periph, union ccb *start_ccb)
 {
 	struct ch_softc *softc;
-	int s;
 
 	softc = (struct ch_softc *)periph->softc;
 
 	switch (softc->state) {
 	case CH_STATE_NORMAL:
 	{
-		s = splbio();
 		if (periph->immediate_priority <= periph->pinfo.priority){
 			start_ccb->ccb_h.ccb_state = CH_CCB_WAITING;
 
 			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
 					  periph_links.sle);
 			periph->immediate_priority = CAM_PRIORITY_NONE;
-			splx(s);
 			wakeup(&periph->ccb_list);
-		} else
-			splx(s);
+		}
 		break;
 	}
 	case CH_STATE_PROBE:
@@ -515,7 +482,7 @@
 				  sizeof(struct scsi_mode_blk_desc) +
 				 sizeof(struct page_element_address_assignment);
 
-		mode_buffer = malloc(mode_buffer_len, M_TEMP, M_NOWAIT);
+		mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT);
 
 		if (mode_buffer == NULL) {
 			printf("chstart: couldn't malloc mode sense data\n");
@@ -647,13 +614,12 @@
 				    == CAM_SCSI_STATUS_ERROR) 
 					scsi_sense_print(&done_ccb->csio);
 				else {
-					xpt_print_path(periph->path);
-					printf("got CAM status %#x\n",
-					       done_ccb->ccb_h.status);
+					xpt_print(periph->path,
+					    "got CAM status %#x\n",
+					    done_ccb->ccb_h.status);
 				}
-				xpt_print_path(periph->path);
-				printf("fatal error, failed to attach to"
-				       " device\n");
+				xpt_print(periph->path, "fatal error, failed "
+				    "to attach to device\n");
 
 				cam_periph_invalidate(periph);
 
@@ -663,7 +629,7 @@
 		if (announce_buf[0] != '\0')
 			xpt_announce_periph(periph, announce_buf);
 		softc->state = CH_STATE_NORMAL;
-		free(mode_header, M_TEMP);
+		free(mode_header, M_SCSICH);
 		/*
 		 * Since our peripheral may be invalidated by an error
 		 * above or an external event, we must release our CCB
@@ -673,7 +639,7 @@
 		 * operation.
 		 */
 		xpt_release_ccb(done_ccb);
-		cam_periph_unlock(periph);
+		cam_periph_unhold(periph);
 		return;
 	}
 	case CH_CCB_WAITING:
@@ -712,6 +678,7 @@
 	if (periph == NULL)
 		return(ENXIO);
 
+	cam_periph_lock(periph);
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering chioctl\n"));
 
 	softc = (struct ch_softc *)periph->softc;
@@ -732,8 +699,10 @@
 		break;
 
 	default:
-		if ((flag & FWRITE) == 0)
+		if ((flag & FWRITE) == 0) {
+			cam_periph_unlock(periph);
 			return (EBADF);
+		}
 	}
 
 	switch (cmd) {
@@ -757,8 +726,10 @@
 	{
 		int new_picker = *(int *)addr;
 
-		if (new_picker > (softc->sc_counts[CHET_MT] - 1))
-			return (EINVAL);
+		if (new_picker > (softc->sc_counts[CHET_MT] - 1)) {
+			error = EINVAL;
+			break;
+		}
 		softc->sc_picker = softc->sc_firsts[CHET_MT] + new_picker;
 		break;
 	}
@@ -797,6 +768,7 @@
 		break;
 	}
 
+	cam_periph_unlock(periph);
 	return (error);
 }
 
@@ -1094,8 +1066,10 @@
 	 * we can allocate enough storage for all of them.  We assume
 	 * that the first one can fit into 1k.
 	 */
+	cam_periph_unlock(periph);
 	data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
 
+	cam_periph_lock(periph);
 	ccb = cam_periph_getccb(periph, /*priority*/ 1);
 
 	scsi_read_element_status(&ccb->csio,
@@ -1116,6 +1090,7 @@
 
 	if (error)
 		goto done;
+	cam_periph_unlock(periph);
 
 	st_hdr = (struct read_element_status_header *)data;
 	pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr +
@@ -1133,6 +1108,7 @@
 	free(data, M_DEVBUF);
 	data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
 
+	cam_periph_lock(periph);
 	scsi_read_element_status(&ccb->csio,
 				 /* retries */ 1,
 				 /* cbfcnp */ chdone,
@@ -1152,6 +1128,7 @@
 
 	if (error)
 		goto done;
+	cam_periph_unlock(periph);
 
 	/*
 	 * Fill in the user status array.
@@ -1162,8 +1139,8 @@
 	avail = scsi_2btoul(st_hdr->count);
 
 	if (avail != cesr->cesr_element_count) {
-		xpt_print_path(periph->path);
-		printf("warning, READ ELEMENT STATUS avail != count\n");
+		xpt_print(periph->path,
+		    "warning, READ ELEMENT STATUS avail != count\n");
 	}
 
 	user_data = (struct changer_element_status *)
@@ -1189,6 +1166,7 @@
 	error = copyout(user_data,
 			cesr->cesr_element_status,
 			avail * sizeof(struct changer_element_status));
+	cam_periph_lock(periph);
 
  done:
 	xpt_release_ccb(ccb);
@@ -1349,7 +1327,7 @@
 	 */
 	mode_buffer_len = sizeof(struct scsi_mode_sense_data);
 
-	mode_buffer = malloc(mode_buffer_len, M_TEMP, M_NOWAIT);
+	mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT);
 
 	if (mode_buffer == NULL) {
 		printf("chgetparams: couldn't malloc mode sense data\n");
@@ -1403,11 +1381,11 @@
 		}
 
 		if (error) {
-			xpt_print_path(periph->path);
-			printf("chgetparams: error getting element "
-			       "address page\n");
+			xpt_print(periph->path,
+			    "chgetparams: error getting element "
+			    "address page\n");
 			xpt_release_ccb(ccb);
-			free(mode_buffer, M_TEMP);
+			free(mode_buffer, M_SCSICH);
 			return(error);
 		}
 	}
@@ -1466,11 +1444,11 @@
 		}
 
 		if (error) {
-			xpt_print_path(periph->path);
-			printf("chgetparams: error getting device "
-			       "capabilities page\n");
+			xpt_print(periph->path,
+			    "chgetparams: error getting device "
+			    "capabilities page\n");
 			xpt_release_ccb(ccb);
-			free(mode_buffer, M_TEMP);
+			free(mode_buffer, M_SCSICH);
 			return(error);
 		}
 	}
@@ -1489,7 +1467,7 @@
 		softc->sc_exchangemask[from] = exchanges[from];
 	}
 
-	free(mode_buffer, M_TEMP);
+	free(mode_buffer, M_SCSICH);
 
 	return(error);
 }
Index: scsi_all.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_all.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/cam/scsi/scsi_all.c -L sys/cam/scsi/scsi_all.c -u -r1.2 -r1.3
--- sys/cam/scsi/scsi_all.c
+++ sys/cam/scsi/scsi_all.c
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.48.2.1 2006/09/09 07:21:18 ken Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.51 2007/06/04 18:25:03 dwmalone Exp $");
 
 #include <sys/param.h>
 
@@ -727,8 +727,6 @@
 #endif
 
 
-#include <sys/param.h>
-
 #if !defined(SCSI_NO_SENSE_STRINGS)
 #define SST(asc, ascq, action, desc) \
 	asc, ascq, action, desc
@@ -3025,7 +3023,7 @@
 	int error, delay;
 
 	delay = scsi_delay;
-	error = sysctl_handle_int(oidp, &delay, sizeof(delay), req);
+	error = sysctl_handle_int(oidp, &delay, 0, req);
 	if (error != 0 || req->newptr == NULL)
 		return (error);
 	return (set_scsi_delay(delay));
Index: scsi_ses.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_ses.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/scsi/scsi_ses.c -L sys/cam/scsi/scsi_ses.c -u -r1.1.1.1 -r1.2
--- sys/cam/scsi/scsi_ses.c
+++ sys/cam/scsi/scsi_ses.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_ses.c,v 1.32 2005/07/01 15:21:30 avatar Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_ses.c,v 1.35 2007/05/16 16:54:23 scottl Exp $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -43,6 +43,7 @@
 #include <cam/cam_periph.h>
 #include <cam/cam_xpt_periph.h>
 #include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
 
 #include <cam/scsi/scsi_all.h>
 #include <cam/scsi/scsi_message.h>
@@ -182,34 +183,19 @@
 	.d_close =	sesclose,
 	.d_ioctl =	sesioctl,
 	.d_name =	"ses",
-	.d_flags =	D_NEEDGIANT,
+	.d_flags =	0,
 };
 
 static void
 sesinit(void)
 {
 	cam_status status;
-	struct cam_path *path;
 
 	/*
 	 * Install a global async callback.  This callback will
 	 * receive async callbacks like "new device found".
 	 */
-	status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID,
-	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
-
-	if (status == CAM_REQ_CMP) {
-		struct ccb_setasync csa;
-
-                xpt_setup_ccb(&csa.ccb_h, path, 5);
-                csa.ccb_h.func_code = XPT_SASYNC_CB;
-                csa.event_enable = AC_FOUND_DEVICE;
-                csa.callback = sesasync;
-                csa.callback_arg = NULL;
-                xpt_action((union ccb *)&csa);
-		status = csa.ccb_h.status;
-                xpt_free_path(path);
-        }
+	status = xpt_register_async(AC_FOUND_DEVICE, sesasync, NULL, NULL);
 
 	if (status != CAM_REQ_CMP) {
 		printf("ses: Failed to attach master async callback "
@@ -221,24 +207,17 @@
 sesoninvalidate(struct cam_periph *periph)
 {
 	struct ses_softc *softc;
-	struct ccb_setasync csa;
 
 	softc = (struct ses_softc *)periph->softc;
 
 	/*
 	 * Unregister any async callbacks.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path, 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = 0;
-	csa.callback = sesasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(0, sesasync, periph, periph->path);
 
 	softc->ses_flags |= SES_FLAG_INVALID;
 
-	xpt_print_path(periph->path);
-	printf("lost device\n");
+	xpt_print(periph->path, "lost device\n");
 }
 
 static void
@@ -250,8 +229,7 @@
 
 	destroy_dev(softc->ses_dev);
 
-	xpt_print_path(periph->path);
-	printf("removing device entry\n");
+	xpt_print(periph->path, "removing device entry\n");
 	free(softc, M_SCSISES);
 }
 
@@ -311,7 +289,6 @@
 sesregister(struct cam_periph *periph, void *arg)
 {
 	struct ses_softc *softc;
-	struct ccb_setasync csa;
 	struct ccb_getdev *cgd;
 	char *tname;
 
@@ -365,21 +342,18 @@
 		return (CAM_REQ_CMP_ERR);
 	}
 
+	cam_periph_unlock(periph);
 	softc->ses_dev = make_dev(&ses_cdevsw, unit2minor(periph->unit_number),
 	    UID_ROOT, GID_OPERATOR, 0600, "%s%d",
 	    periph->periph_name, periph->unit_number);
+	cam_periph_lock(periph);
 	softc->ses_dev->si_drv1 = periph;
 
 	/*
 	 * Add an async callback so that we get
 	 * notified if this device goes away.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path, 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = AC_LOST_DEVICE;
-	csa.callback = sesasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(AC_LOST_DEVICE, sesasync, periph, periph->path);
 
 	switch (softc->ses_type) {
 	default:
@@ -411,25 +385,20 @@
 {
 	struct cam_periph *periph;
 	struct ses_softc *softc;
-	int error, s;
+	int error = 0;
 
-	s = splsoftcam();
 	periph = (struct cam_periph *)dev->si_drv1;
 	if (periph == NULL) {
-		splx(s);
 		return (ENXIO);
 	}
-	if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) {
-		splx(s);
-		return (error);
-	}
-	splx(s);
 
 	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
 		cam_periph_unlock(periph);
 		return (ENXIO);
 	}
 
+	cam_periph_lock(periph);
+
 	softc = (struct ses_softc *)periph->softc;
 
 	if (softc->ses_flags & SES_FLAG_INVALID) {
@@ -455,10 +424,10 @@
 	}
 
 out:
+	cam_periph_unlock(periph);
 	if (error) {
 		cam_periph_release(periph);
 	}
-	cam_periph_unlock(periph);
 	return (error);
 }
 
@@ -475,11 +444,9 @@
 	if (periph == NULL)
 		return (ENXIO);
 
-	softc = (struct ses_softc *)periph->softc;
-
-	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
-		return (error);
+	cam_periph_lock(periph);
 
+	softc = (struct ses_softc *)periph->softc;
 	softc->ses_flags &= ~SES_FLAG_OPEN;
 
 	cam_periph_unlock(periph);
@@ -491,13 +458,11 @@
 static void
 sesstart(struct cam_periph *p, union ccb *sccb)
 {
-	int s = splbio();
 	if (p->immediate_priority <= p->pinfo.priority) {
 		SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle);
 		p->immediate_priority = CAM_PRIORITY_NONE;
 		wakeup(&p->ccb_list);
 	}
-	splx(s);
 }
 
 static void
@@ -541,14 +506,17 @@
 
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering sesioctl\n"));
 
+	cam_periph_lock(periph);
 	ssc = (struct ses_softc *)periph->softc;
 
 	/*
 	 * Now check to see whether we're initialized or not.
 	 */
 	if ((ssc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
+		cam_periph_unlock(periph);
 		return (ENXIO);
 	}
+	cam_periph_lock(periph);
 
 	error = 0;
 
@@ -578,22 +546,34 @@
 		break;
 		
 	case SESIOC_GETOBJMAP:
+		/*
+		 * XXX Dropping the lock while copying multiple segments is
+		 * bogus.
+		 */
+		cam_periph_lock(periph);
 		for (uobj = addr, i = 0; i != ssc->ses_nobjects; i++, uobj++) {
 			obj.obj_id = i;
 			obj.subencid = ssc->ses_objmap[i].subenclosure;
 			obj.object_type = ssc->ses_objmap[i].enctype;
+			cam_periph_lock(periph);
 			error = copyout(&obj, uobj, sizeof (ses_object));
+			cam_periph_lock(periph);
 			if (error) {
 				break;
 			}
 		}
+		cam_periph_lock(periph);
 		break;
 
 	case SESIOC_GETENCSTAT:
+		cam_periph_lock(periph);
 		error = (*ssc->ses_vec.get_encstat)(ssc, 1);
-		if (error)
+		if (error) {
+			cam_periph_unlock(periph);
 			break;
+		}
 		tmp = ssc->ses_encstat & ~ENCI_SVALID;
+		cam_periph_unlock(periph);
 		error = copyout(&tmp, addr, sizeof (ses_encstat));
 		ssc->ses_encstat = tmp;
 		break;
@@ -602,7 +582,9 @@
 		error = copyin(addr, &tmp, sizeof (ses_encstat));
 		if (error)
 			break;
+		cam_periph_lock(periph);
 		error = (*ssc->ses_vec.set_encstat)(ssc, tmp, 1);
+		cam_periph_unlock(periph);
 		break;
 
 	case SESIOC_GETOBJSTAT:
@@ -613,7 +595,9 @@
 			error = EINVAL;
 			break;
 		}
+		cam_periph_lock(periph);
 		error = (*ssc->ses_vec.get_objstat)(ssc, &objs, 1);
+		cam_periph_unlock(periph);
 		if (error)
 			break;
 		error = copyout(&objs, addr, sizeof (ses_objstat));
@@ -632,7 +616,9 @@
 			error = EINVAL;
 			break;
 		}
+		cam_periph_lock(periph);
 		error = (*ssc->ses_vec.set_objstat)(ssc, &objs, 1);
+		cam_periph_unlock(periph);
 
 		/*
 		 * Always (for now) invalidate entry.
@@ -642,11 +628,15 @@
 
 	case SESIOC_INIT:
 
+		cam_periph_lock(periph);
 		error = (*ssc->ses_vec.init_enc)(ssc);
+		cam_periph_unlock(periph);
 		break;
 
 	default:
+		cam_periph_lock(periph);
 		error = cam_periph_ioctl(periph, cmd, arg_addr, seserror);
+		cam_periph_unlock(periph);
 		break;
 	}
 	return (error);
Index: scsi_low.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_low.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/scsi/scsi_low.c -L sys/cam/scsi/scsi_low.c -u -r1.1.1.1 -r1.2
--- sys/cam/scsi/scsi_low.c
+++ sys/cam/scsi/scsi_low.c
@@ -2,7 +2,7 @@
 /*	$NetBSD$	*/
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_low.c,v 1.24 2005/07/01 15:21:30 avatar Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_low.c,v 1.29 2007/06/17 05:55:54 scottl Exp $");
 
 #define	SCSI_LOW_STATICS
 #define	SCSI_LOW_DEBUG
@@ -1084,6 +1084,8 @@
 		break;
 
 	case XPT_SET_TRAN_SETTINGS: {
+		struct ccb_trans_settings_scsi *scsi;
+        	struct ccb_trans_settings_spi *spi;
 		struct ccb_trans_settings *cts;
 		u_int val;
 
@@ -1102,49 +1104,46 @@
 			lun = 0;
 
 		s = SCSI_LOW_SPLSCSI();
-		if ((cts->valid & (CCB_TRANS_BUS_WIDTH_VALID |
-				   CCB_TRANS_SYNC_RATE_VALID |
-				   CCB_TRANS_SYNC_OFFSET_VALID)) != 0)
+		scsi = &cts->proto_specific.scsi;
+		spi = &cts->xport_specific.spi;
+		if ((spi->valid & (CTS_SPI_VALID_BUS_WIDTH |
+				   CTS_SPI_VALID_SYNC_RATE |
+				   CTS_SPI_VALID_SYNC_OFFSET)) != 0)
 		{
-			if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
-				val = cts->bus_width;
+			if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
+				val = spi->bus_width;
 				if (val < ti->ti_width)
 					ti->ti_width = val;
 			}
-			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
-				val = cts->sync_period;
+			if (spi->valid & CTS_SPI_VALID_SYNC_RATE) {
+				val = spi->sync_period;
 				if (val == 0 || val > ti->ti_maxsynch.period)
 					ti->ti_maxsynch.period = val;
 			}
-			if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
-				val = cts->sync_offset;
+			if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
+				val = spi->sync_offset;
 				if (val < ti->ti_maxsynch.offset)
 					ti->ti_maxsynch.offset = val;
 			}
-
 			ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
 			scsi_low_calcf_target(ti);
 		}
 
-		if ((cts->valid & (CCB_TRANS_DISC_VALID |
-				   CCB_TRANS_TQ_VALID)) != 0)
-		{
+		if ((spi->valid & CTS_SPI_FLAGS_DISC_ENB) != 0 ||
+                    (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
+
 			li = scsi_low_alloc_li(ti, lun, 1);
-			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0)
-			{
-				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
-					li->li_quirks |= SCSI_LOW_DISK_DISC;
-				else
-					li->li_quirks &= ~SCSI_LOW_DISK_DISC;
-			}
-			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0)
-			{
-				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
-					li->li_quirks |= SCSI_LOW_DISK_QTAG;
-				else
-					li->li_quirks &= ~SCSI_LOW_DISK_QTAG;
+			if (spi->valid & CTS_SPI_FLAGS_DISC_ENB) {
+				li->li_quirks |= SCSI_LOW_DISK_DISC;
+			} else {
+				li->li_quirks &= ~SCSI_LOW_DISK_DISC;
 			}
 
+			if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
+				li->li_quirks |= SCSI_LOW_DISK_QTAG;
+			} else {
+				li->li_quirks &= ~SCSI_LOW_DISK_QTAG;
+			}
 			li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
 			scsi_low_calcf_target(ti);
 			scsi_low_calcf_lun(li);
@@ -1178,7 +1177,6 @@
 
 		s = SCSI_LOW_SPLSCSI();
 		li = scsi_low_alloc_li(ti, lun, 1);
-#ifdef CAM_NEW_TRAN_CODE
 		if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) {
 			struct ccb_trans_settings_scsi *scsi =
 				&cts->proto_specific.scsi;
@@ -1222,65 +1220,6 @@
 				scsi->valid = 0;
 		} else
 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
-#else
- 		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
- 		{
-#ifdef	SCSI_LOW_DIAGNOSTIC
-			if ((li->li_flags_valid & SCSI_LOW_LUN_FLAGS_DISK_VALID) == 0)
-			{
-				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
-				printf("%s: invalid GET_TRANS_USER_SETTINGS call\n",
-					slp->sl_xname);
-				goto settings_out;
-			}
-#endif	/* SCSI_LOW_DIAGNOSTIC */
-			diskflags = li->li_diskflags & li->li_cfgflags;
-			if ((diskflags & SCSI_LOW_DISK_DISC) != 0)
-				cts->flags |= CCB_TRANS_DISC_ENB;
-			else
-				cts->flags &= ~CCB_TRANS_DISC_ENB;
-			if ((diskflags & SCSI_LOW_DISK_QTAG) != 0)
-				cts->flags |= CCB_TRANS_TAG_ENB;
-			else
-				cts->flags &= ~CCB_TRANS_TAG_ENB;
-		}
-		else if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
-		{
-#ifdef	SCSI_LOW_DIAGNOSTIC
-			if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
-			{
-				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
-				printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n",
-					slp->sl_xname);
-				goto settings_out;
-			}
-#endif	/* SCSI_LOW_DIAGNOSTIC */
-			if ((li->li_flags & SCSI_LOW_DISC) != 0)
-				cts->flags |= CCB_TRANS_DISC_ENB;
-			else
-				cts->flags &= ~CCB_TRANS_DISC_ENB;
-			if ((li->li_flags & SCSI_LOW_QTAG) != 0)
-				cts->flags |= CCB_TRANS_TAG_ENB;
-			else
-				cts->flags &= ~CCB_TRANS_TAG_ENB;
-		}
-		else
-		{
-			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
-			goto settings_out;
-		}
-
-		cts->sync_period = ti->ti_maxsynch.period;
-		cts->sync_offset = ti->ti_maxsynch.offset;
-		cts->bus_width = ti->ti_width;
-
-		cts->valid = CCB_TRANS_SYNC_RATE_VALID
-			   | CCB_TRANS_SYNC_OFFSET_VALID
-			   | CCB_TRANS_BUS_WIDTH_VALID
-			   | CCB_TRANS_DISC_VALID
-			   | CCB_TRANS_TQ_VALID;
-		ccb->ccb_h.status = CAM_REQ_CMP;
-#endif
 settings_out:
 		splx(s);
 		xpt_done(ccb);
@@ -1361,12 +1300,10 @@
 		cpi->initiator_id = slp->sl_hostid;
 		cpi->bus_id = cam_sim_bus(sim);
 		cpi->base_transfer_speed = 3300;
-#ifdef CAM_NEW_TRAN_CODE
 		cpi->transport = XPORT_SPI;
 		cpi->transport_version = 2;
 		cpi->protocol = PROTO_SCSI;
 		cpi->protocol_version = SCSI_REV_2;
-#endif
 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
 		strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN);
 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
@@ -1406,7 +1343,7 @@
 	slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam,
 				scsi_low_poll_cam,
 				DEVPORT_DEVNAME(slp->sl_dev), slp,
-				DEVPORT_DEVUNIT(slp->sl_dev), 
+				DEVPORT_DEVUNIT(slp->sl_dev), &Giant,
 				slp->sl_openings, tagged_openings, devq);
 
 	if (slp->sl_si.sim == NULL) {
@@ -1414,7 +1351,7 @@
 	 	return ENODEV;
 	}
 
-	if (xpt_bus_register(slp->sl_si.sim, 0) != CAM_SUCCESS) {
+	if (xpt_bus_register(slp->sl_si.sim, NULL, 0) != CAM_SUCCESS) {
 		free(slp->sl_si.sim, M_SCSILOW);
 	 	return ENODEV;
 	}
--- /dev/null
+++ sys/cam/scsi/scsi_sg.h
@@ -0,0 +1,144 @@
+/*
+ * Structures and definitions for SCSI commands to the SG passthrough device.
+ *
+ * $FreeBSD: src/sys/cam/scsi/scsi_sg.h,v 1.2 2007/04/10 20:03:42 scottl Exp $
+ */
+
+#ifndef _SCSI_SG_H
+#define _SCSI_SG_H
+
+#define SGIOC	'"'
+#define SG_SET_TIMEOUT		_IO(SGIOC, 0x01)
+#define SG_GET_TIMEOUT		_IO(SGIOC, 0x02)
+#define SG_EMULATED_HOST	_IO(SGIOC, 0x03)
+#define SG_SET_TRANSFORM	_IO(SGIOC, 0x04)
+#define SG_GET_TRANSFORM	_IO(SGIOC, 0x05)
+#define SG_GET_COMMAND_Q	_IO(SGIOC, 0x70)
+#define SG_SET_COMMAND_Q	_IO(SGIOC, 0x71)
+#define SG_GET_RESERVED_SIZE	_IO(SGIOC, 0x72)
+#define SG_SET_RESERVED_SIZE	_IO(SGIOC, 0x75)
+#define SG_GET_SCSI_ID		_IO(SGIOC, 0x76)
+#define SG_SET_FORCE_LOW_DMA	_IO(SGIOC, 0x79)
+#define SG_GET_LOW_DMA		_IO(SGIOC, 0x7a)
+#define SG_SET_FORCE_PACK_ID	_IO(SGIOC, 0x7b)
+#define SG_GET_PACK_ID		_IO(SGIOC, 0x7c)
+#define SG_GET_NUM_WAITING	_IO(SGIOC, 0x7d)
+#define SG_SET_DEBUG		_IO(SGIOC, 0x7e)
+#define SG_GET_SG_TABLESIZE	_IO(SGIOC, 0x7f)
+#define SG_GET_VERSION_NUM	_IO(SGIOC, 0x82)
+#define SG_NEXT_CMD_LEN		_IO(SGIOC, 0x83)
+#define SG_SCSI_RESET		_IO(SGIOC, 0x84)
+#define SG_IO			_IO(SGIOC, 0x85)
+#define SG_GET_REQUEST_TABLE	_IO(SGIOC, 0x86)
+#define SG_SET_KEEP_ORPHAN	_IO(SGIOC, 0x87)
+#define SG_GET_KEEP_ORPHAN	_IO(SGIOC, 0x88)
+#define SG_GET_ACCESS_COUNT	_IO(SGIOC, 0x89)
+
+struct sg_io_hdr {
+	int		interface_id;
+	int		dxfer_direction;
+	u_char		cmd_len;
+	u_char		mx_sb_len;
+	u_short		iovec_count;
+	u_int		dxfer_len;
+	void		*dxferp;
+	u_char		*cmdp;
+	u_char		*sbp;
+	u_int		timeout;
+	u_int		flags;
+	int		pack_id;
+	void		*usr_ptr;
+	u_char		status;
+	u_char		masked_status;
+	u_char		msg_status;
+	u_char		sb_len_wr;
+	u_short		host_status;
+	u_short		driver_status;
+	int		resid;
+	u_int		duration;
+	u_int		info;
+};
+
+#define SG_DXFER_NONE		-1
+#define SG_DXFER_TO_DEV		-2
+#define SG_DXFER_FROM_DEV	-3
+#define SG_DXFER_TO_FROM_DEV	-4
+#define SG_DXFER_UNKNOWN	-5
+
+#define SG_MAX_SENSE 16
+struct sg_header {
+	int		pack_len;
+	int		reply_len;
+	int		pack_id;
+	int		result;
+	u_int		twelve_byte:1;
+	u_int		target_status:5;
+	u_int		host_status:8;
+	u_int		driver_status:8;
+	u_int		other_flags:10;
+	u_char		sense_buffer[SG_MAX_SENSE];
+};
+
+struct sg_scsi_id {
+	int		host_no;
+	int		channel;
+	int		scsi_id;
+	int		lun;
+	int		scsi_type;
+	short		h_cmd_per_lun;
+	short		d_queue_depth;
+	int		unused[2];
+};
+
+struct scsi_idlun {
+	uint32_t	dev_id;
+	uint32_t	host_unique_id;
+};
+
+/*
+ * Host codes
+ */
+#define DID_OK		0x00	/* OK */
+#define DID_NO_CONNECT	0x01	/* timeout during connect */
+#define DID_BUS_BUSY	0x02	/* timeout during command */
+#define DID_TIME_OUT	0x03	/* other timeout */
+#define DID_BAD_TARGET	0x04	/* bad target */
+#define DID_ABORT	0x05	/* abort */
+#define DID_PARITY	0x06	/* parity error */
+#define DID_ERROR	0x07	/* internal error */
+#define DID_RESET	0x08	/* reset by somebody */
+#define DID_BAD_INTR	0x09	/* unexpected interrupt */
+#define DID_PASSTHROUGH	0x0a	/* passthrough */
+#define DID_SOFT_ERROR	0x0b	/* low driver wants retry */
+#define DID_IMM_RETRY	0x0c	/* retry without decreasing retrycnt */
+
+/*
+ * Driver codes
+ */
+#define DRIVER_OK	0x00
+#define DRIVER_BUSY	0x01
+#define DRIVER_SOFT	0x02
+#define DRIVER_MEDIA	0x03
+#define DRIVER_ERROR	0x04
+
+#define DRIVER_INVALID	0x05
+#define DRIVER_TIMEOUT	0x06
+#define DRIVER_HARD	0x07
+#define DRIVER_SENSE	0x08
+
+#define SUGGEST_RETRY	0x10
+#define SUGGEST_ABORT	0x20
+#define SUGGEST_REMAP	0x30
+#define SUGGEST_DIE	0x40
+#define SUGGEST_SENSE	0x80
+#define SUGGEST_IS_OK	0xff
+
+#define DRIVER_MASK	0x0f
+#define SUGGEST_MASK	0xf0
+
+/* Other definitions */
+/* HZ isn't always available, so simulate it */
+#define SG_DEFAULT_HZ		1000
+#define SG_DEFAULT_TIMEOUT	(60*SG_DEFAULT_HZ)
+
+#endif /* !_SCSI_SG_H */
--- /dev/null
+++ sys/cam/scsi/scsi_sg.c
@@ -0,0 +1,983 @@
+/*-
+ * Copyright (c) 2007 Scott Long
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * scsi_sg peripheral driver.  This driver is meant to implement the Linux
+ * SG passthrough interface for SCSI.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_sg.c,v 1.9 2007/05/16 16:54:23 scottl Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/fcntl.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/devicestat.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_periph.h>
+#include <cam/cam_queue.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+#include <cam/scsi/scsi_sg.h>
+
+#include <compat/linux/linux_ioctl.h>
+
+typedef enum {
+	SG_FLAG_OPEN		= 0x01,
+	SG_FLAG_LOCKED		= 0x02,
+	SG_FLAG_INVALID		= 0x04
+} sg_flags;
+
+typedef enum {
+	SG_STATE_NORMAL
+} sg_state;
+
+typedef enum {
+	SG_RDWR_FREE,
+	SG_RDWR_INPROG,
+	SG_RDWR_DONE
+} sg_rdwr_state;
+
+typedef enum {
+	SG_CCB_RDWR_IO,
+	SG_CCB_WAITING
+} sg_ccb_types;
+
+#define ccb_type	ppriv_field0
+#define ccb_rdwr	ppriv_ptr1
+
+struct sg_rdwr {
+	TAILQ_ENTRY(sg_rdwr)	rdwr_link;
+	int			tag;
+	int			state;
+	int			buf_len;
+	char			*buf;
+	union ccb		*ccb;
+	union {
+		struct sg_header hdr;
+		struct sg_io_hdr io_hdr;
+	} hdr;
+};
+
+struct sg_softc {
+	sg_state		state;
+	sg_flags		flags;
+	struct devstat		*device_stats;
+	TAILQ_HEAD(, sg_rdwr)	rdwr_done;
+	struct cdev		*dev;
+	int			sg_timeout;
+	int			sg_user_timeout;
+	uint8_t			pd_type;
+	union ccb		saved_ccb;
+};
+
+static d_open_t		sgopen;
+static d_close_t	sgclose;
+static d_ioctl_t	sgioctl;
+static d_write_t	sgwrite;
+static d_read_t		sgread;
+
+static periph_init_t	sginit;
+static periph_ctor_t	sgregister;
+static periph_oninv_t	sgoninvalidate;
+static periph_dtor_t	sgcleanup;
+static periph_start_t	sgstart;
+static void		sgasync(void *callback_arg, uint32_t code,
+				struct cam_path *path, void *arg);
+static void		sgdone(struct cam_periph *periph, union ccb *done_ccb);
+static int		sgsendccb(struct cam_periph *periph, union ccb *ccb);
+static int		sgsendrdwr(struct cam_periph *periph, union ccb *ccb);
+static int		sgerror(union ccb *ccb, uint32_t cam_flags,
+				uint32_t sense_flags);
+static void		sg_scsiio_status(struct ccb_scsiio *csio,
+					 u_short *hoststat, u_short *drvstat);
+
+static int		scsi_group_len(u_char cmd);
+
+static struct periph_driver sgdriver =
+{
+	sginit, "sg",
+	TAILQ_HEAD_INITIALIZER(sgdriver.units), /* gen */ 0
+};
+PERIPHDRIVER_DECLARE(sg, sgdriver);
+
+static struct cdevsw sg_cdevsw = {
+	.d_version =	D_VERSION,
+	.d_flags =	D_NEEDGIANT,
+	.d_open =	sgopen,
+	.d_close =	sgclose,
+	.d_ioctl =	sgioctl,
+	.d_write =	sgwrite,
+	.d_read =	sgread,
+	.d_name =	"sg",
+};
+
+static int sg_version = 30125;
+
+static void
+sginit(void)
+{
+	cam_status status;
+
+	/*
+	 * Install a global async callback.  This callback will receive aync
+	 * callbacks like "new device found".
+	 */
+	status = xpt_register_async(AC_FOUND_DEVICE, sgasync, NULL, NULL);
+
+	if (status != CAM_REQ_CMP) {
+		printf("sg: Failed to attach master async callbac "
+			"due to status 0x%x!\n", status);
+	}
+}
+
+static void
+sgoninvalidate(struct cam_periph *periph)
+{
+	struct sg_softc *softc;
+
+	softc = (struct sg_softc *)periph->softc;
+
+	/*
+	 * Deregister any async callbacks.
+	 */
+	xpt_register_async(0, sgasync, periph, periph->path);
+
+	softc->flags |= SG_FLAG_INVALID;
+
+	/*
+	 * XXX Return all queued I/O with ENXIO.
+	 * XXX Handle any transactions queued to the card
+	 *     with XPT_ABORT_CCB.
+	 */
+
+	if (bootverbose) {
+		xpt_print(periph->path, "lost device\n");
+	}
+}
+
+static void
+sgcleanup(struct cam_periph *periph)
+{
+	struct sg_softc *softc;
+
+	softc = (struct sg_softc *)periph->softc;
+	devstat_remove_entry(softc->device_stats);
+	destroy_dev(softc->dev);
+	if (bootverbose) {
+		xpt_print(periph->path, "removing device entry\n");
+	}
+	free(softc, M_DEVBUF);
+}
+
+static void
+sgasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
+{
+	struct cam_periph *periph;
+
+	periph = (struct cam_periph *)callback_arg;
+
+	switch (code) {
+	case AC_FOUND_DEVICE:
+	{
+		struct ccb_getdev *cgd;
+		cam_status status;
+
+		cgd = (struct ccb_getdev *)arg;
+		if (cgd == NULL)
+			break;
+
+		/*
+		 * Allocate a peripheral instance for this device and
+		 * start the probe process.
+		 */
+		status = cam_periph_alloc(sgregister, sgoninvalidate,
+					  sgcleanup, sgstart, "sg",
+					  CAM_PERIPH_BIO, cgd->ccb_h.path,
+					  sgasync, AC_FOUND_DEVICE, cgd);
+		if ((status != CAM_REQ_CMP) && (status != CAM_REQ_INPROG)) {
+			const struct cam_status_entry *entry;
+
+			entry = cam_fetch_status_entry(status);
+			printf("sgasync: Unable to attach new device "
+				"due to status %#x: %s\n", status, entry ?
+				entry->status_text : "Unknown");
+		}
+		break;
+	}
+	default:
+		cam_periph_async(periph, code, path, arg);
+		break;
+	}
+}
+
+static cam_status
+sgregister(struct cam_periph *periph, void *arg)
+{
+	struct sg_softc *softc;
+	struct ccb_getdev *cgd;
+	int no_tags;
+
+	cgd = (struct ccb_getdev *)arg;
+	if (periph == NULL) {
+		printf("sgregister: periph was NULL!!\n");
+		return (CAM_REQ_CMP_ERR);
+	}
+
+	if (cgd == NULL) {
+		printf("sgregister: no getdev CCB, can't register device\n");
+		return (CAM_REQ_CMP_ERR);
+	}
+
+	softc = malloc(sizeof(*softc), M_DEVBUF, M_ZERO | M_NOWAIT);
+	if (softc == NULL) {
+		printf("sgregister: Unable to allocate softc\n");
+		return (CAM_REQ_CMP_ERR);
+	}
+
+	softc->state = SG_STATE_NORMAL;
+	softc->pd_type = SID_TYPE(&cgd->inq_data);
+	softc->sg_timeout = SG_DEFAULT_TIMEOUT / SG_DEFAULT_HZ * hz;
+	softc->sg_user_timeout = SG_DEFAULT_TIMEOUT;
+	TAILQ_INIT(&softc->rdwr_done);
+	periph->softc = softc;
+
+	/*
+	 * We pass in 0 for all blocksize, since we don't know what the
+	 * blocksize of the device is, if it even has a blocksize.
+	 */
+	cam_periph_unlock(periph);
+	no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0;
+	softc->device_stats = devstat_new_entry("sg",
+			unit2minor(periph->unit_number), 0,
+			DEVSTAT_NO_BLOCKSIZE
+			| (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0),
+			softc->pd_type |
+			DEVSTAT_TYPE_IF_SCSI |
+			DEVSTAT_TYPE_PASS,
+			DEVSTAT_PRIORITY_PASS);
+
+	/* Register the device */
+	softc->dev = make_dev(&sg_cdevsw, unit2minor(periph->unit_number),
+			      UID_ROOT, GID_OPERATOR, 0600, "%s%d",
+			      periph->periph_name, periph->unit_number);
+	(void)make_dev_alias(softc->dev, "sg%c", 'a' + periph->unit_number);
+	cam_periph_lock(periph);
+	softc->dev->si_drv1 = periph;
+
+	/*
+	 * Add as async callback so that we get
+	 * notified if this device goes away.
+	 */
+	xpt_register_async(AC_LOST_DEVICE, sgasync, periph, periph->path);
+
+	if (bootverbose)
+		xpt_announce_periph(periph, NULL);
+
+	return (CAM_REQ_CMP);
+}
+
+static void
+sgstart(struct cam_periph *periph, union ccb *start_ccb)
+{
+	struct sg_softc *softc;
+
+	softc = (struct sg_softc *)periph->softc;
+
+	switch (softc->state) {
+	case SG_STATE_NORMAL:
+		start_ccb->ccb_h.ccb_type = SG_CCB_WAITING;
+		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
+				  periph_links.sle);
+		periph->immediate_priority = CAM_PRIORITY_NONE;
+		wakeup(&periph->ccb_list);
+		break;
+	}
+}
+
+static void
+sgdone(struct cam_periph *periph, union ccb *done_ccb)
+{
+	struct sg_softc *softc;
+	struct ccb_scsiio *csio;
+
+	softc = (struct sg_softc *)periph->softc;
+	csio = &done_ccb->csio;
+	switch (csio->ccb_h.ccb_type) {
+	case SG_CCB_WAITING:
+		/* Caller will release the CCB */
+		wakeup(&done_ccb->ccb_h.cbfcnp);
+		return;
+	case SG_CCB_RDWR_IO:
+	{
+		struct sg_rdwr *rdwr;
+		int state;
+
+		devstat_end_transaction(softc->device_stats,
+					csio->dxfer_len,
+					csio->tag_action & 0xf,
+					((csio->ccb_h.flags & CAM_DIR_MASK) ==
+					CAM_DIR_NONE) ? DEVSTAT_NO_DATA :
+					(csio->ccb_h.flags & CAM_DIR_OUT) ?
+					DEVSTAT_WRITE : DEVSTAT_READ,
+					NULL, NULL);
+
+		rdwr = done_ccb->ccb_h.ccb_rdwr;
+		state = rdwr->state;
+		rdwr->state = SG_RDWR_DONE;
+		wakeup(rdwr);
+		break;
+	}
+	default:
+		panic("unknown sg CCB type");
+	}
+}
+
+static int
+sgopen(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+	struct cam_periph *periph;
+	struct sg_softc *softc;
+	int error = 0;
+
+	periph = (struct cam_periph *)dev->si_drv1;
+	if (periph == NULL)
+		return (ENXIO);
+
+	/*
+	 * Don't allow access when we're running at a high securelevel.
+	 */
+	error = securelevel_gt(td->td_ucred, 1);
+	if (error)
+		return (error);
+
+	cam_periph_lock(periph);
+
+	softc = (struct sg_softc *)periph->softc;
+	if (softc->flags & SG_FLAG_INVALID) {
+		cam_periph_unlock(periph);
+		return (ENXIO);
+	}
+
+	if ((softc->flags & SG_FLAG_OPEN) == 0) {
+		softc->flags |= SG_FLAG_OPEN;
+	} else {
+		/* Device closes aren't symmetrical, fix up the refcount. */
+		cam_periph_release(periph);
+	}
+
+	cam_periph_unlock(periph);
+
+	return (error);
+}
+
+static int
+sgclose(struct cdev *dev, int flag, int fmt, struct thread *td)
+{
+	struct cam_periph *periph;
+	struct sg_softc *softc;
+
+	periph = (struct cam_periph *)dev->si_drv1;
+	if (periph == NULL)
+		return (ENXIO);
+
+	cam_periph_lock(periph);
+
+	softc = (struct sg_softc *)periph->softc;
+	softc->flags &= ~SG_FLAG_OPEN;
+
+	cam_periph_unlock(periph);
+	cam_periph_release(periph);
+
+	return (0);
+}
+
+static int
+sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
+{
+	union ccb *ccb;
+	struct ccb_scsiio *csio;
+	struct cam_periph *periph;
+	struct sg_softc *softc;
+	struct sg_io_hdr req;
+	int dir, error;
+
+	periph = (struct cam_periph *)dev->si_drv1;
+	if (periph == NULL)
+		return (ENXIO);
+
+	cam_periph_lock(periph);
+
+	softc = (struct sg_softc *)periph->softc;
+	error = 0;
+
+	switch (cmd) {
+	case LINUX_SCSI_GET_BUS_NUMBER: {
+		int busno;
+
+		busno = xpt_path_path_id(periph->path);
+		error = copyout(&busno, arg, sizeof(busno));
+		break;
+	}
+	case LINUX_SCSI_GET_IDLUN: {
+		struct scsi_idlun idlun;
+		struct cam_sim *sim;
+
+		idlun.dev_id = xpt_path_target_id(periph->path);
+		sim = xpt_path_sim(periph->path);
+		idlun.host_unique_id = sim->unit_number;
+		error = copyout(&idlun, arg, sizeof(idlun));
+		break;
+	}
+	case SG_GET_VERSION_NUM:
+	case LINUX_SG_GET_VERSION_NUM:
+		error = copyout(&sg_version, arg, sizeof(sg_version));
+		break;
+	case SG_SET_TIMEOUT:
+	case LINUX_SG_SET_TIMEOUT: {
+		u_int user_timeout;
+
+		error = copyin(arg, &user_timeout, sizeof(u_int));
+		if (error == 0) {
+			softc->sg_user_timeout = user_timeout;
+			softc->sg_timeout = user_timeout / SG_DEFAULT_HZ * hz;
+		}
+		break;
+	}
+	case SG_GET_TIMEOUT:
+	case LINUX_SG_GET_TIMEOUT:
+		/*
+		 * The value is returned directly to the syscall.
+		 */
+		td->td_retval[0] = softc->sg_user_timeout;
+		error = 0;
+		break;
+	case SG_IO:
+	case LINUX_SG_IO:
+		error = copyin(arg, &req, sizeof(req));
+		if (error)
+			break;
+
+		if (req.cmd_len > IOCDBLEN) {
+			error = EINVAL;
+			break;
+		}
+
+		if (req.iovec_count != 0) {
+			error = EOPNOTSUPP;
+			break;
+		}
+
+		ccb = cam_periph_getccb(periph, /*priority*/5);
+		csio = &ccb->csio;
+
+		error = copyin(req.cmdp, &csio->cdb_io.cdb_bytes,
+		    req.cmd_len);
+		if (error) {
+			xpt_release_ccb(ccb);
+			break;
+		}
+
+		switch(req.dxfer_direction) {
+		case SG_DXFER_TO_DEV:
+			dir = CAM_DIR_OUT;
+			break;
+		case SG_DXFER_FROM_DEV:
+			dir = CAM_DIR_IN;
+			break;
+		case SG_DXFER_TO_FROM_DEV:
+			dir = CAM_DIR_IN | CAM_DIR_OUT;
+			break;
+		case SG_DXFER_NONE:
+		default:
+			dir = CAM_DIR_NONE;
+			break;
+		}
+
+		cam_fill_csio(csio,
+			      /*retries*/1,
+			      sgdone,
+			      dir|CAM_DEV_QFRZDIS,
+			      MSG_SIMPLE_Q_TAG,
+			      req.dxferp,
+			      req.dxfer_len,
+			      req.mx_sb_len,
+			      req.cmd_len,
+			      req.timeout);
+
+		error = sgsendccb(periph, ccb);
+		if (error) {
+			req.host_status = DID_ERROR;
+			req.driver_status = DRIVER_INVALID;
+			xpt_release_ccb(ccb);
+			break;
+		}
+
+		req.status = csio->scsi_status;
+		req.masked_status = (csio->scsi_status >> 1) & 0x7f;
+		sg_scsiio_status(csio, &req.host_status, &req.driver_status);
+		req.resid = csio->resid;
+		req.duration = csio->ccb_h.timeout;
+		req.info = 0;
+
+		error = copyout(&req, arg, sizeof(req));
+		if ((error == 0) && (csio->ccb_h.status & CAM_AUTOSNS_VALID)
+		    && (req.sbp != NULL)) {
+			req.sb_len_wr = req.mx_sb_len - csio->sense_resid;
+			error = copyout(&csio->sense_data, req.sbp,
+					req.sb_len_wr);
+		}
+
+		xpt_release_ccb(ccb);
+		break;
+		
+	case SG_GET_RESERVED_SIZE:
+	case LINUX_SG_GET_RESERVED_SIZE: {
+		int size = 32768;
+
+		error = copyout(&size, arg, sizeof(size));
+		break;
+	}
+
+	case SG_GET_SCSI_ID:
+	case LINUX_SG_GET_SCSI_ID:
+	{
+		struct sg_scsi_id id;
+
+		id.host_no = 0; /* XXX */
+		id.channel = xpt_path_path_id(periph->path);
+		id.scsi_id = xpt_path_target_id(periph->path);
+		id.lun = xpt_path_lun_id(periph->path);
+		id.scsi_type = softc->pd_type;
+		id.h_cmd_per_lun = 1;
+		id.d_queue_depth = 1;
+		id.unused[0] = 0;
+		id.unused[1] = 0;
+
+		error = copyout(&id, arg, sizeof(id));
+		break;
+	}
+
+	case SG_EMULATED_HOST:
+	case SG_SET_TRANSFORM:
+	case SG_GET_TRANSFORM:
+	case SG_GET_NUM_WAITING:
+	case SG_SCSI_RESET:
+	case SG_GET_REQUEST_TABLE:
+	case SG_SET_KEEP_ORPHAN:
+	case SG_GET_KEEP_ORPHAN:
+	case SG_GET_ACCESS_COUNT:
+	case SG_SET_FORCE_LOW_DMA:
+	case SG_GET_LOW_DMA:
+	case SG_GET_SG_TABLESIZE:
+	case SG_SET_FORCE_PACK_ID:
+	case SG_GET_PACK_ID:
+	case SG_SET_RESERVED_SIZE:
+	case SG_GET_COMMAND_Q:
+	case SG_SET_COMMAND_Q:
+	case SG_SET_DEBUG:
+	case SG_NEXT_CMD_LEN:
+	case LINUX_SG_EMULATED_HOST:
+	case LINUX_SG_SET_TRANSFORM:
+	case LINUX_SG_GET_TRANSFORM:
+	case LINUX_SG_GET_NUM_WAITING:
+	case LINUX_SG_SCSI_RESET:
+	case LINUX_SG_GET_REQUEST_TABLE:
+	case LINUX_SG_SET_KEEP_ORPHAN:
+	case LINUX_SG_GET_KEEP_ORPHAN:
+	case LINUX_SG_GET_ACCESS_COUNT:
+	case LINUX_SG_SET_FORCE_LOW_DMA:
+	case LINUX_SG_GET_LOW_DMA:
+	case LINUX_SG_GET_SG_TABLESIZE:
+	case LINUX_SG_SET_FORCE_PACK_ID:
+	case LINUX_SG_GET_PACK_ID:
+	case LINUX_SG_SET_RESERVED_SIZE:
+	case LINUX_SG_GET_COMMAND_Q:
+	case LINUX_SG_SET_COMMAND_Q:
+	case LINUX_SG_SET_DEBUG:
+	case LINUX_SG_NEXT_CMD_LEN:
+	default:
+#ifdef CAMDEBUG
+		printf("sgioctl: rejecting cmd 0x%lx\n", cmd);
+#endif
+		error = ENODEV;
+		break;
+	}
+
+	cam_periph_unlock(periph);
+	return (error);
+}
+
+static int
+sgwrite(struct cdev *dev, struct uio *uio, int ioflag)
+{
+	union ccb *ccb;
+	struct cam_periph *periph;
+	struct ccb_scsiio *csio;
+	struct sg_softc *sc;
+	struct sg_header *hdr;
+	struct sg_rdwr *rdwr;
+	u_char cdb_cmd;
+	char *buf;
+	int error = 0, cdb_len, buf_len, dir;
+
+	periph = dev->si_drv1;
+	rdwr = malloc(sizeof(*rdwr), M_DEVBUF, M_WAITOK | M_ZERO);
+	hdr = &rdwr->hdr.hdr;
+
+	/* Copy in the header block and sanity check it */
+	if (uio->uio_resid < sizeof(*hdr)) {
+		error = EINVAL;
+		goto out_hdr;
+	}
+	error = uiomove(hdr, sizeof(*hdr), uio);
+	if (error)
+		goto out_hdr;
+
+	ccb = xpt_alloc_ccb();
+	if (ccb == NULL) {
+		error = ENOMEM;
+		goto out_hdr;
+	}
+	csio = &ccb->csio;
+
+	/*
+	 * Copy in the CDB block.  The designers of the interface didn't
+	 * bother to provide a size for this in the header, so we have to
+	 * figure it out ourselves.
+	 */
+	if (uio->uio_resid < 1)
+		goto out_ccb;
+	error = uiomove(&cdb_cmd, 1, uio);
+	if (error)
+		goto out_ccb;
+	if (hdr->twelve_byte)
+		cdb_len = 12;
+	else
+		cdb_len = scsi_group_len(cdb_cmd);
+	/*
+	 * We've already read the first byte of the CDB and advanced the uio
+	 * pointer.  Just read the rest.
+	 */
+	csio->cdb_io.cdb_bytes[0] = cdb_cmd;
+	error = uiomove(&csio->cdb_io.cdb_bytes[1], cdb_len - 1, uio);
+	if (error)
+		goto out_ccb;
+
+	/*
+	 * Now set up the data block.  Again, the designers didn't bother
+	 * to make this reliable.
+	 */
+	buf_len = uio->uio_resid;
+	if (buf_len != 0) {
+		buf = malloc(buf_len, M_DEVBUF, M_WAITOK | M_ZERO);
+		error = uiomove(buf, buf_len, uio);
+		if (error)
+			goto out_buf;
+		dir = CAM_DIR_OUT;
+	} else if (hdr->reply_len != 0) {
+		buf = malloc(hdr->reply_len, M_DEVBUF, M_WAITOK | M_ZERO);
+		buf_len = hdr->reply_len;
+		dir = CAM_DIR_IN;
+	} else {
+		buf = NULL;
+		buf_len = 0;
+		dir = CAM_DIR_NONE;
+	}
+
+	cam_periph_lock(periph);
+	sc = periph->softc;
+	xpt_setup_ccb(&ccb->ccb_h, periph->path, /*priority*/5);
+	cam_fill_csio(csio,
+		      /*retries*/1,
+		      sgdone,
+		      dir|CAM_DEV_QFRZDIS,
+		      MSG_SIMPLE_Q_TAG,
+		      buf,
+		      buf_len,
+		      SG_MAX_SENSE,
+		      cdb_len,
+		      sc->sg_timeout);
+
+	/*
+	 * Send off the command and hope that it works. This path does not
+	 * go through sgstart because the I/O is supposed to be asynchronous.
+	 */
+	rdwr->buf = buf;
+	rdwr->buf_len = buf_len;
+	rdwr->tag = hdr->pack_id;
+	rdwr->ccb = ccb;
+	rdwr->state = SG_RDWR_INPROG;
+	ccb->ccb_h.ccb_rdwr = rdwr;
+	ccb->ccb_h.ccb_type = SG_CCB_RDWR_IO;
+	TAILQ_INSERT_TAIL(&sc->rdwr_done, rdwr, rdwr_link);
+	error = sgsendrdwr(periph, ccb);
+	cam_periph_unlock(periph);
+	return (error);
+
+out_buf:
+	free(buf, M_DEVBUF);
+out_ccb:
+	xpt_free_ccb(ccb);
+out_hdr:
+	free(rdwr, M_DEVBUF);
+	return (error);
+}
+
+static int
+sgread(struct cdev *dev, struct uio *uio, int ioflag)
+{
+	struct ccb_scsiio *csio;
+	struct cam_periph *periph;
+	struct sg_softc *sc;
+	struct sg_header *hdr;
+	struct sg_rdwr *rdwr;
+	u_short hstat, dstat;
+	int error, pack_len, reply_len, pack_id;
+
+	periph = dev->si_drv1;
+
+	/* XXX The pack len field needs to be updated and written out instead
+	 * of discarded.  Not sure how to do that.
+	 */
+	uio->uio_rw = UIO_WRITE;
+	if ((error = uiomove(&pack_len, 4, uio)) != 0)
+		return (error);
+	if ((error = uiomove(&reply_len, 4, uio)) != 0)
+		return (error);
+	if ((error = uiomove(&pack_id, 4, uio)) != 0)
+		return (error);
+	uio->uio_rw = UIO_READ;
+
+	cam_periph_lock(periph);
+	sc = periph->softc;
+search:
+	TAILQ_FOREACH(rdwr, &sc->rdwr_done, rdwr_link) {
+		if (rdwr->tag == pack_id)
+			break;
+	}
+	if ((rdwr == NULL) || (rdwr->state != SG_RDWR_DONE)) {
+		if (msleep(rdwr, periph->sim->mtx, PCATCH, "sgread", 0) == ERESTART)
+			return (EAGAIN);
+		goto search;
+	}
+	TAILQ_REMOVE(&sc->rdwr_done, rdwr, rdwr_link);
+	cam_periph_unlock(periph);
+
+	hdr = &rdwr->hdr.hdr;
+	csio = &rdwr->ccb->csio;
+	sg_scsiio_status(csio, &hstat, &dstat);
+	hdr->host_status = hstat;
+	hdr->driver_status = dstat;
+	hdr->target_status = csio->scsi_status >> 1;
+
+	switch (hstat) {
+	case DID_OK:
+	case DID_PASSTHROUGH:
+	case DID_SOFT_ERROR:
+		hdr->result = 0;
+		break;
+	case DID_NO_CONNECT:
+	case DID_BUS_BUSY:
+	case DID_TIME_OUT:
+		hdr->result = EBUSY;
+		break;
+	case DID_BAD_TARGET:
+	case DID_ABORT:
+	case DID_PARITY:
+	case DID_RESET:
+	case DID_BAD_INTR:
+	case DID_ERROR:
+	default:
+		hdr->result = EIO;
+		break;
+	}
+
+	if (dstat == DRIVER_SENSE) {
+		bcopy(&csio->sense_data, hdr->sense_buffer,
+		      min(csio->sense_len, SG_MAX_SENSE));
+#ifdef CAMDEBUG
+		scsi_sense_print(csio);
+#endif
+	}
+
+	error = uiomove(&hdr->result, sizeof(*hdr) -
+			offsetof(struct sg_header, result), uio);
+	if ((error == 0) && (hdr->result == 0))
+		error = uiomove(rdwr->buf, rdwr->buf_len, uio);
+
+	cam_periph_lock(periph);
+	xpt_free_ccb(rdwr->ccb);
+	cam_periph_unlock(periph);
+	free(rdwr->buf, M_DEVBUF);
+	free(rdwr, M_DEVBUF);
+	return (error);
+}
+
+static int
+sgsendccb(struct cam_periph *periph, union ccb *ccb)
+{
+	struct sg_softc *softc;
+	struct cam_periph_map_info mapinfo;
+	int error, need_unmap = 0;
+
+	softc = periph->softc;
+	if (((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
+	    && (ccb->csio.data_ptr != NULL)) {
+		bzero(&mapinfo, sizeof(mapinfo));
+
+		/*
+		 * cam_periph_mapmem calls into proc and vm functions that can
+		 * sleep as well as trigger I/O, so we can't hold the lock.
+		 * Dropping it here is reasonably safe.
+		 */
+		cam_periph_unlock(periph);
+		error = cam_periph_mapmem(ccb, &mapinfo);
+		cam_periph_lock(periph);
+		if (error)
+			return (error);
+		need_unmap = 1;
+	}
+
+	error = cam_periph_runccb(ccb,
+				  sgerror,
+				  CAM_RETRY_SELTO,
+				  SF_RETRY_UA,
+				  softc->device_stats);
+
+	if (need_unmap)
+		cam_periph_unmapmem(ccb, &mapinfo);
+
+	return (error);
+}
+
+static int
+sgsendrdwr(struct cam_periph *periph, union ccb *ccb)
+{
+	struct sg_softc *softc;
+
+	softc = periph->softc;
+	devstat_start_transaction(softc->device_stats, NULL);
+	xpt_action(ccb);
+	return (0);
+}
+
+static int
+sgerror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
+{
+	struct cam_periph *periph;
+	struct sg_softc *softc;
+
+	periph = xpt_path_periph(ccb->ccb_h.path);
+	softc = (struct sg_softc *)periph->softc;
+
+	return (cam_periph_error(ccb, cam_flags, sense_flags,
+				 &softc->saved_ccb));
+}
+
+static void
+sg_scsiio_status(struct ccb_scsiio *csio, u_short *hoststat, u_short *drvstat)
+{
+	int status;
+
+	status = csio->ccb_h.status;
+
+	switch (status & CAM_STATUS_MASK) {
+	case CAM_REQ_CMP:
+		*hoststat = DID_OK;
+		*drvstat = 0;
+		break;
+	case CAM_REQ_CMP_ERR:
+		*hoststat = DID_ERROR;
+		*drvstat = 0;
+		break;
+	case CAM_REQ_ABORTED:
+		*hoststat = DID_ABORT;
+		*drvstat = 0;
+		break;
+	case CAM_REQ_INVALID:
+		*hoststat = DID_ERROR;
+		*drvstat = DRIVER_INVALID;
+		break;
+	case CAM_DEV_NOT_THERE:
+		*hoststat = DID_BAD_TARGET;
+		*drvstat = 0;
+	case CAM_SEL_TIMEOUT:
+		*hoststat = DID_NO_CONNECT;
+		*drvstat = 0;
+		break;
+	case CAM_CMD_TIMEOUT:
+		*hoststat = DID_TIME_OUT;
+		*drvstat = 0;
+		break;
+	case CAM_SCSI_STATUS_ERROR:
+		*hoststat = DID_ERROR;
+		*drvstat = 0;
+	case CAM_SCSI_BUS_RESET:
+		*hoststat = DID_RESET;
+		*drvstat = 0;
+		break;
+	case CAM_UNCOR_PARITY:
+		*hoststat = DID_PARITY;
+		*drvstat = 0;
+		break;
+	case CAM_SCSI_BUSY:
+		*hoststat = DID_BUS_BUSY;
+		*drvstat = 0;
+	default:
+		*hoststat = DID_ERROR;
+		*drvstat = DRIVER_ERROR;
+	}
+
+	if (status & CAM_AUTOSNS_VALID)
+		*drvstat = DRIVER_SENSE;
+}
+
+static int
+scsi_group_len(u_char cmd)
+{
+	int len[] = {6, 10, 10, 12, 12, 12, 10, 10};
+	int group;
+
+	group = (cmd >> 5) & 0x7;
+	return (len[group]);
+}
+
Index: scsi_ses.h
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_ses.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/cam/scsi/scsi_ses.h -L sys/cam/scsi/scsi_ses.h -u -r1.2 -r1.3
--- sys/cam/scsi/scsi_ses.h
+++ sys/cam/scsi/scsi_ses.h
@@ -1,4 +1,4 @@
-/* $FreeBSD: src/sys/cam/scsi/scsi_ses.h,v 1.3.2.1 2006/03/09 21:43:10 mjacob Exp $ */
+/* $FreeBSD: src/sys/cam/scsi/scsi_ses.h,v 1.4 2006/01/18 08:37:27 mjacob Exp $ */
 /*-
  * Copyright (c) 2000 by Matthew Jacob
  * All rights reserved.
Index: scsi_sa.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_sa.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -L sys/cam/scsi/scsi_sa.c -L sys/cam/scsi/scsi_sa.c -u -r1.1.1.2 -r1.2
--- sys/cam/scsi/scsi_sa.c
+++ sys/cam/scsi/scsi_sa.c
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_sa.c,v 1.105.2.1 2006/01/26 04:57:04 mjacob Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_sa.c,v 1.113 2007/06/16 18:20:29 scottl Exp $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -447,37 +447,33 @@
 	struct sa_softc *softc;
 	int unit;
 	int error;
-	int s;
 
 	unit = SAUNIT(dev);
 
-	s = splsoftcam();
 	periph = (struct cam_periph *)dev->si_drv1;
-	if (periph == NULL) {
-		(void) splx(s);
-		return (ENXIO);	
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+		return (ENXIO);
 	}
+
+	cam_periph_lock(periph);
+
 	softc = (struct sa_softc *)periph->softc;
-	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
-		splx(s);
-		return (error);
-	}
-	splx(s);
 
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO,
 	    ("saopen(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
 
-	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
-		cam_periph_unlock(periph);
-		return (ENXIO);
-	}
-
 	if (SA_IS_CTRL(dev)) {
 		softc->ctrl_mode = 1;
 		cam_periph_unlock(periph);
 		return (0);
 	}
 
+	if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) {
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
+		return (error);
+	}
+
 	if (softc->flags & SA_FLAG_OPEN) {
 		error = EBUSY;
 	} else if (softc->flags & SA_FLAG_INVALID) {
@@ -499,17 +495,23 @@
 		if (error && (flags & O_NONBLOCK)) {
 			softc->flags |= SA_FLAG_OPEN;
 			softc->open_pending_mount = 1;
+			cam_periph_unhold(periph);
 			cam_periph_unlock(periph);
 			return (0);
 		}
 	}
 
 	if (error) {
+		cam_periph_unhold(periph);
+		cam_periph_unlock(periph);
 		cam_periph_release(periph);
-	} else {
-		saprevent(periph, PR_PREVENT);
-		softc->flags |= SA_FLAG_OPEN;
+		return (error);
 	}
+
+	saprevent(periph, PR_PREVENT);
+	softc->flags |= SA_FLAG_OPEN;
+
+	cam_periph_unhold(periph);
 	cam_periph_unlock(periph);
 	return (error);
 }
@@ -528,32 +530,35 @@
 	if (periph == NULL)
 		return (ENXIO);	
 
+	cam_periph_lock(periph);
+
 	softc = (struct sa_softc *)periph->softc;
 
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO,
 	    ("saclose(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
 
 
-	if ((error = cam_periph_lock(periph, PRIBIO)) != 0) {
-		return (error);
-	}
-
 	softc->open_rdonly = 0; 
 	if (SA_IS_CTRL(dev)) {
 		softc->ctrl_mode = 0;
-		cam_periph_release(periph);
 		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return (0);
 	}
 
 	if (softc->open_pending_mount) {
 		softc->flags &= ~SA_FLAG_OPEN;
 		softc->open_pending_mount = 0; 
-		cam_periph_release(periph);
 		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return (0);
 	}
 
+	if ((error = cam_periph_hold(periph, PRIBIO)) != 0) {
+		cam_periph_unlock(periph);
+		return (error);
+	}
+
 	/*
 	 * Were we writing the tape?
 	 */
@@ -566,8 +571,8 @@
 	 */
 	error = sacheckeod(periph);
 	if (error) {
-		xpt_print_path(periph->path);
-		printf("failed to write terminating filemark(s)\n");
+		xpt_print(periph->path,
+		    "failed to write terminating filemark(s)\n");
 		softc->flags |= SA_FLAG_TAPE_FROZEN;
 	}
 
@@ -622,19 +627,18 @@
 		if (error == 0 && writing && (softc->quirks & SA_QUIRK_2FM)) {
 			tmp = saspace(periph, -1, SS_FILEMARKS);
 			if (tmp) {
-				xpt_print_path(periph->path);
-				printf("unable to backspace over one of double"
-				   " filemarks at end of tape\n");
-				xpt_print_path(periph->path);
-				printf("it is possible that this device"
-				   " needs a SA_QUIRK_1FM quirk set for it\n");
+				xpt_print(periph->path, "unable to backspace "
+				    "over one of double filemarks at end of "
+				    "tape\n");
+				xpt_print(periph->path, "it is possible that "
+				    "this device needs a SA_QUIRK_1FM quirk set"
+				    "for it\n");
 				softc->flags |= SA_FLAG_TAPE_FROZEN;
 			}
 		}
 		break;
 	default:
-		xpt_print_path(periph->path);
-		panic("unknown mode 0x%x in saclose", mode);
+		xpt_print(periph->path, "unknown mode 0x%x in saclose\n", mode);
 		/* NOTREACHED */
 		break;
 	}
@@ -654,15 +658,15 @@
 	 * Inform users if tape state if frozen....
 	 */
 	if (softc->flags & SA_FLAG_TAPE_FROZEN) {
-		xpt_print_path(periph->path);
-		printf("tape is now frozen- use an OFFLINE, REWIND or MTEOM "
-		    "command to clear this state.\n");
+		xpt_print(periph->path, "tape is now frozen- use an OFFLINE, "
+		    "REWIND or MTEOM command to clear this state.\n");
 	}
 	
 	/* release the device if it is no longer mounted */
 	if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0)
 		sareservereleaseunit(periph, FALSE);
 
+	cam_periph_unhold(periph);
 	cam_periph_unlock(periph);
 	cam_periph_release(periph);
 
@@ -679,7 +683,6 @@
 {
 	struct cam_periph *periph;
 	struct sa_softc *softc;
-	int    s;
 	
 	bp->bio_resid = bp->bio_bcount;
 	if (SA_IS_CTRL(bp->bio_dev)) {
@@ -691,18 +694,18 @@
 		biofinish(bp, NULL, ENXIO);
 		return;
 	}
-	softc = (struct sa_softc *)periph->softc;
+	cam_periph_lock(periph);
 
-	s = splsoftcam();
+	softc = (struct sa_softc *)periph->softc;
 
 	if (softc->flags & SA_FLAG_INVALID) {
-		splx(s);
+		cam_periph_unlock(periph);
 		biofinish(bp, NULL, ENXIO);
 		return;
 	}
 
 	if (softc->flags & SA_FLAG_TAPE_FROZEN) {
-		splx(s);
+		cam_periph_unlock(periph);
 		biofinish(bp, NULL, EPERM);
 		return;
 	}
@@ -713,16 +716,15 @@
 	 * file descriptor.
 	 */
 	if (bp->bio_cmd == BIO_WRITE && softc->open_rdonly) {
-		splx(s);
+		cam_periph_unlock(periph);
 		biofinish(bp, NULL, EBADF);
 		return;
 	}
 
-	splx(s);
-
 	if (softc->open_pending_mount) {
 		int error = samount(periph, 0, bp->bio_dev);
 		if (error) {
+			cam_periph_unlock(periph);
 			biofinish(bp, NULL, ENXIO);
 			return;
 		}
@@ -735,6 +737,7 @@
 	 * If it's a null transfer, return immediately
 	 */
 	if (bp->bio_bcount == 0) {
+		cam_periph_unlock(periph);
 		biodone(bp);
 		return;
 	}
@@ -749,10 +752,10 @@
 		    ((bp->bio_bcount & softc->blk_mask) != 0)) ||
 		    ((softc->blk_mask == ~0) &&
 		    ((bp->bio_bcount % softc->min_blk) != 0))) {
-			xpt_print_path(periph->path);
-			printf("Invalid request.  Fixed block device "
-			       "requests must be a multiple "
-			       "of %d bytes\n", softc->min_blk);
+			xpt_print(periph->path, "Invalid request.  Fixed block "
+			    "device requests must be a multiple of %d bytes\n",
+			    softc->min_blk);
+			cam_periph_unlock(periph);
 			biofinish(bp, NULL, EINVAL);
 			return;
 		}
@@ -761,25 +764,19 @@
 		   (bp->bio_bcount & softc->blk_mask) != 0) {
 
 		xpt_print_path(periph->path);
-		printf("Invalid request.  Variable block device "
-		    "requests must be ");
+		printf("Invalid request.  Variable block "
+		    "device requests must be ");
 		if (softc->blk_mask != 0) {
 			printf("a multiple of %d ", (0x1 << softc->blk_gran));
 		}
 		printf("between %d and %d bytes\n", softc->min_blk,
 		    softc->max_blk);
+		cam_periph_unlock(periph);
 		biofinish(bp, NULL, EINVAL);
 		return;
         }
 	
 	/*
-	 * Mask interrupts so that the device cannot be invalidated until
-	 * after we are in the queue.  Otherwise, we might not properly
-	 * clean up one of the buffers.
-	 */
-	s = splbio();
-	
-	/*
 	 * Place it at the end of the queue.
 	 */
 	bioq_insert_tail(&softc->bio_queue, bp);
@@ -794,12 +791,12 @@
 		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
 		    ("sastrategy: queue count now %d\n", softc->queue_count));
 	}
-	splx(s);
 	
 	/*
 	 * Schedule ourselves for performing the work.
 	 */
 	xpt_schedule(periph, 1);
+	cam_periph_unlock(periph);
 
 	return;
 }
@@ -822,7 +819,6 @@
 	struct sa_softc *softc;
 	scsi_space_code spaceop;
 	int didlockperiph = 0;
-	int s;
 	int mode;
 	int error = 0;
 
@@ -834,6 +830,7 @@
 	if (periph == NULL)
 		return (ENXIO);	
 
+	cam_periph_lock(periph);
 	softc = (struct sa_softc *)periph->softc;
 
 	/*
@@ -859,13 +856,10 @@
 			 * other thread that has this device open to do
 			 * an MTIOCERRSTAT that would clear latched status.
 			 */
-			s = splsoftcam();
 			if ((periph->flags & CAM_PERIPH_LOCKED) == 0) {
-				error = cam_periph_lock(periph, PRIBIO|PCATCH);
-				if (error != 0) {
-					splx(s);
+				error = cam_periph_hold(periph, PRIBIO|PCATCH);
+				 if (error != 0)
 					return (error);
-				}
 				didlockperiph = 1;
 			}
 			break;
@@ -898,12 +892,9 @@
 			 * than at open time because we are sharing writable
 			 * access to data structures.
 			 */
-			s = splsoftcam();
-			error = cam_periph_lock(periph, PRIBIO|PCATCH);
-			if (error != 0) {
-				splx(s);
+			error = cam_periph_hold(periph, PRIBIO|PCATCH);
+			if (error != 0)
 				return (error);
-			}
 			didlockperiph = 1;
 			break;
 
@@ -1070,8 +1061,8 @@
 			nmarks = softc->filemarks;
 			error = sacheckeod(periph);
 			if (error) {
-				xpt_print_path(periph->path);
-				printf("EOD check prior to spacing failed\n");
+				xpt_print(periph->path,
+				    "EOD check prior to spacing failed\n");
 				softc->flags |= SA_FLAG_EIO_PENDING;
 				break;
 			}
@@ -1322,16 +1313,17 @@
 			softc->fileno = (daddr_t) -1;
 			softc->blkno = (daddr_t) -1;
 			softc->flags &= ~SA_FLAG_TAPE_FROZEN;
-			xpt_print_path(periph->path);
-			printf("tape state now unfrozen.\n");
+			xpt_print(periph->path,
+			    "tape state now unfrozen.\n");
 			break;
 		default:
 			break;
 		}
 	}
 	if (didlockperiph) {
-		cam_periph_unlock(periph);
+		cam_periph_unhold(periph);
 	}
+	cam_periph_unlock(periph);
 	return (error);
 }
 
@@ -1339,29 +1331,11 @@
 sainit(void)
 {
 	cam_status status;
-	struct cam_path *path;
 
 	/*
 	 * Install a global async callback.
 	 */
-	status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID,
-				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
-
-	if (status == CAM_REQ_CMP) {
-		/* Register the async callbacks of interrest */
-		struct ccb_setasync csa; /*
-					  * This is an immediate CCB,
-					  * so using the stack is OK
-					  */
-		xpt_setup_ccb(&csa.ccb_h, path, 5);
-		csa.ccb_h.func_code = XPT_SASYNC_CB;
-		csa.event_enable = AC_FOUND_DEVICE;
-		csa.callback = saasync;
-		csa.callback_arg = NULL;
-		xpt_action((union ccb *)&csa);
-		status = csa.ccb_h.status;
-		xpt_free_path(path);
-	}
+	status = xpt_register_async(AC_FOUND_DEVICE, saasync, NULL, NULL);
 
 	if (status != CAM_REQ_CMP) {
 		printf("sa: Failed to attach master async callback "
@@ -1373,42 +1347,25 @@
 saoninvalidate(struct cam_periph *periph)
 {
 	struct sa_softc *softc;
-	struct ccb_setasync csa;
-	int s;
 
 	softc = (struct sa_softc *)periph->softc;
 
 	/*
 	 * De-register any async callbacks.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path,
-		      /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = 0;
-	csa.callback = saasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(0, saasync, periph, periph->path);
 
 	softc->flags |= SA_FLAG_INVALID;
 
 	/*
-	 * Although the oninvalidate() routines are always called at
-	 * splsoftcam, we need to be at splbio() here to keep the buffer
-	 * queue from being modified while we traverse it.
-	 */
-	s = splbio();
-
-	/*
 	 * Return all queued I/O with ENXIO.
 	 * XXX Handle any transactions queued to the card
 	 *     with XPT_ABORT_CCB.
 	 */
 	bioq_flush(&softc->bio_queue, NULL, ENXIO);
 	softc->queue_count = 0;
-	splx(s);
 
-	xpt_print_path(periph->path);
-	printf("lost device\n");
+	xpt_print(periph->path, "lost device\n");
 
 }
 
@@ -1430,8 +1387,7 @@
 		destroy_dev(softc->devs.mode_devs[i].er_dev);
 	}
 
-	xpt_print_path(periph->path);
-	printf("removing device entry\n");
+	xpt_print(periph->path, "removing device entry\n");
 	free(softc, M_SCSISA);
 }
 
@@ -1481,7 +1437,6 @@
 saregister(struct cam_periph *periph, void *arg)
 {
 	struct sa_softc *softc;
-	struct ccb_setasync csa;
 	struct ccb_getdev *cgd;
 	caddr_t match;
 	int i;
@@ -1525,9 +1480,8 @@
 		softc->last_media_blksize =
 		    ((struct sa_quirk_entry *)match)->prefblk;
 #ifdef	CAMDEBUG
-		xpt_print_path(periph->path);
-		printf("found quirk entry %d\n", (int)
-		    (((struct sa_quirk_entry *) match) - sa_quirk_table));
+		xpt_print(periph->path, "found quirk entry %d\n",
+		    (int) (((struct sa_quirk_entry *) match) - sa_quirk_table));
 #endif
 	} else
 		softc->quirks = SA_QUIRK_NONE;
@@ -1537,6 +1491,7 @@
 	 * blocksize until we media is inserted.  So, set a flag to
 	 * indicate that the blocksize is unavailable right now.
 	 */
+	cam_periph_unlock(periph);
 	softc->device_stats = devstat_new_entry("sa", periph->unit_number, 0,
 	    DEVSTAT_BS_UNAVAILABLE, SID_TYPE(&cgd->inq_data) |
 	    DEVSTAT_TYPE_IF_SCSI, DEVSTAT_PRIORITY_TAPE);
@@ -1583,17 +1538,13 @@
 			alias->si_drv1 = periph;
 		}
 	}
+	cam_periph_lock(periph);
 
 	/*
 	 * Add an async callback so that we get
 	 * notified if this device goes away.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = AC_LOST_DEVICE;
-	csa.callback = saasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(AC_LOST_DEVICE, saasync, periph, periph->path);
 
 	xpt_announce_periph(periph, NULL);
 
@@ -1615,12 +1566,10 @@
 	{
 		/* Pull a buffer from the queue and get going on it */		
 		struct bio *bp;
-		int s;
 
 		/*
 		 * See if there is a buf with work for us to do..
 		 */
-		s = splbio();
 		bp = bioq_first(&softc->bio_queue);
 		if (periph->immediate_priority <= periph->pinfo.priority) {
 			CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
@@ -1629,10 +1578,8 @@
 			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
 					  periph_links.sle);
 			periph->immediate_priority = CAM_PRIORITY_NONE;
-			splx(s);
 			wakeup(&periph->ccb_list);
 		} else if (bp == NULL) {
-			splx(s);
 			xpt_release_ccb(start_ccb);
 		} else if ((softc->flags & SA_FLAG_ERR_PENDING) != 0) {
 			struct bio *done_bp;
@@ -1675,7 +1622,6 @@
 			    "%d more buffers queued up\n",
 			    (softc->flags & SA_FLAG_ERR_PENDING),
 			    (bp != NULL)? "not " : " ", softc->queue_count));
-			splx(s);
 			xpt_release_ccb(start_ccb);
 			biodone(done_bp);
 		} else {
@@ -1693,10 +1639,8 @@
 					    softc->media_blksize;
 				} else {
 					bp->bio_error = EIO;
-					xpt_print_path(periph->path);
-					printf("zero blocksize for "
-					    "FIXED length writes?\n");
-					splx(s);
+					xpt_print(periph->path, "zero blocksize"
+					    " for FIXED length writes?\n");
 					biodone(bp);
 					break;
 				}
@@ -1747,7 +1691,6 @@
 			Set_CCB_Type(start_ccb, SA_CCB_BUFFER_IO);
 			start_ccb->ccb_h.ccb_bp = bp;
 			bp = bioq_first(&softc->bio_queue);
-			splx(s);
 			xpt_action(start_ccb);
 		}
 		
@@ -1792,7 +1735,6 @@
 		}
 
 		if (error == EIO) {
-			int s;			
 
 			/*
 			 * Catastrophic error. Mark the tape as frozen
@@ -1805,10 +1747,8 @@
 			 *
 			 */
 
-			s = splbio();
 			softc->flags |= SA_FLAG_TAPE_FROZEN;
 			bioq_flush(&softc->bio_queue, NULL, EIO);
-			splx(s);
 		}
 		if (error != 0) {
 			bp->bio_resid = bp->bio_bcount;
@@ -1920,8 +1860,8 @@
 			 */
 			softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
 			if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
-				xpt_print_path(periph->path);
-				printf("error %d on TUR in samount\n", error);
+				xpt_print(periph->path,
+				    "error %d on TUR in samount\n", error);
 			}
 		}
 	} else {
@@ -1982,10 +1922,9 @@
 		 * read a full record.
 		 */
 		rblim = (struct  scsi_read_block_limits_data *)
-		    malloc(8192, M_TEMP, M_WAITOK);
+		    malloc(8192, M_SCSISA, M_NOWAIT);
 		if (rblim == NULL) {
-			xpt_print_path(periph->path);
-			printf("no memory for test read\n");
+			xpt_print(periph->path, "no memory for test read\n");
 			xpt_release_ccb(ccb);
 			error = ENOMEM;
 			goto exit;
@@ -2006,8 +1945,8 @@
 			    softc->device_stats);
 			QFRLS(ccb);
 			if (error) {
-				xpt_print_path(periph->path);
-				printf("unable to rewind after test read\n");
+				xpt_print(periph->path,
+				    "unable to rewind after test read\n");
 				xpt_release_ccb(ccb);
 				goto exit;
 			}
@@ -2171,8 +2110,8 @@
 		if ((softc->max_blk < softc->media_blksize) ||
 		    (softc->min_blk > softc->media_blksize &&
 		    softc->media_blksize)) {
-			xpt_print_path(periph->path);
-			printf("BLOCK LIMITS (%d..%d) could not match current "
+			xpt_print(periph->path,
+			    "BLOCK LIMITS (%d..%d) could not match current "
 			    "block settings (%d)- adjusting\n", softc->min_blk,
 			    softc->max_blk, softc->media_blksize);
 			softc->max_blk = softc->min_blk =
@@ -2206,9 +2145,9 @@
 			error = sasetparams(periph, SA_PARAM_BLOCKSIZE,
 			    softc->media_blksize, 0, 0, SF_NO_PRINT);
 			if (error) {
-				xpt_print_path(periph->path);
-				printf("unable to set fixed blocksize to %d\n",
-				     softc->media_blksize);
+				xpt_print(periph->path,
+				    "unable to set fixed blocksize to %d\n",
+				    softc->media_blksize);
 				goto exit;
 			}
 		}
@@ -2233,8 +2172,8 @@
 						softc->last_media_blksize = 512;
 					goto tryagain;
 				}
-				xpt_print_path(periph->path);
-				printf("unable to set variable blocksize\n");
+				xpt_print(periph->path,
+				    "unable to set variable blocksize\n");
 				goto exit;
 			}
 		}
@@ -2291,8 +2230,8 @@
 			if (error == 0) {
 				softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF;
 			} else {
-				xpt_print_path(periph->path);
-				printf("unable to set buffered mode\n");
+				xpt_print(periph->path,
+				    "unable to set buffered mode\n");
 			}
 			error = 0;	/* not an error */
 		}
@@ -2303,7 +2242,7 @@
 		}
 exit:
 		if (rblim != NULL)
-			free(rblim, M_TEMP);
+			free(rblim, M_SCSISA);
 
 		if (error != 0) {
 			softc->dsreg = MTIO_DSREG_NIL;
@@ -2534,8 +2473,8 @@
 	 */
 	if (error == 0 && (sense->flags & SSD_ILI)) {
 		if (info < 0) {
-			xpt_print_path(csio->ccb_h.path);
-			printf(toobig, csio->dxfer_len - info);
+			xpt_print(csio->ccb_h.path, toobig,
+			    csio->dxfer_len - info);
 			csio->resid = csio->dxfer_len;
 			error = EIO;
 		} else {
@@ -2604,7 +2543,12 @@
 			mode_buffer_len += sizeof (sa_comp_t);
 	}
 
-	mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK | M_ZERO);
+	/* XXX Fix M_NOWAIT */
+	mode_buffer = malloc(mode_buffer_len, M_SCSISA, M_NOWAIT | M_ZERO);
+	if (mode_buffer == NULL) {
+		xpt_release_ccb(ccb);
+		return (ENOMEM);
+	}
 	mode_hdr = (struct scsi_mode_header_6 *)mode_buffer;
 	mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
 
@@ -2633,7 +2577,7 @@
 			goto retry;
 		}
 		softc->quirks |= SA_QUIRK_NOCOMP;
-		free(mode_buffer, M_TEMP);
+		free(mode_buffer, M_SCSISA);
 		goto retry;
 	} else if (status == CAM_SCSI_STATUS_ERROR) {
 		/* Tell the user about the fatal error. */
@@ -2742,7 +2686,7 @@
 sagetparamsexit:
 
 	xpt_release_ccb(ccb);
-	free(mode_buffer, M_TEMP);
+	free(mode_buffer, M_SCSISA);
 	return (error);
 }
 
@@ -2784,7 +2728,9 @@
 
 	softc = (struct sa_softc *)periph->softc;
 
-	ccomp = malloc(sizeof (sa_comp_t), M_TEMP, M_WAITOK);
+	ccomp = malloc(sizeof (sa_comp_t), M_SCSISA, M_NOWAIT);
+	if (ccomp == NULL)
+		return (ENOMEM);
 
 	/*
 	 * Since it doesn't make sense to set the number of blocks, or
@@ -2799,7 +2745,7 @@
 	    &current_calg, ccomp);
 
 	if (error != 0) {
-		free(ccomp, M_TEMP);
+		free(ccomp, M_SCSISA);
 		return (error);
 	}
 
@@ -2807,7 +2753,11 @@
 	if (params_to_set & SA_PARAM_COMPRESSION)
 		mode_buffer_len += sizeof (sa_comp_t);
 
-	mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK | M_ZERO);
+	mode_buffer = malloc(mode_buffer_len, M_SCSISA, M_NOWAIT | M_ZERO);
+	if (mode_buffer == NULL) {
+		free(ccomp, M_SCSISA);
+		return (ENOMEM);
+	}
 
 	mode_hdr = (struct scsi_mode_header_6 *)mode_buffer;
 	mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
@@ -2956,8 +2906,8 @@
 			 * so turn off the set compression bit.
 			 */
 			params_to_set &= ~SA_PARAM_COMPRESSION;
-			xpt_print_path(periph->path);
-			printf("device does not seem to support compression\n");
+			xpt_print(periph->path,
+			    "device does not seem to support compression\n");
 
 			/*
 			 * If that was the only thing the user wanted us to set,
@@ -2965,7 +2915,7 @@
 			 * 'operation not supported'.
 			 */
 			if (params_to_set == SA_PARAM_NONE) {
-				free(mode_buffer, M_TEMP);
+				free(mode_buffer, M_SCSISA);
 				xpt_release_ccb(ccb);
 				return (ENODEV);
 			}
@@ -3050,7 +3000,7 @@
 	xpt_release_ccb(ccb);
 
 	if (ccomp != NULL)
-		free(ccomp, M_TEMP);
+		free(ccomp, M_SCSISA);
 
 	if (params_to_set & SA_PARAM_COMPRESSION) {
 		if (error) {
@@ -3069,7 +3019,7 @@
 		}
 	}
 
-	free(mode_buffer, M_TEMP);
+	free(mode_buffer, M_SCSISA);
 	return (error);
 }
 
Index: scsi_cd.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_cd.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/cam/scsi/scsi_cd.c -L sys/cam/scsi/scsi_cd.c -u -r1.2 -r1.3
--- sys/cam/scsi/scsi_cd.c
+++ sys/cam/scsi/scsi_cd.c
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_cd.c,v 1.93.2.3 2006/07/26 07:48:51 delphij Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_cd.c,v 1.102 2007/07/21 18:07:45 kan Exp $");
 
 #include "opt_cd.h"
 
@@ -70,6 +70,7 @@
 #include <cam/cam_periph.h>
 #include <cam/cam_xpt_periph.h>
 #include <cam/cam_queue.h>
+#include <cam/cam_sim.h>
 
 #include <cam/scsi/scsi_message.h>
 #include <cam/scsi/scsi_da.h>
@@ -103,7 +104,8 @@
 	CD_FLAG_RETRY_UA	= 0x0200,
 	CD_FLAG_VALID_MEDIA	= 0x0400,
 	CD_FLAG_VALID_TOC	= 0x0800,
-	CD_FLAG_SCTX_INIT	= 0x1000
+	CD_FLAG_SCTX_INIT	= 0x1000,
+	CD_FLAG_OPEN		= 0x2000
 } cd_flags;
 
 typedef enum {
@@ -290,9 +292,6 @@
 
 PERIPHDRIVER_DECLARE(cd, cddriver);
 
-
-static int num_changers;
-
 #ifndef CHANGER_MIN_BUSY_SECONDS
 #define CHANGER_MIN_BUSY_SECONDS	5
 #endif
@@ -319,41 +318,32 @@
 	struct camq			 devq;
 	struct timeval			 start_time;
 	struct cd_softc			 *cur_device;
-	struct callout_handle		 short_handle;
-	struct callout_handle		 long_handle;
+	struct callout			 short_handle;
+	struct callout			 long_handle;
 	volatile cd_changer_flags	 flags;
 	STAILQ_ENTRY(cdchanger)		 changer_links;
 	STAILQ_HEAD(chdevlist, cd_softc) chluns;
 };
 
+static struct mtx changerq_mtx;
 static STAILQ_HEAD(changerlist, cdchanger) changerq;
+static int num_changers;
 
+MALLOC_DEFINE(M_SCSICD, "scsi_cd", "scsi_cd buffers");
 
 static void
 cdinit(void)
 {
 	cam_status status;
-	struct cam_path *path;
+
+	mtx_init(&changerq_mtx, "cdchangerq", "SCSI CD Changer List", MTX_DEF);
+	STAILQ_INIT(&changerq);
 
 	/*
 	 * Install a global async callback.  This callback will
 	 * receive async callbacks like "new device found".
 	 */
-	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
-				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
-
-	if (status == CAM_REQ_CMP) {
-		struct ccb_setasync csa;
-
-                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
-                csa.ccb_h.func_code = XPT_SASYNC_CB;
-                csa.event_enable = AC_FOUND_DEVICE;
-                csa.callback = cdasync;
-                csa.callback_arg = NULL;
-                xpt_action((union ccb *)&csa);
-		status = csa.ccb_h.status;
-                xpt_free_path(path);
-        }
+	status = xpt_register_async(AC_FOUND_DEVICE, cdasync, NULL, NULL);
 
 	if (status != CAM_REQ_CMP) {
 		printf("cd: Failed to attach master async callback "
@@ -364,39 +354,23 @@
 static void
 cdoninvalidate(struct cam_periph *periph)
 {
-	int s;
 	struct cd_softc *softc;
-	struct ccb_setasync csa;
 
 	softc = (struct cd_softc *)periph->softc;
 
 	/*
 	 * De-register any async callbacks.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path,
-		      /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = 0;
-	csa.callback = cdasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(0, cdasync, periph, periph->path);
 
 	softc->flags |= CD_FLAG_INVALID;
 
 	/*
-	 * Although the oninvalidate() routines are always called at
-	 * splsoftcam, we need to be at splbio() here to keep the buffer
-	 * queue from being modified while we traverse it.
-	 */
-	s = splbio();
-
-	/*
 	 * Return all queued I/O with ENXIO.
 	 * XXX Handle any transactions queued to the card
 	 *     with XPT_ABORT_CCB.
 	 */
 	bioq_flush(&softc->bio_queue, NULL, ENXIO);
-	splx(s);
 
 	/*
 	 * If this device is part of a changer, and it was scheduled
@@ -408,28 +382,23 @@
 		camq_remove(&softc->changer->devq, softc->pinfo.index);
 
 	disk_gone(softc->disk);
-	xpt_print_path(periph->path);
-	printf("lost device\n");
+	xpt_print(periph->path, "lost device\n");
 }
 
 static void
 cdcleanup(struct cam_periph *periph)
 {
 	struct cd_softc *softc;
-	int s;
 
 	softc = (struct cd_softc *)periph->softc;
 
-	xpt_print_path(periph->path);
-	printf("removing device entry\n");
+	xpt_print(periph->path, "removing device entry\n");
 
 	if ((softc->flags & CD_FLAG_SCTX_INIT) != 0
 	    && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
-		xpt_print_path(periph->path);
-		printf("can't remove sysctl context\n");
+		xpt_print(periph->path, "can't remove sysctl context\n");
 	}
 
-	s = splsoftcam();
 	/*
 	 * In the queued, non-active case, the device in question
 	 * has already been removed from the changer run queue.  Since this
@@ -459,8 +428,7 @@
 		 * be any bogus pointer references there.
 		 */
 		if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
-			untimeout(cdshorttimeout, softc->changer,
-				  softc->changer->short_handle);
+			callout_stop(&softc->changer->short_handle);
 			softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
 		}
 		softc->changer->devq.qfrozen_cnt--;
@@ -481,27 +449,27 @@
 		 * it won't hurt to check and see if there are any left.
 		 */
 		if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) {
-			untimeout(cdrunchangerqueue, softc->changer,
-				  softc->changer->long_handle);
+			callout_stop(&softc->changer->long_handle);
 			softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED;
 		}
 
 		if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
-			untimeout(cdshorttimeout, softc->changer,
-				  softc->changer->short_handle);
+			callout_stop(&softc->changer->short_handle);
 			softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
 		}
 
+		mtx_lock(&changerq_mtx);
 		STAILQ_REMOVE(&changerq, softc->changer, cdchanger,
 			      changer_links);
-		xpt_print_path(periph->path);
-		printf("removing changer entry\n");
-		free(softc->changer, M_DEVBUF);
 		num_changers--;
+		mtx_unlock(&changerq_mtx);
+		xpt_print(periph->path, "removing changer entry\n");
+		free(softc->changer, M_DEVBUF);
 	}
+	cam_periph_unlock(periph);
 	disk_destroy(softc->disk);
+	cam_periph_lock(periph);
 	free(softc, M_DEVBUF);
-	splx(s);
 }
 
 static void
@@ -548,10 +516,8 @@
 	{
 		struct cd_softc *softc;
 		struct ccb_hdr *ccbh;
-		int s;
 
 		softc = (struct cd_softc *)periph->softc;
-		s = splsoftcam();
 		/*
 		 * Don't fail on the expected unit attention
 		 * that will occur.
@@ -559,7 +525,6 @@
 		softc->flags |= CD_FLAG_RETRY_UA;
 		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
 			ccbh->ccb_state |= CD_CCB_RETRY_UA;
-		splx(s);
 		/* FALLTHROUGH */
 	}
 	default:
@@ -576,8 +541,10 @@
 	char tmpstr[80], tmpstr2[80];
 
 	periph = (struct cam_periph *)context;
-	softc = (struct cd_softc *)periph->softc;
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+		return;
 
+	softc = (struct cd_softc *)periph->softc;
 	snprintf(tmpstr, sizeof(tmpstr), "CAM CD unit %d", periph->unit_number);
 	snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
 
@@ -592,6 +559,7 @@
 	if (softc->sysctl_tree == NULL) {
 		printf("cdsysctlinit: unable to allocate sysctl tree\n");
 		mtx_unlock(&Giant);
+		cam_periph_release(periph);
 		return;
 	}
 
@@ -605,6 +573,7 @@
 		"Minimum CDB size");
 
 	mtx_unlock(&Giant);
+	cam_periph_release(periph);
 }
 
 /*
@@ -648,7 +617,6 @@
 cdregister(struct cam_periph *periph, void *arg)
 {
 	struct cd_softc *softc;
-	struct ccb_setasync csa;
 	struct ccb_pathinq cpi;
 	struct ccb_getdev *cgd;
 	char tmpstr[80];
@@ -738,6 +706,7 @@
 	 * WORM peripheral driver.  WORM drives will also have the WORM
 	 * driver attached to them.
 	 */
+	cam_periph_unlock(periph);
 	softc->disk = disk_alloc();
 	softc->disk->d_devstat = devstat_new_entry("cd", 
 			  periph->unit_number, 0,
@@ -751,20 +720,16 @@
 	softc->disk->d_name = "cd";
 	softc->disk->d_unit = periph->unit_number;
 	softc->disk->d_drv1 = periph;
-	softc->disk->d_flags = DISKFLAG_NEEDSGIANT;
+	softc->disk->d_flags = 0;
 	disk_create(softc->disk, DISK_VERSION);
+	cam_periph_lock(periph);
 
 	/*
 	 * Add an async callback so that we get
 	 * notified if this device goes away.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path,
-		      /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
-	csa.callback = cdasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
+			   cdasync, periph, periph->path);
 
 	/*
 	 * If the target lun is greater than 0, we most likely have a CD
@@ -787,13 +752,11 @@
 		/* Set the changer flag in the current device's softc */
 		softc->flags |= CD_FLAG_CHANGER;
 
-		if (num_changers == 0)
-			STAILQ_INIT(&changerq);
-
 		/*
 		 * Now, look around for an existing changer device with the
 		 * same path and target ID as the current device.
 		 */
+		mtx_lock(&changerq_mtx);
 		for (found = 0,
 		     nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq);
 		     nchanger != NULL;
@@ -804,6 +767,7 @@
 				break;
 			}
 		}
+		mtx_unlock(&changerq_mtx);
 
 		/*
 		 * If we found a matching entry, just add this device to
@@ -909,8 +873,6 @@
 				goto cdregisterexit;
 			}
 
-			num_changers++;
-
 			nchanger->path_id = cgd->ccb_h.path_id;
 			nchanger->target_id = cgd->ccb_h.target_id;
 
@@ -919,8 +881,16 @@
 
 			STAILQ_INIT(&nchanger->chluns);
 
+			callout_init_mtx(&nchanger->long_handle,
+			    periph->sim->mtx, 0);
+			callout_init_mtx(&nchanger->short_handle,
+			    periph->sim->mtx, 0);
+
+			mtx_lock(&changerq_mtx);
+			num_changers++;
 			STAILQ_INSERT_TAIL(&changerq, nchanger,
 					   changer_links);
+			mtx_unlock(&changerq_mtx);
 			
 			/*
 			 * Create a path with lun id 0, and see if we can
@@ -982,9 +952,11 @@
 
 cdregisterexit:
 
-	/* Lock this peripheral until we are setup */
-	/* Can't block */
-	cam_periph_lock(periph, PRIBIO); 
+	/*
+	 * Refcount and block open attempts until we are setup
+	 * Can't block
+	 */
+	(void)cam_periph_hold(periph, PRIBIO);
 
 	if ((softc->flags & CD_FLAG_CHANGER) == 0)
 		xpt_schedule(periph, /*priority*/5);
@@ -1000,7 +972,6 @@
 	struct cam_periph *periph;
 	struct cd_softc *softc;
 	int error;
-	int s;
 
 	periph = (struct cam_periph *)dp->d_drv1;
 	if (periph == NULL)
@@ -1008,24 +979,28 @@
 
 	softc = (struct cd_softc *)periph->softc;
 
-	/*
-	 * Grab splsoftcam and hold it until we lock the peripheral.
-	 */
-	s = splsoftcam();
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+		return(ENXIO);
+
+	cam_periph_lock(periph);
+
 	if (softc->flags & CD_FLAG_INVALID) {
-		splx(s);
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return(ENXIO);
 	}
 
-	if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) {
-		splx(s);
+	if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
 		return (error);
 	}
 
-	splx(s);
-
-	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
-		return(ENXIO);
+	/* Closes aren't symmetrical with opens, so fix up the refcounting. */
+	if (softc->flags & CD_FLAG_OPEN)
+		cam_periph_release(periph);
+	else
+		softc->flags |= CD_FLAG_OPEN;
 
 	/*
 	 * Check for media, and set the appropriate flags.  We don't bail
@@ -1034,11 +1009,11 @@
 	 */
 	cdcheckmedia(periph);
 
-	cam_periph_unlock(periph);
-
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n"));
+	cam_periph_unhold(periph);
+	cam_periph_unlock(periph);
 
-	return (error);
+	return (0);
 }
 
 static int
@@ -1046,7 +1021,6 @@
 {
 	struct 	cam_periph *periph;
 	struct	cd_softc *softc;
-	int	error;
 
 	periph = (struct cam_periph *)dp->d_drv1;
 	if (periph == NULL)
@@ -1054,8 +1028,8 @@
 
 	softc = (struct cd_softc *)periph->softc;
 
-	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
-		return (error);
+	cam_periph_lock(periph);
+	cam_periph_hold(periph, PRIBIO);
 
 	if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0)
 		cdprevent(periph, PR_ALLOW);
@@ -1069,8 +1043,9 @@
 	/*
 	 * We'll check the media and toc again at the next open().
 	 */
-	softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC);
+	softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC|CD_FLAG_OPEN);
 
+	cam_periph_unhold(periph);
 	cam_periph_unlock(periph);
 	cam_periph_release(periph);
 
@@ -1081,9 +1056,6 @@
 cdshorttimeout(void *arg)
 {
 	struct cdchanger *changer;
-	int s;
-
-	s = splsoftcam();
 
 	changer = (struct cdchanger *)arg;
 
@@ -1099,8 +1071,6 @@
 		changer->flags |= CHANGER_MANUAL_CALL;
 		cdrunchangerqueue(changer);
 	}
-
-	splx(s);
 }
 
 /*
@@ -1110,9 +1080,6 @@
 cdschedule(struct cam_periph *periph, int priority)
 {
 	struct cd_softc *softc;
-	int s;
-
-	s = splsoftcam();
 
 	softc = (struct cd_softc *)periph->softc;
 
@@ -1151,9 +1118,6 @@
 	} else if ((softc->flags & CD_FLAG_ACTIVE)
 		&& ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0))
 		xpt_schedule(periph, priority);
-
-	splx(s);
-
 }
 
 static void
@@ -1162,9 +1126,6 @@
 	struct cd_softc *softc;
 	struct cdchanger *changer;
 	int called_from_timeout;
-	int s;
-
-	s = splsoftcam();
 
 	changer = (struct cdchanger *)arg;
 
@@ -1184,7 +1145,6 @@
 
 	/* nothing to do if the queue is empty */
 	if (changer->devq.entries <= 0) {
-		splx(s);
 		return;
 	}
 
@@ -1194,29 +1154,28 @@
 	 */
 	if (changer->devq.qfrozen_cnt > 0) {
 
+		/*
+		 * We always need to reset the frozen count and clear the
+		 * active flag.
+		 */
+		changer->devq.qfrozen_cnt--;
+		changer->cur_device->flags &= ~CD_FLAG_ACTIVE;
+		changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP;
+
 		if (changer->cur_device->outstanding_cmds > 0) {
 			changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP;
 			changer->cur_device->bufs_left = 
 				changer->cur_device->outstanding_cmds;
 			if (called_from_timeout) {
-				changer->long_handle =
-					timeout(cdrunchangerqueue, changer,
-				        changer_max_busy_seconds * hz);
+				callout_reset(&changer->long_handle,
+			            changer_max_busy_seconds * hz,
+				    cdrunchangerqueue, changer);
 				changer->flags |= CHANGER_TIMEOUT_SCHED;
 			}
-			splx(s);
 			return;
 		}
 
 		/*
-		 * We always need to reset the frozen count and clear the
-		 * active flag.
-		 */
-		changer->devq.qfrozen_cnt--;
-		changer->cur_device->flags &= ~CD_FLAG_ACTIVE;
-		changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP;
-
-		/*
 		 * Check to see whether the current device has any I/O left
 		 * to do.  If so, requeue it at the end of the queue.  If
 		 * not, there is no need to requeue it.
@@ -1246,12 +1205,12 @@
 	 * ones so this device gets its full time quantum.
 	 */
 	if (changer->flags & CHANGER_TIMEOUT_SCHED) {
-		untimeout(cdrunchangerqueue, changer, changer->long_handle);
+		callout_stop(&changer->long_handle);
 		changer->flags &= ~CHANGER_TIMEOUT_SCHED;
 	}
 
 	if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
-		untimeout(cdshorttimeout, changer, changer->short_handle);
+		callout_stop(&changer->short_handle);
 		changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
 	}
 
@@ -1261,17 +1220,12 @@
 	 * switch time.
 	 */
 	changer->flags |= CHANGER_NEED_TIMEOUT;
-
-	splx(s);
 }
 
 static void
 cdchangerschedule(struct cd_softc *softc)
 {
 	struct cdchanger *changer;
-	int s;
-
-	s = splsoftcam();
 
 	changer = softc->changer;
 
@@ -1317,18 +1271,18 @@
 		 * and schedule our timeouts.
 		 */
 		if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) {
-			changer->long_handle =
-			    timeout(cdrunchangerqueue, changer,
-				    changer_max_busy_seconds * hz);
+			callout_reset(&changer->long_handle,
+			    changer_max_busy_seconds * hz,
+			    cdrunchangerqueue, changer);
 			changer->flags |= CHANGER_TIMEOUT_SCHED;
 		} else
 			printf("cdchangerschedule: already have a long"
 			       " timeout!\n");
 
 		if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) {
-			changer->short_handle =
-			    timeout(cdshorttimeout, changer,
-				    changer_min_busy_seconds * hz);
+			callout_reset(&changer->short_handle,
+			    changer_min_busy_seconds * hz,
+			    cdshorttimeout, changer);
 			changer->flags |= CHANGER_SHORT_TMOUT_SCHED;
 		} else
 			printf("cdchangerschedule: already have a short "
@@ -1341,7 +1295,6 @@
 		changer->flags &= ~CHANGER_NEED_TIMEOUT;
 
 	}
-	splx(s);
 }
 
 static int
@@ -1370,14 +1323,10 @@
 cdgetccb(struct cam_periph *periph, u_int32_t priority)
 {
 	struct cd_softc *softc;
-	int s;
 
 	softc = (struct cd_softc *)periph->softc;
 
 	if (softc->flags & CD_FLAG_CHANGER) {
-
-		s = splsoftcam();
-
 		/*
 		 * This should work the first time this device is woken up,
 		 * but just in case it doesn't, we use a while loop.
@@ -1400,9 +1349,9 @@
 				softc->changer->flags |= CHANGER_MANUAL_CALL;
 				cdrunchangerqueue(softc->changer);
 			} else
-				tsleep(&softc->changer, PRIBIO, "cgticb", 0);
+				msleep(&softc->changer, periph->sim->mtx,
+				    PRIBIO, "cgticb", 0);
 		}
-		splx(s);
 	}
 	return(cam_periph_getccb(periph, priority));
 }
@@ -1418,7 +1367,6 @@
 {
 	struct cam_periph *periph;
 	struct cd_softc *softc;
-	int    s;
 
 	periph = (struct cam_periph *)bp->bio_disk->d_drv1;
 	if (periph == NULL) {
@@ -1426,22 +1374,16 @@
 		return;
 	}
 
+	cam_periph_lock(periph);
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n"));
 
 	softc = (struct cd_softc *)periph->softc;
 
 	/*
-	 * Mask interrupts so that the pack cannot be invalidated until
-	 * after we are in the queue.  Otherwise, we might not properly
-	 * clean up one of the buffers.
-	 */
-	s = splbio();
-	
-	/*
 	 * If the device has been made invalid, error out
 	 */
 	if ((softc->flags & CD_FLAG_INVALID)) {
-		splx(s);
+		cam_periph_unlock(periph);
 		biofinish(bp, NULL, ENXIO);
 		return;
 	}
@@ -1455,7 +1397,7 @@
 
 		error = cdcheckmedia(periph);
 		if (error != 0) {
-			splx(s);
+			cam_periph_unlock(periph);
 			biofinish(bp, NULL, error);
 			return;
 		}
@@ -1466,8 +1408,6 @@
 	 */
 	bioq_disksort(&softc->bio_queue, bp);
 
-	splx(s);
-	
 	/*
 	 * Schedule ourselves for performing the work.  We do things
 	 * differently for changers.
@@ -1477,6 +1417,7 @@
 	else
 		cdschedule(periph, /* priority */ 1);
 
+	cam_periph_unlock(periph);
 	return;
 }
 
@@ -1487,7 +1428,6 @@
 	struct bio *bp;
 	struct ccb_scsiio *csio;
 	struct scsi_read_capacity_data *rcap;
-	int s;
 
 	softc = (struct cd_softc *)periph->softc;
 
@@ -1496,9 +1436,6 @@
 	switch (softc->state) {
 	case CD_STATE_NORMAL:
 	{
-		int oldspl;
-
-		s = splbio();
 		bp = bioq_first(&softc->bio_queue);
 		if (periph->immediate_priority <= periph->pinfo.priority) {
 			start_ccb->ccb_h.ccb_state = CD_CCB_WAITING;
@@ -1506,10 +1443,8 @@
 			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
 					  periph_links.sle);
 			periph->immediate_priority = CAM_PRIORITY_NONE;
-			splx(s);
 			wakeup(&periph->ccb_list);
 		} else if (bp == NULL) {
-			splx(s);
 			xpt_release_ccb(start_ccb);
 		} else {
 			bioq_remove(&softc->bio_queue, bp);
@@ -1533,15 +1468,9 @@
 			start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO;
 
 			
-			/*
-			 * Block out any asyncronous callbacks
-			 * while we touch the pending ccb list.
-			 */
-			oldspl = splcam();
 			LIST_INSERT_HEAD(&softc->pending_ccbs,
 					 &start_ccb->ccb_h, periph_links.le);
 			softc->outstanding_cmds++;
-			splx(oldspl);
 
 			/* We expect a unit attention from this device */
 			if ((softc->flags & CD_FLAG_RETRY_UA) != 0) {
@@ -1551,7 +1480,6 @@
 
 			start_ccb->ccb_h.ccb_bp = bp;
 			bp = bioq_first(&softc->bio_queue);
-			splx(s);
 
 			xpt_action(start_ccb);
 		}
@@ -1565,11 +1493,11 @@
 	{
 
 		rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap),
-								M_TEMP,
+								M_SCSICD,
 								M_NOWAIT);
 		if (rcap == NULL) {
-			xpt_print_path(periph->path);
-			printf("cdstart: Couldn't malloc read_capacity data\n");
+			xpt_print(periph->path,
+			    "cdstart: Couldn't malloc read_capacity data\n");
 			/* cd_free_periph??? */
 			break;
 		}
@@ -1605,7 +1533,6 @@
 	{
 		struct bio	*bp;
 		int		error;
-		int		oldspl;
 
 		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
 		error = 0;
@@ -1629,13 +1556,9 @@
 		}
 
 		if (error != 0) {
-			int s;
-
-			xpt_print_path(periph->path);
-			printf("cddone: got error %#x back\n", error);
-			s = splbio();
+			xpt_print(periph->path,
+			    "cddone: got error %#x back\n", error);
 			bioq_flush(&softc->bio_queue, NULL, EIO);
-			splx(s);
 			bp->bio_resid = bp->bio_bcount;
 			bp->bio_error = error;
 			bp->bio_flags |= BIO_ERROR;
@@ -1658,14 +1581,8 @@
 			}
 		}
 
-		/*
-		 * Block out any asyncronous callbacks
-		 * while we touch the pending ccb list.
-		 */
-		oldspl = splcam();
 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
 		softc->outstanding_cmds--;
-		splx(oldspl);
 
 		if (softc->flags & CD_FLAG_CHANGER)
 			cdchangerschedule(softc);
@@ -1813,14 +1730,12 @@
 						scsi_sense_print(
 							&done_ccb->csio);
 					else {
-						xpt_print_path(periph->path);
-						printf("got CAM status %#x\n",
-						       done_ccb->ccb_h.status);
+						xpt_print(periph->path,
+						    "got CAM status %#x\n",
+						    done_ccb->ccb_h.status);
 					}
-					xpt_print_path(periph->path);
-					printf("fatal error, failed" 
-					       " to attach to device\n");
-
+					xpt_print(periph->path, "fatal error, "
+					    "failed to attach to device\n");
 					/*
 					 * Invalidate this peripheral.
 					 */
@@ -1837,7 +1752,7 @@
 				}
 			}
 		}
-		free(rdcap, M_TEMP);
+		free(rdcap, M_SCSICD);
 		if (announce_buf[0] != '\0') {
 			xpt_announce_periph(periph, announce_buf);
 			if (softc->flags & CD_FLAG_CHANGER)
@@ -1858,7 +1773,7 @@
 		 * operation.
 		 */
 		xpt_release_ccb(done_ccb);
-		cam_periph_unlock(periph);
+		cam_periph_unhold(periph);
 		return;
 	}
 	case CD_CCB_WAITING:
@@ -1911,12 +1826,13 @@
 
 	struct 	cam_periph *periph;
 	struct	cd_softc *softc;
-	int	error, nocopyout;
+	int	nocopyout, error = 0;
 
 	periph = (struct cam_periph *)dp->d_drv1;
 	if (periph == NULL)
 		return(ENXIO);	
 
+	cam_periph_lock(periph);
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n"));
 
 	softc = (struct cd_softc *)periph->softc;
@@ -1924,10 +1840,12 @@
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 
 		  ("trying to do ioctl %#lx\n", cmd));
 
-	error = cam_periph_lock(periph, PRIBIO | PCATCH);
+	if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
+		return (error);
+	}
 
-	if (error != 0)
-		return(error);
 	/*
 	 * If we don't have media loaded, check for it.  If still don't
 	 * have media loaded, we can only do a load or eject.
@@ -1943,10 +1861,16 @@
 	 && (IOCGROUP(cmd) == 'c')) {
 		error = cdcheckmedia(periph);
 		if (error != 0) {
+			cam_periph_unhold(periph);
 			cam_periph_unlock(periph);
 			return (error);
 		}
 	}
+	/*
+	 * Drop the lock here so later mallocs can use WAITOK.  The periph
+	 * is essentially locked still with the cam_periph_hold call above.
+	 */
+	cam_periph_unlock(periph);
 
 	nocopyout = 0;
 	switch (cmd) {
@@ -1959,15 +1883,17 @@
 			union cd_pages *page;
 
 			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP,
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 						 M_WAITOK | M_ZERO);
 
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCPLAYTRACKS\n"));
 
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -1975,9 +1901,11 @@
 			page->audio.flags &= ~CD_PA_SOTC;
 			page->audio.flags |= CD_PA_IMMED;
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
-			if (error)
+			free(params.mode_buf, M_SCSICD);
+			if (error) {
+				cam_periph_unlock(periph);
 				break;
+			}
 
 			/*
 			 * This was originally implemented with the PLAY
@@ -2039,6 +1967,7 @@
 						     args->end_track,
 						     args->end_index);
 			}
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCPLAYMSF:
@@ -2049,15 +1978,17 @@
 			union cd_pages *page;
 
 			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP,
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 						 M_WAITOK | M_ZERO);
 
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCPLAYMSF\n"));
 
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2065,9 +1996,11 @@
 			page->audio.flags &= ~CD_PA_SOTC;
 			page->audio.flags |= CD_PA_IMMED;
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
-			if (error)
+			free(params.mode_buf, M_SCSICD);
+			if (error) {
+				cam_periph_unlock(periph);
 				break;
+			}
 			error = cdplaymsf(periph,
 					  args->start_m,
 					  args->start_s,
@@ -2075,6 +2008,7 @@
 					  args->end_m,
 					  args->end_s,
 					  args->end_f);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCPLAYBLOCKS:
@@ -2084,16 +2018,19 @@
 			struct cd_mode_params params;
 			union cd_pages *page;
 
+			params.alloc_len = sizeof(union cd_mode_data_6_10);
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD,
+						 M_WAITOK | M_ZERO);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCPLAYBLOCKS\n"));
 
-			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP,
-						 M_WAITOK | M_ZERO);
 
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2101,10 +2038,13 @@
 			page->audio.flags &= ~CD_PA_SOTC;
 			page->audio.flags |= CD_PA_IMMED;
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
-			if (error)
+			free(params.mode_buf, M_SCSICD);
+			if (error) {
+				cam_periph_unlock(periph);
 				break;
+			}
 			error = cdplay(periph, args->blk, args->len);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCREADSUBCHANNEL_SYSSPACE:
@@ -2117,12 +2057,13 @@
 			struct cd_sub_channel_info *data;
 			u_int32_t len = args->data_len;
 
+			data = malloc(sizeof(struct cd_sub_channel_info), 
+				      M_SCSICD, M_WAITOK);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCREADSUBCHANNEL\n"));
 
-			data = malloc(sizeof(struct cd_sub_channel_info), 
-				      M_TEMP, M_WAITOK);
-
 			if ((len > sizeof(struct cd_sub_channel_info)) ||
 			    (len < sizeof(struct cd_sub_channel_header))) {
 				printf(
@@ -2130,7 +2071,8 @@
 					"cdioreadsubchannel: error, len=%d\n",
 					len);
 				error = EINVAL;
-				free(data, M_TEMP);
+				free(data, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 
@@ -2141,7 +2083,8 @@
 				args->data_format, args->track, data, len);
 
 			if (error) {
-				free(data, M_TEMP);
+				free(data, M_SCSICD);
+				cam_periph_unlock(periph);
 	 			break;
 			}
 			if (softc->quirks & CD_Q_BCD_TRACKS)
@@ -2150,6 +2093,7 @@
 			len = min(len, ((data->header.data_len[0] << 8) +
 				data->header.data_len[1] +
 				sizeof(struct cd_sub_channel_header)));
+			cam_periph_unlock(periph);
 			if (nocopyout == 0) {
 				if (copyout(data, args->data, len) != 0) {
 					error = EFAULT;
@@ -2157,7 +2101,7 @@
 			} else {
 				bcopy(data, args->data, len);
 			}
-			free(data, M_TEMP);
+			free(data, M_SCSICD);
 		}
 		break;
 
@@ -2165,15 +2109,18 @@
 		{
 			struct ioc_toc_header *th;
 
+			th = malloc(sizeof(struct ioc_toc_header), M_SCSICD,
+				    M_WAITOK);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOREADTOCHEADER\n"));
 
-			th = malloc(sizeof(struct ioc_toc_header), M_TEMP,
-				    M_WAITOK);
 			error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, 
 				          sizeof (*th), /*sense_flags*/0);
 			if (error) {
-				free(th, M_TEMP);
+				free(th, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			if (softc->quirks & CD_Q_BCD_TRACKS) {
@@ -2186,7 +2133,8 @@
 			}
 			th->len = ntohs(th->len);
 			bcopy(th, addr, sizeof(*th));
-			free(th, M_TEMP);
+			free(th, M_SCSICD);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOREADTOCENTRYS:
@@ -2199,12 +2147,13 @@
 			u_int32_t len, readlen, idx, num;
 			u_int32_t starting_track = te->starting_track;
 
+			data = malloc(sizeof(*data), M_SCSICD, M_WAITOK);
+			lead = malloc(sizeof(*lead), M_SCSICD, M_WAITOK);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOREADTOCENTRYS\n"));
 
-			data = malloc(sizeof(*data), M_TEMP, M_WAITOK);
-			lead = malloc(sizeof(*lead), M_TEMP, M_WAITOK);
-
 			if (te->data_len < sizeof(struct cd_toc_entry)
 			 || (te->data_len % sizeof(struct cd_toc_entry)) != 0
 			 || (te->address_format != CD_MSF_FORMAT
@@ -2212,8 +2161,9 @@
 				error = EINVAL;
 				printf("scsi_cd: error in readtocentries, "
 				       "returning EINVAL\n");
-				free(data, M_TEMP);
-				free(lead, M_TEMP);
+				free(data, M_SCSICD);
+				free(lead, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 
@@ -2221,8 +2171,9 @@
 			error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, 
 					  sizeof (*th), /*sense_flags*/0);
 			if (error) {
-				free(data, M_TEMP);
-				free(lead, M_TEMP);
+				free(data, M_SCSICD);
+				free(lead, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 
@@ -2243,8 +2194,9 @@
 				 starting_track > th->ending_track + 1) {
 				printf("scsi_cd: error in readtocentries, "
 				       "returning EINVAL\n");
-				free(data, M_TEMP);
-				free(lead, M_TEMP);
+				free(data, M_SCSICD);
+				free(lead, M_SCSICD);
+				cam_periph_unlock(periph);
 				error = EINVAL;
 				break;
 			}
@@ -2264,8 +2216,9 @@
 				printf("scsi_cd: error in readtocentries, "
 				       "returning EINVAL\n");
 				error = EINVAL;
-				free(data, M_TEMP);
-				free(lead, M_TEMP);
+				free(data, M_SCSICD);
+				free(lead, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			num = len / sizeof(struct cd_toc_entry);
@@ -2277,8 +2230,9 @@
 						  readlen + sizeof (*th),
 						  /*sense_flags*/0);
 				if (error) {
-					free(data, M_TEMP);
-					free(lead, M_TEMP);
+					free(data, M_SCSICD);
+					free(lead, M_SCSICD);
+					cam_periph_unlock(periph);
 					break;
 				}
 			}
@@ -2293,8 +2247,9 @@
 						  sizeof(*lead),
 						  /*sense_flags*/0);
 				if (error) {
-					free(data, M_TEMP);
-					free(lead, M_TEMP);
+					free(data, M_SCSICD);
+					free(lead, M_SCSICD);
+					cam_periph_unlock(periph);
 					break;
 				}
 				data->entries[idx - starting_track] = 
@@ -2307,9 +2262,10 @@
 				}
 			}
 
+			cam_periph_unlock(periph);
 			error = copyout(data->entries, te->data, len);
-			free(data, M_TEMP);
-			free(lead, M_TEMP);
+			free(data, M_SCSICD);
+			free(lead, M_SCSICD);
 		}
 		break;
 	case CDIOREADTOCENTRY:
@@ -2320,17 +2276,19 @@
 			struct ioc_toc_header *th;
 			u_int32_t track;
 
+			data = malloc(sizeof(*data), M_SCSICD, M_WAITOK);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOREADTOCENTRY\n"));
 
-			data = malloc(sizeof(*data), M_TEMP, M_WAITOK);
-
 			if (te->address_format != CD_MSF_FORMAT
 			    && te->address_format != CD_LBA_FORMAT) {
 				printf("error in readtocentry, "
 				       " returning EINVAL\n");
-				free(data, M_TEMP);
+				free(data, M_SCSICD);
 				error = EINVAL;
+				cam_periph_unlock(periph);
 				break;
 			}
 
@@ -2338,7 +2296,8 @@
 			error = cdreadtoc(periph, 0, 0, (u_int8_t *)th,
 					  sizeof (*th), /*sense_flags*/0);
 			if (error) {
-				free(data, M_TEMP);
+				free(data, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 
@@ -2359,8 +2318,9 @@
 				 track > th->ending_track + 1) {
 				printf("error in readtocentry, "
 				       " returning EINVAL\n");
-				free(data, M_TEMP);
+				free(data, M_SCSICD);
 				error = EINVAL;
+				cam_periph_unlock(periph);
 				break;
 			}
 
@@ -2368,7 +2328,8 @@
 					  (u_int8_t *)data, sizeof(*data),
 					  /*sense_flags*/0);
 			if (error) {
-				free(data, M_TEMP);
+				free(data, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 
@@ -2376,7 +2337,8 @@
 				data->entry.track = bcd2bin(data->entry.track);
 			bcopy(&data->entry, &te->entry,
 			      sizeof(struct cd_toc_entry));
-			free(data, M_TEMP);
+			free(data, M_SCSICD);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCSETPATCH:
@@ -2385,15 +2347,18 @@
 			struct cd_mode_params params;
 			union cd_pages *page;
 
+			params.alloc_len = sizeof(union cd_mode_data_6_10);
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD, 
+						 M_WAITOK | M_ZERO);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCSETPATCH\n"));
 
-			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP, 
-						 M_WAITOK | M_ZERO);
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2405,7 +2370,8 @@
 			page->audio.port[2].channels = arg->patch[2];
 			page->audio.port[3].channels = arg->patch[3];
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
+			free(params.mode_buf, M_SCSICD);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCGETVOL:
@@ -2414,15 +2380,18 @@
 			struct cd_mode_params params;
 			union cd_pages *page;
 
+			params.alloc_len = sizeof(union cd_mode_data_6_10);
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD, 
+						 M_WAITOK | M_ZERO);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCGETVOL\n"));
 
-			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP, 
-						 M_WAITOK | M_ZERO);
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2433,7 +2402,8 @@
 				page->audio.port[RIGHT_PORT].volume;
 			arg->vol[2] = page->audio.port[2].volume;
 			arg->vol[3] = page->audio.port[3].volume;
-			free(params.mode_buf, M_TEMP);
+			free(params.mode_buf, M_SCSICD);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCSETVOL:
@@ -2442,15 +2412,18 @@
 			struct cd_mode_params params;
 			union cd_pages *page;
 
+			params.alloc_len = sizeof(union cd_mode_data_6_10);
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD, 
+						 M_WAITOK | M_ZERO);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCSETVOL\n"));
 
-			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP, 
-						 M_WAITOK | M_ZERO);
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2464,7 +2437,8 @@
 			page->audio.port[2].volume = arg->vol[2];
 			page->audio.port[3].volume = arg->vol[3];
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
+			cam_periph_unlock(periph);
+			free(params.mode_buf, M_SCSICD);
 		}
 		break;
 	case CDIOCSETMONO:
@@ -2472,15 +2446,18 @@
 			struct cd_mode_params params;
 			union cd_pages *page;
 
+			params.alloc_len = sizeof(union cd_mode_data_6_10);
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD,
+						 M_WAITOK | M_ZERO);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCSETMONO\n"));
 
-			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP,
-						 M_WAITOK | M_ZERO);
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2492,7 +2469,8 @@
 			page->audio.port[2].channels = 0;
 			page->audio.port[3].channels = 0;
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
+			cam_periph_unlock(periph);
+			free(params.mode_buf, M_SCSICD);
 		}
 		break;
 	case CDIOCSETSTEREO:
@@ -2500,15 +2478,18 @@
 			struct cd_mode_params params;
 			union cd_pages *page;
 
+			params.alloc_len = sizeof(union cd_mode_data_6_10);
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD,
+						 M_WAITOK | M_ZERO);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCSETSTEREO\n"));
 
-			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP,
-						 M_WAITOK | M_ZERO);
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2520,7 +2501,8 @@
 			page->audio.port[2].channels = 0;
 			page->audio.port[3].channels = 0;
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
+			free(params.mode_buf, M_SCSICD);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCSETMUTE:
@@ -2528,15 +2510,18 @@
 			struct cd_mode_params params;
 			union cd_pages *page;
 
+			params.alloc_len = sizeof(union cd_mode_data_6_10);
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD,
+						 M_WAITOK | M_ZERO);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCSETMUTE\n"));
 
-			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP,
-						 M_WAITOK | M_ZERO);
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(&params, M_TEMP);
+				free(&params, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2546,7 +2531,8 @@
 			page->audio.port[2].channels = 0;
 			page->audio.port[3].channels = 0;
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
+			free(params.mode_buf, M_SCSICD);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCSETLEFT:
@@ -2554,16 +2540,18 @@
 			struct cd_mode_params params;
 			union cd_pages *page;
 
+			params.alloc_len = sizeof(union cd_mode_data_6_10);
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD,
+						 M_WAITOK | M_ZERO);
+
+			cam_periph_lock(periph);
 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 				  ("trying to do CDIOCSETLEFT\n"));
 
-			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP,
-						 M_WAITOK | M_ZERO);
-			
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2573,7 +2561,8 @@
 			page->audio.port[2].channels = 0;
 			page->audio.port[3].channels = 0;
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
+			free(params.mode_buf, M_SCSICD);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCSETRIGHT:
@@ -2581,16 +2570,18 @@
 			struct cd_mode_params params;
 			union cd_pages *page;
 
-			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
-				  ("trying to do CDIOCSETRIGHT\n"));
-
 			params.alloc_len = sizeof(union cd_mode_data_6_10);
-			params.mode_buf = malloc(params.alloc_len, M_TEMP,
+			params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 						 M_WAITOK | M_ZERO);
 
+			cam_periph_lock(periph);
+			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
+				  ("trying to do CDIOCSETRIGHT\n"));
+
 			error = cdgetmode(periph, &params, AUDIO_PAGE);
 			if (error) {
-				free(params.mode_buf, M_TEMP);
+				free(params.mode_buf, M_SCSICD);
+				cam_periph_unlock(periph);
 				break;
 			}
 			page = cdgetpage(&params);
@@ -2600,32 +2591,49 @@
 			page->audio.port[2].channels = 0;
 			page->audio.port[3].channels = 0;
 			error = cdsetmode(periph, &params);
-			free(params.mode_buf, M_TEMP);
+			free(params.mode_buf, M_SCSICD);
+			cam_periph_unlock(periph);
 		}
 		break;
 	case CDIOCRESUME:
+		cam_periph_lock(periph);
 		error = cdpause(periph, 1);
+		cam_periph_unlock(periph);
 		break;
 	case CDIOCPAUSE:
+		cam_periph_lock(periph);
 		error = cdpause(periph, 0);
+		cam_periph_unlock(periph);
 		break;
 	case CDIOCSTART:
+		cam_periph_lock(periph);
 		error = cdstartunit(periph, 0);
+		cam_periph_unlock(periph);
 		break;
 	case CDIOCCLOSE:
+		cam_periph_lock(periph);
 		error = cdstartunit(periph, 1);
+		cam_periph_unlock(periph);
 		break;
 	case CDIOCSTOP:
+		cam_periph_lock(periph);
 		error = cdstopunit(periph, 0);
+		cam_periph_unlock(periph);
 		break;
 	case CDIOCEJECT:
+		cam_periph_lock(periph);
 		error = cdstopunit(periph, 1);
+		cam_periph_unlock(periph);
 		break;
 	case CDIOCALLOW:
+		cam_periph_lock(periph);
 		cdprevent(periph, PR_ALLOW);
+		cam_periph_unlock(periph);
 		break;
 	case CDIOCPREVENT:
+		cam_periph_lock(periph);
 		cdprevent(periph, PR_PREVENT);
+		cam_periph_unlock(periph);
 		break;
 	case CDIOCSETDEBUG:
 		/* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */
@@ -2640,10 +2648,14 @@
 		error = ENOTTY;
 		break;
 	case CDRIOCREADSPEED:
+		cam_periph_lock(periph);
 		error = cdsetspeed(periph, *(u_int32_t *)addr, CDR_MAX_SPEED);
+		cam_periph_unlock(periph);
 		break;
 	case CDRIOCWRITESPEED:
+		cam_periph_lock(periph);
 		error = cdsetspeed(periph, CDR_MAX_SPEED, *(u_int32_t *)addr);
+		cam_periph_unlock(periph);
 		break;
 	case DVDIOCSENDKEY:
 	case DVDIOCREPORTKEY: {
@@ -2651,10 +2663,12 @@
 
 		authinfo = (struct dvd_authinfo *)addr;
 
+		cam_periph_lock(periph);
 		if (cmd == DVDIOCREPORTKEY)
 			error = cdreportkey(periph, authinfo);
 		else
 			error = cdsendkey(periph, authinfo);
+		cam_periph_unlock(periph);
 		break;
 		}
 	case DVDIOCREADSTRUCTURE: {
@@ -2662,21 +2676,27 @@
 
 		dvdstruct = (struct dvd_struct *)addr;
 
+		cam_periph_lock(periph);
 		error = cdreaddvdstructure(periph, dvdstruct);
+		cam_periph_unlock(periph);
 
 		break;
 	}
 	default:
+		cam_periph_lock(periph);
 		error = cam_periph_ioctl(periph, cmd, addr, cderror);
+		cam_periph_unlock(periph);
 		break;
 	}
 
-	cam_periph_unlock(periph);
-
+	cam_periph_lock(periph);
+	cam_periph_unhold(periph);
+	
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n"));
 	if (error && bootverbose) {
 		printf("scsi_cd.c::ioctl cmd=%08lx error=%d\n", cmd, error);
 	}
+	cam_periph_unlock(periph);
 
 	return (error);
 }
@@ -2875,8 +2895,11 @@
              
 	ccb = cdgetccb(periph, /* priority */ 1);
 
+	/* XXX Should be M_WAITOK */
 	rcap_buf = malloc(sizeof(struct scsi_read_capacity_data), 
-			  M_TEMP, M_WAITOK);
+			  M_SCSICD, M_NOWAIT);
+	if (rcap_buf == NULL)
+		return (ENOMEM);
 
 	scsi_read_capacity(&ccb->csio, 
 			   /*retries*/ 1,
@@ -2904,7 +2927,7 @@
 	if (softc->params.blksize > 2048 && softc->params.blksize <= 2352)
 		softc->params.blksize = 2048;
 
-	free(rcap_buf, M_TEMP);
+	free(rcap_buf, M_SCSICD);
 	*size = softc->params.disksize;
 
 	return (error);
@@ -2955,16 +2978,16 @@
 	 * cdsetmode()!
 	 */
 	if (found == 0) {
-		xpt_print_path(periph->path);
-		printf("mode buffer not found in mode queue!\n");
+		xpt_print(periph->path,
+		    "mode buffer not found in mode queue!\n");
 		return (0);
 	}
 
 	params->cdb_size = 10;
 	softc->minimum_command_size = 10;
-	xpt_print_path(ccb->ccb_h.path);
-	printf("%s(6) failed, increasing minimum CDB size to 10 bytes\n",
-	       (cdb[0] == MODE_SENSE_6) ? "MODE_SENSE" : "MODE_SELECT");
+	xpt_print(ccb->ccb_h.path,
+	    "%s(6) failed, increasing minimum CDB size to 10 bytes\n",
+	    (cdb[0] == MODE_SENSE_6) ? "MODE_SENSE" : "MODE_SELECT");
 
 	if (cdb[0] == MODE_SENSE_6) {
 		struct scsi_mode_sense_10 ms10;
@@ -3296,10 +3319,9 @@
 		 * the data length incorrectly.
 		 */
 		if (data_len > data->alloc_len) {
-			xpt_print_path(periph->path);
-			printf("allocated modepage %d length %d < returned "
-			       "length %d\n", page, data->alloc_len, data_len);
-
+			xpt_print(periph->path, "allocated modepage %d length "
+			    "%d < returned length %d\n", page, data->alloc_len,
+			    data_len);
 			error = ENOSPC;
 		}
 	}
@@ -3757,9 +3779,8 @@
 		goto bailout;
 
 	if (ccb->csio.resid != 0) {
-		xpt_print_path(periph->path);
-		printf("warning, residual for report key command is %d\n",
-		       ccb->csio.resid);
+		xpt_print(periph->path, "warning, residual for report key "
+		    "command is %d\n", ccb->csio.resid);
 	}
 
 	switch(authinfo->format) {
Index: scsi_target.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_target.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/scsi/scsi_target.c -L sys/cam/scsi/scsi_target.c -u -r1.1.1.1 -r1.2
--- sys/cam/scsi/scsi_target.c
+++ sys/cam/scsi/scsi_target.c
@@ -28,7 +28,8 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_target.c,v 1.67.2.1 2005/08/13 21:24:15 rwatson Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_target.c,v 1.73 2007/04/15 08:49:11 scottl Exp $");
+
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -40,11 +41,13 @@
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/devicestat.h>
+#include <sys/proc.h>
 
 #include <cam/cam.h>
 #include <cam/cam_ccb.h>
 #include <cam/cam_periph.h>
 #include <cam/cam_xpt_periph.h>
+#include <cam/cam_sim.h>
 #include <cam/scsi/scsi_targetio.h>
 
 /* Transaction information attached to each CCB sent by the user */
@@ -89,7 +92,6 @@
 	targ_state		 state;
 	struct selinfo		 read_select;
 	struct devstat		 device_stats;
-	struct mtx		 mtx;
 };
 
 static d_open_t		targopen;
@@ -157,27 +159,24 @@
 };
 PERIPHDRIVER_DECLARE(targ, targdriver);
 
-static struct mtx		targ_mtx;
-#define TARG_LOCK(softc)	mtx_lock(&(softc)->mtx)
-#define TARG_UNLOCK(softc)	mtx_unlock(&(softc)->mtx)
-
 static MALLOC_DEFINE(M_TARG, "TARG", "TARG data");
 
-/* Create softc and initialize it. Only one proc can open each targ device. */
+/*
+ * Create softc and initialize it. Only one proc can open each targ device.
+ * There is no locking here because a periph doesn't get created until an
+ * ioctl is issued to do so, and that can't happen until this method returns.
+ */
 static int
 targopen(struct cdev *dev, int flags, int fmt, struct thread *td)
 {
 	struct targ_softc *softc;
 
-	mtx_lock(&targ_mtx);
 	if (dev->si_drv1 != 0) {
-		mtx_unlock(&targ_mtx);
 		return (EBUSY);
 	}
 	
 	/* Mark device busy before any potentially blocking operations */
 	dev->si_drv1 = (void *)~0;
-	mtx_unlock(&targ_mtx);
 
 	/* Create the targ device, allocate its softc, initialize it */
 	if ((dev->si_flags & SI_NAMED) == 0) {
@@ -190,13 +189,12 @@
 	softc->state = TARG_STATE_OPENED;
 	softc->periph = NULL;
 	softc->path = NULL;
-	mtx_init(&softc->mtx, devtoname(dev), "targ cdev", MTX_DEF);
 
 	TAILQ_INIT(&softc->pending_ccb_queue);
 	TAILQ_INIT(&softc->work_queue);
 	TAILQ_INIT(&softc->abort_queue);
 	TAILQ_INIT(&softc->user_ccb_queue);
-	knlist_init(&softc->read_select.si_note, &softc->mtx, NULL, NULL, NULL);
+	knlist_init(&softc->read_select.si_note, NULL, NULL, NULL, NULL);
 
 	return (0);
 }
@@ -206,26 +204,37 @@
 targclose(struct cdev *dev, int flag, int fmt, struct thread *td)
 {
 	struct targ_softc     *softc;
+	struct cam_periph     *periph;
 	int    error;
 
 	softc = (struct targ_softc *)dev->si_drv1;
-	TARG_LOCK(softc);
+	if ((softc->periph == NULL) ||
+	    (softc->state & TARG_STATE_LUN_ENABLED) == 0) {
+		destroy_dev(dev);
+		FREE(softc, M_TARG);
+		return (0);
+	}
+
+	/*
+	 * Acquire a hold on the periph so that it doesn't go away before
+	 * we are ready at the end of the function.
+	 */
+	periph = softc->periph;
+	cam_periph_acquire(periph);
+	cam_periph_lock(periph);
 	error = targdisable(softc);
 	if (error == CAM_REQ_CMP) {
 		dev->si_drv1 = 0;
-		mtx_lock(&targ_mtx);
 		if (softc->periph != NULL) {
 			cam_periph_invalidate(softc->periph);
 			softc->periph = NULL;
 		}
-		mtx_unlock(&targ_mtx);
-		TARG_UNLOCK(softc);
-		mtx_destroy(&softc->mtx);
 		destroy_dev(dev);
 		FREE(softc, M_TARG);
-	} else {
-		TARG_UNLOCK(softc);
 	}
+	cam_periph_unlock(periph);
+	cam_periph_release(periph);
+
 	return (error);
 }
 
@@ -243,51 +252,56 @@
 	{
 		struct ioc_enable_lun	*new_lun;
 		struct cam_path		*path;
+		struct cam_sim		*sim;
 
 		new_lun = (struct ioc_enable_lun *)addr;
-		status = xpt_create_path(&path, /*periph*/NULL,
-					 new_lun->path_id,
-					 new_lun->target_id,
-					 new_lun->lun_id);
+		status = xpt_create_path_unlocked(&path, /*periph*/NULL,
+						  new_lun->path_id,
+						  new_lun->target_id,
+						  new_lun->lun_id);
 		if (status != CAM_REQ_CMP) {
 			printf("Couldn't create path, status %#x\n", status);
 			break;
 		}
-		TARG_LOCK(softc);
+		sim = xpt_path_sim(path);
+		mtx_lock(sim->mtx);
 		status = targenable(softc, path, new_lun->grp6_len,
 				    new_lun->grp7_len);
-		TARG_UNLOCK(softc);
 		xpt_free_path(path);
+		mtx_unlock(sim->mtx);
 		break;
 	}
 	case TARGIOCDISABLE:
-		TARG_LOCK(softc);
+		if (softc->periph == NULL) {
+			status = CAM_DEV_NOT_THERE;
+			break;
+		}
+		cam_periph_lock(softc->periph);
 		status = targdisable(softc);
-		TARG_UNLOCK(softc);
+		cam_periph_unlock(softc->periph);
 		break;
 	case TARGIOCDEBUG:
 	{
 #ifdef	CAMDEBUG
 		struct ccb_debug cdbg;
 
+		/* If no periph available, disallow debugging changes */
+		if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
+			status = CAM_DEV_NOT_THERE;
+			break;
+		}
 		bzero(&cdbg, sizeof cdbg);
 		if (*((int *)addr) != 0)
 			cdbg.flags = CAM_DEBUG_PERIPH;
 		else
 			cdbg.flags = CAM_DEBUG_NONE;
+		cam_periph_lock(softc->periph);
 		xpt_setup_ccb(&cdbg.ccb_h, softc->path, /*priority*/0);
 		cdbg.ccb_h.func_code = XPT_DEBUG;
 		cdbg.ccb_h.cbfcnp = targdone;
 
-		/* If no periph available, disallow debugging changes */
-		TARG_LOCK(softc);
-		if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
-			status = CAM_DEV_NOT_THERE;
-			TARG_UNLOCK(softc);
-			break;
-		}
 		xpt_action((union ccb *)&cdbg);
-		TARG_UNLOCK(softc);
+		cam_periph_unlock(softc->periph);
 		status = cdbg.ccb_h.status & CAM_STATUS_MASK;
 #else
 		status = CAM_FUNC_NOTAVAIL;
@@ -315,15 +329,15 @@
 	revents = poll_events & (POLLOUT | POLLWRNORM);
 	if ((poll_events & (POLLIN | POLLRDNORM)) != 0) {
 		/* Poll for read() depends on user and abort queues. */
-		TARG_LOCK(softc);
+		cam_periph_lock(softc->periph);
 		if (!TAILQ_EMPTY(&softc->user_ccb_queue) ||
 		    !TAILQ_EMPTY(&softc->abort_queue)) {
 			revents |= poll_events & (POLLIN | POLLRDNORM);
 		}
+		cam_periph_unlock(softc->periph);
 		/* Only sleep if the user didn't poll for write. */
 		if (revents == 0)
 			selrecord(td, &softc->read_select);
-		TARG_UNLOCK(softc);
 	}
 
 	return (revents);
@@ -358,8 +372,10 @@
 	int	retval;
 
 	softc = (struct targ_softc *)kn->kn_hook;
+	cam_periph_lock(softc->periph);
 	retval = !TAILQ_EMPTY(&softc->user_ccb_queue) ||
 		 !TAILQ_EMPTY(&softc->abort_queue);
+	cam_periph_unlock(softc->periph);
 	return (retval);
 }
 
@@ -380,9 +396,8 @@
 	xpt_action((union ccb *)&en_ccb);
 	status = en_ccb.ccb_h.status & CAM_STATUS_MASK;
 	if (status != CAM_REQ_CMP) {
-		xpt_print_path(path);
-		printf("%sable lun CCB rejected, status %#x\n",
-		       enable ? "en" : "dis", status);
+		xpt_print(path, "%sable lun CCB rejected, status %#x\n",
+		    enable ? "en" : "dis", status);
 	}
 	return (status);
 }
@@ -415,7 +430,6 @@
 	}
 
 	/* Destroy any periph on our path if it is disabled */
-	mtx_lock(&targ_mtx);
 	periph = cam_periph_find(path, "targ");
 	if (periph != NULL) {
 		struct targ_softc *del_softc;
@@ -427,7 +441,6 @@
 		} else {
 			printf("Requested path still in use by targ%d\n",
 			       periph->unit_number);
-			mtx_unlock(&targ_mtx);
 			status = CAM_LUN_ALRDY_ENA;
 			goto enable_fail;
 		}
@@ -436,7 +449,6 @@
 	/* Create a periph instance attached to this path */
 	status = cam_periph_alloc(targctor, NULL, targdtor, targstart,
 			"targ", CAM_PERIPH_BIO, path, targasync, 0, softc);
-	mtx_unlock(&targ_mtx);
 	if (status != CAM_REQ_CMP) {
 		printf("cam_periph_alloc failed, status %#x\n", status);
 		goto enable_fail;
@@ -559,6 +571,7 @@
 		switch (func_code) {
 		case XPT_ACCEPT_TARGET_IO:
 		case XPT_IMMED_NOTIFY:
+			cam_periph_lock(softc->periph);
 			ccb = targgetccb(softc, func_code, priority);
 			descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
 			descr->user_ccb = user_ccb;
@@ -566,13 +579,13 @@
 			CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
 				  ("Sent ATIO/INOT (%p)\n", user_ccb));
 			xpt_action(ccb);
-			TARG_LOCK(softc);
 			TAILQ_INSERT_TAIL(&softc->pending_ccb_queue,
 					  &ccb->ccb_h,
 					  periph_links.tqe);
-			TARG_UNLOCK(softc);
+			cam_periph_unlock(softc->periph);
 			break;
 		default:
+			cam_periph_lock(softc->periph);
 			if ((func_code & XPT_FC_QUEUED) != 0) {
 				CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
 					  ("Sending queued ccb %#x (%p)\n",
@@ -581,10 +594,8 @@
 				descr->user_ccb = user_ccb;
 				descr->priority = priority;
 				descr->func_code = func_code;
-				TARG_LOCK(softc);
 				TAILQ_INSERT_TAIL(&softc->work_queue,
 						  descr, tqe);
-				TARG_UNLOCK(softc);
 				xpt_schedule(softc->periph, priority);
 			} else {
 				CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
@@ -600,6 +611,7 @@
 					targsendccb(softc, ccb, descr);
 				targreturnccb(softc, ccb);
 			}
+			cam_periph_unlock(softc->periph);
 			break;
 		}
 		write_len += sizeof(user_ccb);
@@ -629,29 +641,24 @@
 	softc = (struct targ_softc *)periph->softc;
 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targstart %p\n", start_ccb));
 
-	TARG_LOCK(softc);
 	descr = TAILQ_FIRST(&softc->work_queue);
 	if (descr == NULL) {
-		TARG_UNLOCK(softc);
 		xpt_release_ccb(start_ccb);
 	} else {
 		TAILQ_REMOVE(&softc->work_queue, descr, tqe);
 		next_descr = TAILQ_FIRST(&softc->work_queue);
-		TARG_UNLOCK(softc);
 
 		/* Initiate a transaction using the descr and supplied CCB */
 		error = targusermerge(softc, descr, start_ccb);
 		if (error == 0)
 			error = targsendccb(softc, start_ccb, descr);
 		if (error != 0) {
-			xpt_print_path(periph->path);
-			printf("targsendccb failed, err %d\n", error);
+			xpt_print(periph->path,
+			    "targsendccb failed, err %d\n", error);
 			xpt_release_ccb(start_ccb);
 			suword(&descr->user_ccb->ccb_h.status,
 			       CAM_REQ_CMP_ERR);
-			TARG_LOCK(softc);
 			TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
-			TARG_UNLOCK(softc);
 			notify_user(softc);
 		}
 
@@ -694,7 +701,6 @@
 		struct ccb_hdr *ccb_h;
 
 		cab = (struct ccb_abort *)ccb;
-		TARG_LOCK(softc);
 		TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue,
 		    periph_links.tqe) {
 			struct targ_cmd_descr *ab_descr;
@@ -708,7 +714,6 @@
 				break;
 			}
 		}
-		TARG_UNLOCK(softc);
 		/* CCB not found, set appropriate status */
 		if (ccb_h == NULL) {
 			k_ccbh->status = CAM_PATH_INVALID;
@@ -776,10 +781,8 @@
 	 */
 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("sendccb %p\n", ccb));
 	if (XPT_FC_IS_QUEUED(ccb)) {
-		TARG_LOCK(softc);
 		TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, ccb_h,
 				  periph_links.tqe);
-		TARG_UNLOCK(softc);
 	}
 	xpt_action(ccb);
 
@@ -795,7 +798,6 @@
 
 	CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("targdone %p\n", done_ccb));
 	softc = (struct targ_softc *)periph->softc;
-	TARG_LOCK(softc);
 	TAILQ_REMOVE(&softc->pending_ccb_queue, &done_ccb->ccb_h,
 		     periph_links.tqe);
 	status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
@@ -803,7 +805,6 @@
 	/* If we're no longer enabled, throw away CCB */
 	if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
 		targfreeccb(softc, done_ccb);
-		TARG_UNLOCK(softc);
 		return;
 	}
 	/* abort_all_pending() waits for pending queue to be empty */
@@ -817,7 +818,6 @@
 	case XPT_CONT_TARGET_IO:
 		TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h,
 				  periph_links.tqe);
-		TARG_UNLOCK(softc);
 		notify_user(softc);
 		break;
 	default:
@@ -847,25 +847,24 @@
 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n"));
 
 	/* If no data is available, wait or return immediately */
-	TARG_LOCK(softc);
+	cam_periph_lock(softc->periph);
 	ccb_h = TAILQ_FIRST(user_queue);
 	user_descr = TAILQ_FIRST(abort_queue);
 	while (ccb_h == NULL && user_descr == NULL) {
 		if ((ioflag & IO_NDELAY) == 0) {
-			error = msleep(user_queue, &softc->mtx,
-				       PRIBIO | PCATCH, "targrd", 0);
+			error = msleep(user_queue, softc->periph->sim->mtx,
+			    PRIBIO | PCATCH, "targrd", 0);
 			ccb_h = TAILQ_FIRST(user_queue);
 			user_descr = TAILQ_FIRST(abort_queue);
 			if (error != 0) {
 				if (error == ERESTART) {
 					continue;
 				} else {
-					TARG_UNLOCK(softc);
 					goto read_fail;
 				}
 			}
 		} else {
-			TARG_UNLOCK(softc);
+			cam_periph_unlock(softc->periph);
 			return (EAGAIN);
 		}
 	}
@@ -877,7 +876,6 @@
 		if (uio->uio_resid < sizeof(user_ccb))
 			break;
 		TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe);
-		TARG_UNLOCK(softc);
 		descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
 		user_ccb = descr->user_ccb;
 		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
@@ -885,12 +883,13 @@
 		error = targreturnccb(softc, (union ccb *)ccb_h);
 		if (error != 0)
 			goto read_fail;
+		cam_periph_unlock(softc->periph);
 		error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
+		cam_periph_lock(softc->periph);
 		if (error != 0)
 			goto read_fail;
 		read_len += sizeof(user_ccb);
 
-		TARG_LOCK(softc);
 		ccb_h = TAILQ_FIRST(user_queue);
 	}
 
@@ -899,21 +898,20 @@
 		if (uio->uio_resid < sizeof(user_ccb))
 			break;
 		TAILQ_REMOVE(abort_queue, user_descr, tqe);
-		TARG_UNLOCK(softc);
 		user_ccb = user_descr->user_ccb;
 		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
 			  ("targread aborted descr %p (%p)\n",
 			  user_descr, user_ccb));
 		suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED);
+		cam_periph_unlock(softc->periph);
 		error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
+		cam_periph_lock(softc->periph);
 		if (error != 0)
 			goto read_fail;
 		read_len += sizeof(user_ccb);
 
-		TARG_LOCK(softc);
 		user_descr = TAILQ_FIRST(abort_queue);
 	}
-	TARG_UNLOCK(softc);
 
 	/*
 	 * If we've successfully read some amount of data, don't report an
@@ -924,6 +922,7 @@
 		error = ENOSPC;
 
 read_fail:
+	cam_periph_unlock(softc->periph);
 	return (error);
 }
 
@@ -951,9 +950,8 @@
 		cam_periph_unmapmem(ccb, &descr->mapinfo);
 	error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len);
 	if (error != 0) {
-		xpt_print_path(softc->path);
-		printf("targreturnccb - CCB copyout failed (%d)\n",
-		       error);
+		xpt_print(softc->path,
+		    "targreturnccb - CCB copyout failed (%d)\n", error);
 	}
 	/* Free CCB or send back to devq. */
 	targfreeccb(softc, ccb);
@@ -1020,7 +1018,6 @@
 static void
 targinit(void)
 {
-	mtx_init(&targ_mtx, "targ global", NULL, MTX_DEF);
 	EVENTHANDLER_REGISTER(dev_clone, targclone, 0, 1000);
 }
 
@@ -1054,6 +1051,7 @@
 	struct targ_cmd_descr   *descr;
 	struct ccb_abort	 cab;
 	struct ccb_hdr		*ccb_h;
+	struct cam_sim		*sim;
 
 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n"));
 
@@ -1078,15 +1076,16 @@
 		cab.abort_ccb = (union ccb *)ccb_h;
 		xpt_action((union ccb *)&cab);
 		if (cab.ccb_h.status != CAM_REQ_CMP) {
-			xpt_print_path(cab.ccb_h.path);
-			printf("Unable to abort CCB, status %#x\n",
-			       cab.ccb_h.status);
+			xpt_print(cab.ccb_h.path,
+			    "Unable to abort CCB, status %#x\n",
+			    cab.ccb_h.status);
 		}
 	}
 
 	/* If we aborted at least one pending CCB ok, wait for it. */
 	if (cab.ccb_h.status == CAM_REQ_CMP) {
-		msleep(&softc->pending_ccb_queue, &softc->mtx,
+		sim = xpt_path_sim(softc->path);
+		msleep(&softc->pending_ccb_queue, sim->mtx,
 		       PRIBIO | PCATCH, "tgabrt", 0);
 	}
 
@@ -1105,7 +1104,7 @@
 	 * blocking read().
 	 */
 	selwakeuppri(&softc->read_select, PRIBIO);
-	KNOTE_LOCKED(&softc->read_select.si_note, 0);
+	KNOTE_UNLOCKED(&softc->read_select.si_note, 0);
 	wakeup(&softc->user_ccb_queue);
 }
 
Index: scsi_all.h
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_all.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/cam/scsi/scsi_all.h -L sys/cam/scsi/scsi_all.h -u -r1.2 -r1.3
--- sys/cam/scsi/scsi_all.h
+++ sys/cam/scsi/scsi_all.h
@@ -14,7 +14,7 @@
  *
  * Ported to run under 386BSD by Julian Elischer (julian at tfs.com) Sept 1992
  *
- * $FreeBSD: src/sys/cam/scsi/scsi_all.h,v 1.24.2.2 2006/09/09 07:21:18 ken Exp $
+ * $FreeBSD: src/sys/cam/scsi/scsi_all.h,v 1.28.2.1 2007/11/15 16:27:59 scottl Exp $
  */
 
 /*
@@ -170,8 +170,11 @@
 #define	SMS_PAGE_CODE 			0x3F
 #define SMS_VENDOR_SPECIFIC_PAGE	0x00
 #define SMS_DISCONNECT_RECONNECT_PAGE	0x02
+#define SMS_CACHE_PAGE			0x08
 #define SMS_PERIPHERAL_DEVICE_PAGE	0x09
 #define SMS_CONTROL_MODE_PAGE		0x0A
+#define SMS_PROTO_SPECIFIC_PAGE		0x19
+#define SMS_INFO_EXCEPTIONS_PAGE	0x1C
 #define SMS_ALL_PAGES_PAGE		0x3F
 #define	SMS_PAGE_CTRL_MASK		0xC0
 #define	SMS_PAGE_CTRL_CURRENT 		0x00
@@ -257,6 +260,8 @@
 #define	SLS_ERROR_VERIFY_PAGE		0x05
 #define	SLS_ERROR_NONMEDIUM_PAGE	0x06
 #define	SLS_ERROR_LASTN_PAGE		0x07
+#define SLS_SELF_TEST_PAGE		0x10
+#define SLS_IE_PAGE			0x2f
 #define	SLS_PAGE_CTRL_MASK		0xC0
 #define	SLS_PAGE_CTRL_THRESHOLD		0x00
 #define	SLS_PAGE_CTRL_CUMULATIVE	0x40
@@ -329,6 +334,55 @@
 	u_int8_t aen_holdoff_period[2];
 };
 
+struct scsi_cache_page {
+	u_int8_t page_code;
+#define SCHP_PAGE_SAVABLE		0x80	/* Page is savable */
+	u_int8_t page_length;
+	u_int8_t cache_flags;
+#define SCHP_FLAGS_WCE			0x04	/* Write Cache Enable */
+#define SCHP_FLAGS_MF			0x02	/* Multiplication factor */
+#define SCHP_FLAGS_RCD			0x01	/* Read Cache Disable */
+	u_int8_t rw_cache_policy;
+	u_int8_t dis_prefetch[2];
+	u_int8_t min_prefetch[2];
+	u_int8_t max_prefetch[2];
+	u_int8_t max_prefetch_ceil[2];
+};
+
+struct scsi_info_exceptions_page {
+	u_int8_t page_code;
+#define SIEP_PAGE_SAVABLE		0x80	/* Page is savable */
+	u_int8_t page_length;
+	u_int8_t info_flags;
+#define SIEP_FLAGS_PERF			0x80
+#define SIEP_FLAGS_EBF			0x20
+#define SIEP_FLAGS_EWASC		0x10
+#define SIEP_FLAGS_DEXCPT		0x08
+#define SIEP_FLAGS_TEST			0x04
+#define SIEP_FLAGS_EBACKERR		0x02
+#define SIEP_FLAGS_LOGERR		0x01
+	u_int8_t mrie;
+	u_int8_t interval_timer[4];
+	u_int8_t report_count[4];
+};
+
+struct scsi_proto_specific_page {
+	u_int8_t page_code;
+#define SPSP_PAGE_SAVABLE		0x80	/* Page is savable */
+	u_int8_t page_length;
+	u_int8_t protocol;
+#define SPSP_PROTO_FC			0x00
+#define SPSP_PROTO_SPI			0x01
+#define SPSP_PROTO_SSA			0x02
+#define SPSP_PROTO_1394			0x03
+#define SPSP_PROTO_RDMA			0x04
+#define SPSP_PROTO_ISCSI		0x05
+#define SPSP_PROTO_SAS			0x06
+#define SPSP_PROTO_ADT			0x07
+#define SPSP_PROTO_ATA			0x08
+#define SPSP_PROTO_NONE			0x0f
+};
+
 struct scsi_reserve
 {
 	u_int8_t opcode;
@@ -468,6 +522,47 @@
 	u_int8_t control;
 };
 
+struct ata_pass_12 {
+	u_int8_t opcode;
+	u_int8_t protocol;
+#define AP_MULTI	0xe0
+	u_int8_t flags;
+#define AP_T_LEN	0x03
+#define AP_BB		0x04
+#define AP_T_DIR	0x08
+#define AP_CK_COND	0x20
+#define AP_OFFLINE	0x60
+	u_int8_t features;
+	u_int8_t sector_count;
+	u_int8_t lba_low;
+	u_int8_t lba_mid;
+	u_int8_t lba_high;
+	u_int8_t device;
+	u_int8_t command;
+	u_int8_t reserved;
+	u_int8_t control;
+};
+
+struct ata_pass_16 {
+	u_int8_t opcode;
+	u_int8_t protocol;
+#define AP_EXTEND	0x01
+	u_int8_t flags;
+	u_int8_t features_ext;
+	u_int8_t features;
+	u_int8_t sector_count_ext;
+	u_int8_t sector_count;
+	u_int8_t lba_low_ext;
+	u_int8_t lba_low;
+	u_int8_t lba_mid_ext;
+	u_int8_t lba_mid;
+	u_int8_t lba_high_ext;
+	u_int8_t lba_high;
+	u_int8_t device;
+	u_int8_t command;
+	u_int8_t control;
+};
+
 #define SC_SCSI_1 0x01
 #define SC_SCSI_2 0x03
 
@@ -494,6 +589,7 @@
 #define WRITE_10		0x2a
 #define POSITION_TO_ELEMENT	0x2b
 #define	SYNCHRONIZE_CACHE	0x35
+#define	READ_DEFECT_DATA_10	0x37
 #define	WRITE_BUFFER            0x3b
 #define	READ_BUFFER             0x3c
 #define	CHANGE_DEFINITION	0x40
@@ -501,10 +597,12 @@
 #define	LOG_SENSE		0x4d
 #define	MODE_SELECT_10		0x55
 #define	MODE_SENSE_10		0x5A
+#define	ATA_PASS_16		0x85
 #define	READ_16			0x88
 #define	WRITE_16		0x8a
 #define	SERVICE_ACTION_IN	0x9e
 #define	REPORT_LUNS		0xA0
+#define	ATA_PASS_12		0xa1
 #define	MOVE_MEDIUM     	0xa5
 #define	READ_12			0xa8
 #define	WRITE_12		0xaa
@@ -599,6 +697,9 @@
 #define SID_AENC	0x80
 #define SID_TrmIOP	0x40
 	u_int8_t additional_length;
+#define	SID_ADDITIONAL_LENGTH(iqd)					\
+	((iqd)->additional_length +					\
+	offsetof(struct scsi_inquiry_data, additional_length) + 1)
 	u_int8_t reserved;
 	u_int8_t spc2_flags;
 #define SPC2_SID_MChngr 	0x08
@@ -611,7 +712,6 @@
     (((iqd)->flags & SID_CmdQue) && !((iqd)->spc2_flags & SPC2_SID_BQueue)) || \
     (!((iqd)->flags & SID_CmdQue) && ((iqd)->spc2_flags & SPC2_SID_BQueue)))
 
-
 	u_int8_t flags;
 #define	SID_SftRe	0x01
 #define	SID_CmdQue	0x02
@@ -661,6 +761,17 @@
 	u_int8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE];
 };
 
+struct scsi_vpd_supported_page_list
+{
+	u_int8_t device;
+	u_int8_t page_code;
+#define SVPD_SUPPORTED_PAGE_LIST 0x00
+	u_int8_t reserved;
+	u_int8_t length;	/* number of VPD entries */
+#define SVPD_SUPPORTED_PAGES_SIZE	251
+	u_int8_t list[SVPD_SUPPORTED_PAGES_SIZE];
+};
+
 struct scsi_vpd_unit_serial_number
 {
 	u_int8_t device;
Index: scsi_da.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_da.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/cam/scsi/scsi_da.c -L sys/cam/scsi/scsi_da.c -u -r1.2 -r1.3
--- sys/cam/scsi/scsi_da.c
+++ sys/cam/scsi/scsi_da.c
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_da.c,v 1.180.2.8 2006/07/26 07:48:51 delphij Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_da.c,v 1.224 2007/07/01 17:42:07 imp Exp $");
 
 #include <sys/param.h>
 
@@ -37,20 +37,15 @@
 #include <sys/bio.h>
 #include <sys/sysctl.h>
 #include <sys/taskqueue.h>
-#endif /* _KERNEL */
-
-#include <sys/devicestat.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/conf.h>
+#include <sys/devicestat.h>
 #include <sys/eventhandler.h>
 #include <sys/malloc.h>
 #include <sys/cons.h>
-
-#include <machine/md_var.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-
 #include <geom/geom_disk.h>
+#endif /* _KERNEL */
 
 #ifndef _KERNEL
 #include <stdio.h>
@@ -61,6 +56,7 @@
 #include <cam/cam_ccb.h>
 #include <cam/cam_periph.h>
 #include <cam/cam_xpt_periph.h>
+#include <cam/cam_sim.h>
 
 #include <cam/scsi/scsi_message.h>
 
@@ -133,6 +129,7 @@
 	struct task		sysctl_task;
 	struct sysctl_ctx_list	sysctl_ctx;
 	struct sysctl_oid	*sysctl_tree;
+	struct callout		sendordered_c;
 };
 
 struct da_quirk_entry {
@@ -169,7 +166,6 @@
 		 */
 		{T_DIRECT, SIP_MEDIA_FIXED, "FUJITSU", "M2954*", "*"},
 		/*quirks*/ DA_Q_NO_SYNC_CACHE
-	
 	},
 	{
 		/*
@@ -241,7 +237,7 @@
 		 * Reported by: walter at pelissero.de
 		 */
 		{T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CP3500*", "*"},
-                /*quirks*/ DA_Q_NO_SYNC_CACHE
+		/*quirks*/ DA_Q_NO_SYNC_CACHE
 	},
 	{
 		/*
@@ -266,7 +262,7 @@
 		 */
 		{T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "USB Flash Disk*",
 		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
-	}, 
+	},
  	{
  		/*
  		 * Creative Nomad MUVO mp3 player (USB)
@@ -351,8 +347,8 @@
 		 * Kingston DataTraveler II+ USB Pen-Drive.
 		 * Reported by: Pawel Jakub Dawidek <pjd at FreeBSD.org>
 		 */
-		{T_DIRECT, SIP_MEDIA_REMOVABLE, "Kingston" , "DataTraveler II+", "*"},
-		/*quirks*/ DA_Q_NO_SYNC_CACHE
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "Kingston" , "DataTraveler II+",
+		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
 	},
 	{
 		/*
@@ -443,6 +439,102 @@
 		{T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "STORAGE DEVICE*",
 		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
 	},
+	{
+		/*
+		 * Rekam Digital CAMERA
+		 * PR: usb/98713
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "CAMERA*", "4MP-9J6*",
+		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * iRiver H10 MP3 player
+		 * PR: usb/102547
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "iriver", "H10*",
+		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * iRiver U10 MP3 player
+		 * PR: usb/92306
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "iriver", "U10*",
+		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * X-Micro Flash Disk
+		 * PR: usb/96901
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "X-Micro", "Flash Disk",
+		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * EasyMP3 EM732X USB 2.0 Flash MP3 Player
+		 * PR: usb/96546
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "EM732X", "MP3 Player*",
+		"1.0"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * Denver MP3 player
+		 * PR: usb/107101
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "DENVER", "MP3 PLAYER",
+		 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * Philips USB Key Audio KEY013
+		 * PR: usb/68412
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "PHILIPS", "Key*", "*"},
+		/*quirks*/ DA_Q_NO_SYNC_CACHE | DA_Q_NO_PREVENT
+	},
+	{
+		/*
+		 * JNC MP3 Player
+		 * PR: usb/94439
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "JNC*" , "MP3 Player*",
+		 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * SAMSUNG MP0402H
+		 * PR: usb/108427
+		 */
+		{T_DIRECT, SIP_MEDIA_FIXED, "SAMSUNG", "MP0402H", "*"},
+		/*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * I/O Magic USB flash - Giga Bank
+		 * PR: usb/108810
+		 */
+		{T_DIRECT, SIP_MEDIA_FIXED, "GS-Magic", "stor*", "*"},
+		/*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * JoyFly 128mb USB Flash Drive
+		 * PR: 96133
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "USB 2.0", "Flash Disk*",
+		 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * ChipsBnk usb stick
+		 * PR: 103702
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "ChipsBnk", "USB*",
+		 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
 };
 
 static	disk_strategy_t	dastrategy;
@@ -475,8 +567,14 @@
 #define	DA_DEFAULT_RETRY	4
 #endif
 
+#ifndef	DA_DEFAULT_SEND_ORDERED
+#define	DA_DEFAULT_SEND_ORDERED	1
+#endif
+
+
 static int da_retry_count = DA_DEFAULT_RETRY;
 static int da_default_timeout = DA_DEFAULT_TIMEOUT;
+static int da_send_ordered = DA_DEFAULT_SEND_ORDERED;
 
 SYSCTL_NODE(_kern_cam, OID_AUTO, da, CTLFLAG_RD, 0,
             "CAM Direct Access Disk driver");
@@ -486,6 +584,9 @@
 SYSCTL_INT(_kern_cam_da, OID_AUTO, default_timeout, CTLFLAG_RW,
            &da_default_timeout, 0, "Normal I/O timeout (in seconds)");
 TUNABLE_INT("kern.cam.da.default_timeout", &da_default_timeout);
+SYSCTL_INT(_kern_cam_da, OID_AUTO, da_send_ordered, CTLFLAG_RW,
+           &da_send_ordered, 0, "Send Ordered Tags");
+TUNABLE_INT("kern.cam.da.da_send_ordered", &da_send_ordered);
 
 /*
  * DA_ORDEREDTAG_INTERVAL determines how often, relative
@@ -511,7 +612,7 @@
 
 PERIPHDRIVER_DECLARE(da, dadriver);
 
-static SLIST_HEAD(,da_softc) softc_list;
+MALLOC_DEFINE(M_SCSIDA, "scsi_da", "scsi_da buffers");
 
 static int
 daopen(struct disk *dp)
@@ -520,34 +621,35 @@
 	struct da_softc *softc;
 	int unit;
 	int error;
-	int s;
 
-	s = splsoftcam();
 	periph = (struct cam_periph *)dp->d_drv1;
 	if (periph == NULL) {
-		splx(s);
 		return (ENXIO);	
 	}
-	unit = periph->unit_number;
 
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+		return(ENXIO);
+	}
+
+	cam_periph_lock(periph);
+	if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) {
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
+		return (error);
+	}
+
+	unit = periph->unit_number;
 	softc = (struct da_softc *)periph->softc;
+	softc->flags |= DA_FLAG_OPEN;
 
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
 	    ("daopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit,
 	     unit));
 
-	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0)
-		return (error); /* error code from tsleep */
-
-	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
-		return(ENXIO);
-	softc->flags |= DA_FLAG_OPEN;
-
 	if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) {
 		/* Invalidate our pack information. */
 		softc->flags &= ~DA_FLAG_PACK_INVALID;
 	}
-	splx(s);
 
 	error = dagetcapacity(periph);
 
@@ -570,6 +672,7 @@
 		softc->flags &= ~DA_FLAG_OPEN;
 		cam_periph_release(periph);
 	}
+	cam_periph_unhold(periph);
 	cam_periph_unlock(periph);
 	return (error);
 }
@@ -579,18 +682,21 @@
 {
 	struct	cam_periph *periph;
 	struct	da_softc *softc;
-	int	error;
+	int error;
 
 	periph = (struct cam_periph *)dp->d_drv1;
 	if (periph == NULL)
 		return (ENXIO);	
 
-	softc = (struct da_softc *)periph->softc;
-
-	if ((error = cam_periph_lock(periph, PRIBIO)) != 0) {
-		return (error); /* error code from tsleep */
+	cam_periph_lock(periph);
+	if ((error = cam_periph_hold(periph, PRIBIO)) != 0) {
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
+		return (error);
 	}
 
+	softc = (struct da_softc *)periph->softc;
+
 	if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) {
 		union	ccb *ccb;
 
@@ -622,11 +728,10 @@
 				if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
 					scsi_sense_print(&ccb->csio);
 			} else {
-				xpt_print_path(periph->path);
-				printf("Synchronize cache failed, status "
-				       "== 0x%x, scsi status == 0x%x\n",
-				       ccb->csio.ccb_h.status,
-				       ccb->csio.scsi_status);
+				xpt_print(periph->path, "Synchronize cache "
+				    "failed, status == 0x%x, scsi status == "
+				    "0x%x\n", ccb->csio.ccb_h.status,
+				    ccb->csio.scsi_status);
 			}
 		}
 
@@ -653,8 +758,9 @@
 	}
 
 	softc->flags &= ~DA_FLAG_OPEN;
-	cam_periph_unlock(periph);
+	cam_periph_unhold(periph);
 	cam_periph_release(periph);
+	cam_periph_unlock(periph);
 	return (0);	
 }
 
@@ -668,7 +774,6 @@
 {
 	struct cam_periph *periph;
 	struct da_softc *softc;
-	int    s;
 	
 	periph = (struct cam_periph *)bp->bio_disk->d_drv1;
 	if (periph == NULL) {
@@ -676,6 +781,9 @@
 		return;
 	}
 	softc = (struct da_softc *)periph->softc;
+
+	cam_periph_lock(periph);
+
 #if 0
 	/*
 	 * check it's not too big a transfer for our adapter
@@ -688,13 +796,12 @@
 	 * after we are in the queue.  Otherwise, we might not properly
 	 * clean up one of the buffers.
 	 */
-	s = splbio();
 	
 	/*
 	 * If the device has been made invalid, error out
 	 */
 	if ((softc->flags & DA_FLAG_PACK_INVALID)) {
-		splx(s);
+		cam_periph_unlock(periph);
 		biofinish(bp, NULL, ENXIO);
 		return;
 	}
@@ -704,12 +811,11 @@
 	 */
 	bioq_disksort(&softc->bio_queue, bp);
 
-	splx(s);
-	
 	/*
 	 * Schedule ourselves for performing the work.
 	 */
 	xpt_schedule(periph, /* XXX priority */1);
+	cam_periph_unlock(periph);
 
 	return;
 }
@@ -728,12 +834,16 @@
 	if (periph == NULL)
 		return (ENXIO);
 	softc = (struct da_softc *)periph->softc;
+	cam_periph_lock(periph);
 	secsize = softc->params.secsize;
 	
-	if ((softc->flags & DA_FLAG_PACK_INVALID) != 0)
+	if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) {
+		cam_periph_unlock(periph);
 		return (ENXIO);
+	}
 
 	if (length > 0) {
+		periph->flags |= CAM_PERIPH_POLLED;
 		xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1);
 		csio.ccb_h.ccb_state = DA_CCB_DUMP;
 		scsi_read_write(&csio,
@@ -759,10 +869,12 @@
 			else
 				printf("status == 0x%x, scsi status == 0x%x\n",
 				       csio.ccb_h.status, csio.scsi_status);
+			periph->flags |= CAM_PERIPH_POLLED;
 			return(EIO);
 		}
+		cam_periph_unlock(periph);
 		return(0);
-	} 
+	}
 		
 	/*
 	 * Sync the disk cache contents to the physical media.
@@ -794,13 +906,15 @@
 				if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
 					scsi_sense_print(&csio);
 			} else {
-				xpt_print_path(periph->path);
-				printf("Synchronize cache failed, status "
-				       "== 0x%x, scsi status == 0x%x\n",
-				       csio.ccb_h.status, csio.scsi_status);
+				xpt_print(periph->path, "Synchronize cache "
+				    "failed, status == 0x%x, scsi status == "
+				    "0x%x\n", csio.ccb_h.status,
+				    csio.scsi_status);
 			}
 		}
 	}
+	periph->flags &= ~CAM_PERIPH_POLLED;
+	cam_periph_unlock(periph);
 	return (0);
 }
 
@@ -808,41 +922,17 @@
 dainit(void)
 {
 	cam_status status;
-	struct cam_path *path;
 
-	SLIST_INIT(&softc_list);
-	
 	/*
 	 * Install a global async callback.  This callback will
 	 * receive async callbacks like "new device found".
 	 */
-	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
-				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
-
-	if (status == CAM_REQ_CMP) {
-		struct ccb_setasync csa;
-
-                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
-                csa.ccb_h.func_code = XPT_SASYNC_CB;
-                csa.event_enable = AC_FOUND_DEVICE;
-                csa.callback = daasync;
-                csa.callback_arg = NULL;
-                xpt_action((union ccb *)&csa);
-		status = csa.ccb_h.status;
-                xpt_free_path(path);
-        }
+	status = xpt_register_async(AC_FOUND_DEVICE, daasync, NULL, NULL);
 
 	if (status != CAM_REQ_CMP) {
 		printf("da: Failed to attach master async callback "
 		       "due to status 0x%x!\n", status);
-	} else {
-
-		/*
-		 * Schedule a periodic event to occasionally send an
-		 * ordered tag to a device.
-		 */
-		timeout(dasendorderedtag, NULL,
-			(DA_DEFAULT_TIMEOUT * hz) / DA_ORDEREDTAG_INTERVAL);
+	} else if (da_send_ordered) {
 
 		/* Register our shutdown event handler */
 		if ((EVENTHANDLER_REGISTER(shutdown_post_sync, dashutdown, 
@@ -854,45 +944,26 @@
 static void
 daoninvalidate(struct cam_periph *periph)
 {
-	int s;
 	struct da_softc *softc;
-	struct ccb_setasync csa;
 
 	softc = (struct da_softc *)periph->softc;
 
 	/*
 	 * De-register any async callbacks.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path,
-		      /* priority */ 5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = 0;
-	csa.callback = daasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(0, daasync, periph, periph->path);
 
 	softc->flags |= DA_FLAG_PACK_INVALID;
 
 	/*
-	 * Although the oninvalidate() routines are always called at
-	 * splsoftcam, we need to be at splbio() here to keep the buffer
-	 * queue from being modified while we traverse it.
-	 */
-	s = splbio();
-
-	/*
 	 * Return all queued I/O with ENXIO.
 	 * XXX Handle any transactions queued to the card
 	 *     with XPT_ABORT_CCB.
 	 */
 	bioq_flush(&softc->bio_queue, NULL, ENXIO);
-	splx(s);
-
-	SLIST_REMOVE(&softc_list, softc, da_softc, links);
 
 	disk_gone(softc->disk);
-	xpt_print_path(periph->path);
-	printf("lost device\n");
+	xpt_print(periph->path, "lost device\n");
 }
 
 static void
@@ -902,17 +973,19 @@
 
 	softc = (struct da_softc *)periph->softc;
 
-	xpt_print_path(periph->path);
-	printf("removing device entry\n");
+	xpt_print(periph->path, "removing device entry\n");
 	/*
 	 * If we can't free the sysctl tree, oh well...
 	 */
 	if ((softc->flags & DA_FLAG_SCTX_INIT) != 0
 	    && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
-		xpt_print_path(periph->path);
-		printf("can't remove sysctl context\n");
+		xpt_print(periph->path, "can't remove sysctl context\n");
 	}
+
+	cam_periph_unlock(periph);
 	disk_destroy(softc->disk);
+	callout_drain(&softc->sendordered_c);
+	cam_periph_lock(periph);
 	free(softc, M_DEVBUF);
 }
 
@@ -927,6 +1000,7 @@
 	case AC_FOUND_DEVICE:
 	{
 		struct ccb_getdev *cgd;
+		struct cam_sim *sim;
 		cam_status status;
  
 		cgd = (struct ccb_getdev *)arg;
@@ -943,6 +1017,7 @@
 		 * this device and start the probe
 		 * process.
 		 */
+		sim = xpt_path_sim(cgd->ccb_h.path);
 		status = cam_periph_alloc(daregister, daoninvalidate,
 					  dacleanup, dastart,
 					  "da", CAM_PERIPH_BIO,
@@ -960,10 +1035,8 @@
 	{
 		struct da_softc *softc;
 		struct ccb_hdr *ccbh;
-		int s;
 
 		softc = (struct da_softc *)periph->softc;
-		s = splsoftcam();
 		/*
 		 * Don't fail on the expected unit attention
 		 * that will occur.
@@ -971,7 +1044,6 @@
 		softc->flags |= DA_FLAG_RETRY_UA;
 		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
 			ccbh->ccb_state |= DA_CCB_RETRY_UA;
-		splx(s);
 		/* FALLTHROUGH*/
 	}
 	default:
@@ -988,8 +1060,10 @@
 	char tmpstr[80], tmpstr2[80];
 
 	periph = (struct cam_periph *)context;
-	softc = (struct da_softc *)periph->softc;
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+		return;
 
+	softc = (struct da_softc *)periph->softc;
 	snprintf(tmpstr, sizeof(tmpstr), "CAM DA unit %d", periph->unit_number);
 	snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
 
@@ -1002,6 +1076,7 @@
 	if (softc->sysctl_tree == NULL) {
 		printf("dasysctlinit: unable to allocate sysctl tree\n");
 		mtx_unlock(&Giant);
+		cam_periph_release(periph);
 		return;
 	}
 
@@ -1015,6 +1090,7 @@
 		"Minimum CDB size");
 
 	mtx_unlock(&Giant);
+	cam_periph_release(periph);
 }
 
 static int
@@ -1052,9 +1128,7 @@
 static cam_status
 daregister(struct cam_periph *periph, void *arg)
 {
-	int s;
 	struct da_softc *softc;
-	struct ccb_setasync csa;
 	struct ccb_pathinq cpi;
 	struct ccb_getdev *cgd;
 	char tmpstr[80];
@@ -1142,17 +1216,10 @@
 		softc->minimum_cmd_size = 16;
 
 	/*
-	 * Block our timeout handler while we
-	 * add this softc to the dev list.
-	 */
-	s = splsoftclock();
-	SLIST_INSERT_HEAD(&softc_list, softc, links);
-	splx(s);
-
-	/*
 	 * Register this media as a disk
 	 */
 
+	mtx_unlock(periph->sim->mtx);
 	softc->disk = disk_alloc();
 	softc->disk->d_open = daopen;
 	softc->disk->d_close = daclose;
@@ -1162,8 +1229,11 @@
 	softc->disk->d_drv1 = periph;
 	softc->disk->d_maxsize = DFLTPHYS; /* XXX: probably not arbitrary */
 	softc->disk->d_unit = periph->unit_number;
-	softc->disk->d_flags = DISKFLAG_NEEDSGIANT;
+	softc->disk->d_flags = 0;
+	if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0)
+		softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
 	disk_create(softc->disk, DISK_VERSION);
+	mtx_lock(periph->sim->mtx);
 
 	/*
 	 * Add async callbacks for bus reset and
@@ -1173,19 +1243,26 @@
 	 * them and the only alternative would be to
 	 * not attach the device on failure.
 	 */
-	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
-	csa.ccb_h.func_code = XPT_SASYNC_CB;
-	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
-	csa.callback = daasync;
-	csa.callback_arg = periph;
-	xpt_action((union ccb *)&csa);
+	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
+			   daasync, periph, periph->path);
+
 	/*
-	 * Lock this peripheral until we are setup.
-	 * This first call can't block
+	 * Take an exclusive refcount on the periph while dastart is called
+	 * to finish the probe.  The reference will be dropped in dadone at
+	 * the end of probe.
 	 */
-	(void)cam_periph_lock(periph, PRIBIO);
+	(void)cam_periph_hold(periph, PRIBIO);
 	xpt_schedule(periph, /*priority*/5);
 
+	/*
+	 * Schedule a periodic event to occasionally send an
+	 * ordered tag to a device.
+	 */
+	callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0);
+	callout_reset(&softc->sendordered_c,
+	    (DA_DEFAULT_TIMEOUT * hz) / DA_ORDEREDTAG_INTERVAL,
+	    dasendorderedtag, softc);
+
 	return(CAM_REQ_CMP);
 }
 
@@ -1196,18 +1273,15 @@
 
 	softc = (struct da_softc *)periph->softc;
 
-	
 	switch (softc->state) {
 	case DA_STATE_NORMAL:
 	{
 		/* Pull a buffer from the queue and get going on it */		
 		struct bio *bp;
-		int s;
 
 		/*
 		 * See if there is a buf with work for us to do..
 		 */
-		s = splbio();
 		bp = bioq_first(&softc->bio_queue);
 		if (periph->immediate_priority <= periph->pinfo.priority) {
 			CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
@@ -1216,13 +1290,10 @@
 			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
 					  periph_links.sle);
 			periph->immediate_priority = CAM_PRIORITY_NONE;
-			splx(s);
 			wakeup(&periph->ccb_list);
 		} else if (bp == NULL) {
-			splx(s);
 			xpt_release_ccb(start_ccb);
 		} else {
-			int oldspl;
 			u_int8_t tag_code;
 
 			bioq_remove(&softc->bio_queue, bp);
@@ -1234,31 +1305,44 @@
 			} else {
 				tag_code = MSG_SIMPLE_Q_TAG;
 			}
-			scsi_read_write(&start_ccb->csio,
-					/*retries*/da_retry_count,
-					/*cbfcnp*/dadone,
-					/*tag_action*/tag_code,
-					/*read_op*/bp->bio_cmd == BIO_READ,
-					/*byte2*/0,
-					softc->minimum_cmd_size,
-					/*lba*/bp->bio_pblkno,
-					/*block_count*/bp->bio_bcount /
-					softc->params.secsize,
-					/*data_ptr*/ bp->bio_data,
-					/*dxfer_len*/ bp->bio_bcount,
-					/*sense_len*/SSD_FULL_SIZE,
-					/*timeout*/da_default_timeout*1000);
+			switch (bp->bio_cmd) {
+			case BIO_READ:
+			case BIO_WRITE:
+				scsi_read_write(&start_ccb->csio,
+						/*retries*/da_retry_count,
+						/*cbfcnp*/dadone,
+						/*tag_action*/tag_code,
+						/*read_op*/bp->bio_cmd == BIO_READ,
+						/*byte2*/0,
+						softc->minimum_cmd_size,
+						/*lba*/bp->bio_pblkno,
+						/*block_count*/bp->bio_bcount /
+						softc->params.secsize,
+						/*data_ptr*/ bp->bio_data,
+						/*dxfer_len*/ bp->bio_bcount,
+						/*sense_len*/SSD_FULL_SIZE,
+						/*timeout*/da_default_timeout*1000);
+				break;
+			case BIO_FLUSH:
+				scsi_synchronize_cache(&start_ccb->csio,
+						       /*retries*/1,
+						       /*cbfcnp*/dadone,
+						       MSG_SIMPLE_Q_TAG,
+						       /*begin_lba*/0,/* Cover the whole disk */
+						       /*lb_count*/0,
+						       SSD_FULL_SIZE,
+						       /*timeout*/da_default_timeout*1000);
+				break;
+			}
 			start_ccb->ccb_h.ccb_state = DA_CCB_BUFFER_IO;
 
 			/*
 			 * Block out any asyncronous callbacks
 			 * while we touch the pending ccb list.
 			 */
-			oldspl = splcam();
 			LIST_INSERT_HEAD(&softc->pending_ccbs,
 					 &start_ccb->ccb_h, periph_links.le);
 			softc->outstanding_cmds++;
-			splx(oldspl);
 
 			/* We expect a unit attention from this device */
 			if ((softc->flags & DA_FLAG_RETRY_UA) != 0) {
@@ -1268,7 +1352,6 @@
 
 			start_ccb->ccb_h.ccb_bp = bp;
 			bp = bioq_first(&softc->bio_queue);
-			splx(s);
 
 			xpt_action(start_ccb);
 		}
@@ -1284,9 +1367,8 @@
 		struct ccb_scsiio *csio;
 		struct scsi_read_capacity_data *rcap;
 
-		rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap),
-								M_TEMP,
-								M_NOWAIT);
+		rcap = (struct scsi_read_capacity_data *)
+		    malloc(sizeof(*rcap), M_SCSIDA, M_NOWAIT|M_ZERO);
 		if (rcap == NULL) {
 			printf("dastart: Couldn't malloc read_capacity data\n");
 			/* da_free_periph??? */
@@ -1311,7 +1393,7 @@
 		struct scsi_read_capacity_data_long *rcaplong;
 
 		rcaplong = (struct scsi_read_capacity_data_long *)
-			malloc(sizeof(*rcaplong), M_TEMP, M_NOWAIT);
+			malloc(sizeof(*rcaplong), M_SCSIDA, M_NOWAIT|M_ZERO);
 		if (rcaplong == NULL) {
 			printf("dastart: Couldn't malloc read_capacity data\n");
 			/* da_free_periph??? */
@@ -1352,9 +1434,8 @@
 	    (*cdb != READ_6 && *cdb != WRITE_6))
 		return 0;
 
-	xpt_print_path(ccb->ccb_h.path);
- 	printf("READ(6)/WRITE(6) not supported, "
-	       "increasing minimum_cmd_size to 10.\n");
+	xpt_print(ccb->ccb_h.path, "READ(6)/WRITE(6) not supported, "
+	    "increasing minimum_cmd_size to 10.\n");
  	softc = (struct da_softc *)xpt_path_periph(ccb->ccb_h.path)->softc;
 	softc->minimum_cmd_size = 10;
 
@@ -1394,12 +1475,10 @@
 	case DA_CCB_BUFFER_IO:
 	{
 		struct bio *bp;
-		int    oldspl;
 
 		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
 			int error;
-			int s;
 			int sf;
 			
 			if ((csio->ccb_h.ccb_state & DA_CCB_RETRY_UA) != 0)
@@ -1417,18 +1496,17 @@
 			}
 			if (error != 0) {
 
-				s = splbio();
-
 				if (error == ENXIO) {
 					/*
 					 * Catastrophic error.  Mark our pack as
 					 * invalid.
 					 */
-					/* XXX See if this is really a media
-					 *     change first.
+					/*
+					 * XXX See if this is really a media
+					 * XXX change first?
 					 */
-					xpt_print_path(periph->path);
-					printf("Invalidating pack\n");
+					xpt_print(periph->path,
+					    "Invalidating pack\n");
 					softc->flags |= DA_FLAG_PACK_INVALID;
 				}
 
@@ -1438,7 +1516,6 @@
 				 * proper order should it attempt to recover.
 				 */
 				bioq_flush(&softc->bio_queue, NULL, EIO);
-				splx(s);
 				bp->bio_error = error;
 				bp->bio_resid = bp->bio_bcount;
 				bp->bio_flags |= BIO_ERROR;
@@ -1466,12 +1543,10 @@
 		 * Block out any asyncronous callbacks
 		 * while we touch the pending ccb list.
 		 */
-		oldspl = splcam();
 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
 		softc->outstanding_cmds--;
 		if (softc->outstanding_cmds == 0)
 			softc->flags |= DA_FLAG_WENT_IDLE;
-		splx(oldspl);
 
 		biodone(bp);
 		break;
@@ -1510,7 +1585,7 @@
 				 */
 				if (maxsector == 0xffffffff) {
 					softc->state = DA_STATE_PROBE2;
-					free(rdcap, M_TEMP);
+					free(rdcap, M_SCSIDA);
 					xpt_release_ccb(done_ccb);
 					xpt_schedule(periph, /*priority*/5);
 					return;
@@ -1519,15 +1594,30 @@
 				block_size = scsi_4btoul(rcaplong->length);
 				maxsector = scsi_8btou64(rcaplong->addr);
 			}
-			dasetgeom(periph, block_size, maxsector);
-			dp = &softc->params;
-			snprintf(announce_buf, sizeof(announce_buf),
-			        "%juMB (%ju %u byte sectors: %dH %dS/T %dC)",
-				(uintmax_t) (((uintmax_t)dp->secsize *
-				dp->sectors) / (1024*1024)),
-			        (uintmax_t)dp->sectors,
-				dp->secsize, dp->heads, dp->secs_per_track,
-				dp->cylinders);
+
+			/*
+			 * Because GEOM code just will panic us if we
+			 * give them an 'illegal' value we'll avoid that
+			 * here.
+			 */
+			if (block_size >= MAXPHYS || block_size == 0) {
+				xpt_print(periph->path,
+				    "unsupportable block size %ju\n",
+				    (uintmax_t) block_size);
+				announce_buf[0] = '\0';
+				cam_periph_invalidate(periph);
+			} else {
+				dasetgeom(periph, block_size, maxsector);
+				dp = &softc->params;
+				snprintf(announce_buf, sizeof(announce_buf),
+				        "%juMB (%ju %u byte sectors: %dH %dS/T "
+                                        "%dC)", (uintmax_t)
+	                                (((uintmax_t)dp->secsize *
+				        dp->sectors) / (1024*1024)),
+			                (uintmax_t)dp->sectors,
+				        dp->secsize, dp->heads,
+                                        dp->secs_per_track, dp->cylinders);
+			}
 		} else {
 			int	error;
 
@@ -1608,14 +1698,13 @@
 						scsi_sense_print(
 							&done_ccb->csio);
 					else {
-						xpt_print_path(periph->path);
-						printf("got CAM status %#x\n",
-						       done_ccb->ccb_h.status);
+						xpt_print(periph->path,
+						    "got CAM status %#x\n",
+						    done_ccb->ccb_h.status);
 					}
 
-					xpt_print_path(periph->path);
-					printf("fatal error, failed" 
-					       " to attach to device\n");
+					xpt_print(periph->path, "fatal error, "
+					    "failed to attach to device\n");
 
 					/*
 					 * Free up resources.
@@ -1624,7 +1713,7 @@
 				} 
 			}
 		}
-		free(csio->data_ptr, M_TEMP);
+		free(csio->data_ptr, M_SCSIDA);
 		if (announce_buf[0] != '\0') {
 			xpt_announce_periph(periph, announce_buf);
 			/*
@@ -1643,7 +1732,7 @@
 		 * operation.
 		 */
 		xpt_release_ccb(done_ccb);
-		cam_periph_unlock(periph);
+		cam_periph_unhold(periph);
 		return;
 	}
 	case DA_CCB_WAITING:
@@ -1753,16 +1842,22 @@
 	uint32_t block_len;
 	uint64_t maxsector;
 	int error;
+	u_int32_t sense_flags;
 
 	softc = (struct da_softc *)periph->softc;
 	block_len = 0;
 	maxsector = 0;
 	error = 0;
+	sense_flags = SF_RETRY_UA;
+	if (softc->flags & DA_FLAG_PACK_REMOVABLE)
+		sense_flags |= SF_NO_PRINT;
 
 	/* Do a read capacity */
 	rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcaplong),
-							M_TEMP,
-							M_WAITOK);
+							M_SCSIDA,
+							M_NOWAIT);
+	if (rcap == NULL)
+		return (ENOMEM);
 		
 	ccb = cam_periph_getccb(periph, /*priority*/1);
 	scsi_read_capacity(&ccb->csio,
@@ -1776,7 +1871,7 @@
 
 	error = cam_periph_runccb(ccb, daerror,
 				  /*cam_flags*/CAM_RETRY_SELTO,
-				  /*sense_flags*/SF_RETRY_UA,
+				  sense_flags,
 				  softc->disk->d_devstat);
 
 	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
@@ -1811,7 +1906,7 @@
 
 	error = cam_periph_runccb(ccb, daerror,
 				  /*cam_flags*/CAM_RETRY_SELTO,
-				  /*sense_flags*/SF_RETRY_UA,
+				  sense_flags,
 				  softc->disk->d_devstat);
 
 	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
@@ -1833,7 +1928,7 @@
 
 	xpt_release_ccb(ccb);
 
-	free(rcap, M_TEMP);
+	free(rcap, M_SCSIDA);
 
 	return (error);
 }
@@ -1866,21 +1961,31 @@
 	ccg.secs_per_track = 0;
 	ccg.cylinders = 0;
 	xpt_action((union ccb*)&ccg);
-	dp->heads = ccg.heads;
-	dp->secs_per_track = ccg.secs_per_track;
-	dp->cylinders = ccg.cylinders;
+	if ((ccg.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+		/*
+		 * We don't know what went wrong here- but just pick
+		 * a geometry so we don't have nasty things like divide
+		 * by zero.
+		 */
+		dp->heads = 255;
+		dp->secs_per_track = 255;
+		dp->cylinders = dp->sectors / (255 * 255);
+		if (dp->cylinders == 0) {
+			dp->cylinders = 1;
+		}
+	} else {
+		dp->heads = ccg.heads;
+		dp->secs_per_track = ccg.secs_per_track;
+		dp->cylinders = ccg.cylinders;
+	}
 }
 
 static void
 dasendorderedtag(void *arg)
 {
-	struct da_softc *softc;
-	int s;
+	struct da_softc *softc = arg;
 
-	for (softc = SLIST_FIRST(&softc_list);
-	     softc != NULL;
-	     softc = SLIST_NEXT(softc, links)) {
-		s = splsoftcam();
+	if (da_send_ordered) {
 		if ((softc->ordered_tag_count == 0) 
 		 && ((softc->flags & DA_FLAG_WENT_IDLE) == 0)) {
 			softc->flags |= DA_FLAG_NEED_OTAG;
@@ -1889,11 +1994,11 @@
 			softc->flags &= ~DA_FLAG_WENT_IDLE;
 
 		softc->ordered_tag_count = 0;
-		splx(s);
 	}
 	/* Queue us up again */
-	timeout(dasendorderedtag, NULL,
-		(da_default_timeout * hz) / DA_ORDEREDTAG_INTERVAL);
+	callout_reset(&softc->sendordered_c,
+	    (DA_DEFAULT_TIMEOUT * hz) / DA_ORDEREDTAG_INTERVAL,
+	    dasendorderedtag, softc);
 }
 
 /*
@@ -1908,6 +2013,8 @@
 
 	TAILQ_FOREACH(periph, &dadriver.units, unit_links) {
 		union ccb ccb;
+
+		cam_periph_lock(periph);
 		softc = (struct da_softc *)periph->softc;
 
 		/*
@@ -1915,8 +2022,10 @@
 		 * if the drive is capable of it..
 		 */
 		if (((softc->flags & DA_FLAG_OPEN) == 0)
-		 || (softc->quirks & DA_Q_NO_SYNC_CACHE))
+		 || (softc->quirks & DA_Q_NO_SYNC_CACHE)) {
+			cam_periph_unlock(periph);
 			continue;
+		}
 
 		xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/1);
 
@@ -1945,10 +2054,10 @@
 				if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
 					scsi_sense_print(&ccb.csio);
 			} else {
-				xpt_print_path(periph->path);
-				printf("Synchronize cache failed, status "
-				       "== 0x%x, scsi status == 0x%x\n",
-				       ccb.ccb_h.status, ccb.csio.scsi_status);
+				xpt_print(periph->path, "Synchronize "
+				    "cache failed, status == 0x%x, scsi status "
+				    "== 0x%x\n", ccb.ccb_h.status,
+				    ccb.csio.scsi_status);
 			}
 		}
 
@@ -1958,7 +2067,7 @@
 					 /*reduction*/0,
 					 /*timeout*/0,
 					 /*getcount_only*/0);
-
+		cam_periph_unlock(periph);
 	}
 }
 
Index: scsi_targ_bh.c
===================================================================
RCS file: /home/cvs/src/sys/cam/scsi/scsi_targ_bh.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/cam/scsi/scsi_targ_bh.c -L sys/cam/scsi/scsi_targ_bh.c -u -r1.1.1.1 -r1.2
--- sys/cam/scsi/scsi_targ_bh.c
+++ sys/cam/scsi/scsi_targ_bh.c
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_targ_bh.c,v 1.22 2005/07/01 15:21:30 avatar Exp $");
+__FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_targ_bh.c,v 1.25 2007/05/16 16:54:23 scottl Exp $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -46,6 +46,7 @@
 #include <cam/cam_queue.h>
 #include <cam/cam_xpt_periph.h>
 #include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
 
 #include <cam/scsi/scsi_all.h>
 #include <cam/scsi/scsi_message.h>
@@ -155,27 +156,13 @@
 targbhinit(void)
 {
 	cam_status status;
-	struct cam_path *path;
 
 	/*
 	 * Install a global async callback.  This callback will
 	 * receive async callbacks like "new path registered".
 	 */
-	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
-				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
-
-	if (status == CAM_REQ_CMP) {
-		struct ccb_setasync csa;
-
-		xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
-		csa.ccb_h.func_code = XPT_SASYNC_CB;
-		csa.event_enable = AC_PATH_REGISTERED | AC_PATH_DEREGISTERED;
-		csa.callback = targbhasync;
-		csa.callback_arg = NULL;
-		xpt_action((union ccb *)&csa);
-		status = csa.ccb_h.status;
-		xpt_free_path(path);
-        }
+	status = xpt_register_async(AC_PATH_REGISTERED | AC_PATH_DEREGISTERED,
+				    targbhasync, NULL, NULL);
 
 	if (status != CAM_REQ_CMP) {
 		printf("targbh: Failed to attach master async callback "
@@ -263,9 +250,9 @@
 	xpt_action(&immed_ccb);
 	status = immed_ccb.ccb_h.status;
 	if (status != CAM_REQ_CMP) {
-		xpt_print_path(periph->path);
-		printf("targbhenlun - Enable Lun Rejected with status 0x%x\n",
-		       status);
+		xpt_print(periph->path,
+		    "targbhenlun - Enable Lun Rejected with status 0x%x\n",
+		    status);
 		return (status);
 	}
 	
@@ -309,9 +296,9 @@
 	}
 
 	if (i == 0) {
-		xpt_print_path(periph->path);
-		printf("targbhenlun - Could not allocate accept tio CCBs: "
-		       "status = 0x%x\n", status);
+		xpt_print(periph->path,
+		    "targbhenlun - Could not allocate accept tio CCBs: status "
+		    "= 0x%x\n", status);
 		targbhdislun(periph);
 		return (CAM_REQ_CMP_ERR);
 	}
@@ -345,9 +332,9 @@
 	}
 
 	if (i == 0) {
-		xpt_print_path(periph->path);
-		printf("targbhenlun - Could not allocate immediate notify "
-		       "CCBs: status = 0x%x\n", status);
+		xpt_print(periph->path,
+		    "targbhenlun - Could not allocate immediate notify "
+		    "CCBs: status = 0x%x\n", status);
 		targbhdislun(periph);
 		return (CAM_REQ_CMP_ERR);
 	}
@@ -447,7 +434,7 @@
 		/* FALLTHROUGH */
 	default:
 		/* XXX Wait for callback of targbhdislun() */
-		tsleep(softc, PRIBIO, "targbh", hz/2);
+		msleep(softc, periph->sim->mtx, PRIBIO, "targbh", hz/2);
 		free(softc, M_SCSIBH);
 		break;
 	}
@@ -462,27 +449,22 @@
 	struct targbh_cmd_desc *desc;
 	struct ccb_scsiio *csio;
 	ccb_flags flags;
-	int    s;
 
 	softc = (struct targbh_softc *)periph->softc;
 	
-	s = splbio();
 	ccbh = TAILQ_FIRST(&softc->work_queue);
 	if (periph->immediate_priority <= periph->pinfo.priority) {
 		start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING;			
 		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
 				  periph_links.sle);
 		periph->immediate_priority = CAM_PRIORITY_NONE;
-		splx(s);
 		wakeup(&periph->ccb_list);
 	} else if (ccbh == NULL) {
-		splx(s);
 		xpt_release_ccb(start_ccb);	
 	} else {
 		TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
 		TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
 				  periph_links.tqe);
-		splx(s);	
 		atio = (struct ccb_accept_tio*)ccbh;
 		desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
 
@@ -543,9 +525,7 @@
 					 /*getcount_only*/0); 
 			atio->ccb_h.status &= ~CAM_DEV_QFRZN;
 		}
-		s = splbio();
 		ccbh = TAILQ_FIRST(&softc->work_queue);
-		splx(s);
 	}
 	if (ccbh != NULL)
 		xpt_schedule(periph, /*priority*/1);


More information about the Midnightbsd-cvs mailing list