Module Name:    src
Committed By:   mlelstv
Date:           Sun Nov 20 15:37:19 UTC 2016

Modified Files:
        src/share/man/man9: scsipi.9
        src/sys/dev/scsipi: atapi_wdc.c atapiconf.c cd.c ch.c if_se.c
            scsi_base.c scsiconf.c scsipi_base.c scsipi_base.h scsipi_ioctl.c
            scsipiconf.c scsipiconf.h sd.c ses.c ss.c ss_mustek.c ss_scanjet.c
            st.c uk.c

Log Message:
Make scsipi framework MPSAFE.

Data structures are now protected by a per-adapter mutex at IPL_BIO
that is created by the scsibus or atapibus instance when the adapter
is configured.
The enable reference counter and the channel freeze counter which are
currently used by HBA code before the adapter is configured, are made
atomic.
The target drivers are now all tagged as D_MPSAFE.

Almost all HBA drivers still require the kernel lock to present,
so all callbacks into HBA code are still protected by kernel lock
unless the driver is tagged as SCSIPI_ADAPT_MPSAFE.

TODO: refactor sd and cd to use dksubr.


To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/share/man/man9/scsipi.9
cvs rdiff -u -r1.122 -r1.123 src/sys/dev/scsipi/atapi_wdc.c
cvs rdiff -u -r1.88 -r1.89 src/sys/dev/scsipi/atapiconf.c
cvs rdiff -u -r1.332 -r1.333 src/sys/dev/scsipi/cd.c
cvs rdiff -u -r1.90 -r1.91 src/sys/dev/scsipi/ch.c \
    src/sys/dev/scsipi/scsi_base.c
cvs rdiff -u -r1.92 -r1.93 src/sys/dev/scsipi/if_se.c
cvs rdiff -u -r1.275 -r1.276 src/sys/dev/scsipi/scsiconf.c
cvs rdiff -u -r1.166 -r1.167 src/sys/dev/scsipi/scsipi_base.c
cvs rdiff -u -r1.22 -r1.23 src/sys/dev/scsipi/scsipi_base.h
cvs rdiff -u -r1.68 -r1.69 src/sys/dev/scsipi/scsipi_ioctl.c
cvs rdiff -u -r1.41 -r1.42 src/sys/dev/scsipi/scsipiconf.c
cvs rdiff -u -r1.123 -r1.124 src/sys/dev/scsipi/scsipiconf.h
cvs rdiff -u -r1.318 -r1.319 src/sys/dev/scsipi/sd.c
cvs rdiff -u -r1.49 -r1.50 src/sys/dev/scsipi/ses.c
cvs rdiff -u -r1.87 -r1.88 src/sys/dev/scsipi/ss.c
cvs rdiff -u -r1.42 -r1.43 src/sys/dev/scsipi/ss_mustek.c
cvs rdiff -u -r1.53 -r1.54 src/sys/dev/scsipi/ss_scanjet.c
cvs rdiff -u -r1.229 -r1.230 src/sys/dev/scsipi/st.c
cvs rdiff -u -r1.64 -r1.65 src/sys/dev/scsipi/uk.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man9/scsipi.9
diff -u src/share/man/man9/scsipi.9:1.28 src/share/man/man9/scsipi.9:1.29
--- src/share/man/man9/scsipi.9:1.28	Fri Jul 29 19:27:45 2016
+++ src/share/man/man9/scsipi.9	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-.\"	$NetBSD: scsipi.9,v 1.28 2016/07/29 19:27:45 palle Exp $
+.\"	$NetBSD: scsipi.9,v 1.29 2016/11/20 15:37:19 mlelstv Exp $
 .\"
 .\"
 .\" Copyright (c) 2001 Manuel Bouyer.
@@ -55,6 +55,10 @@
 .Fn scsipi_target_detach "struct scsipi_channel *chan" "int target" "int lun" "int flags"
 .Ft int
 .Fn scsipi_thread_call_callback "struct scsipi_channel *chan" "void (*callback)(struct scsipi_channel *, void *)" "void *arg"
+.Ft int
+.Fn scsipi_adapter_addref "struct scsipi_adapter *adapt"
+.Ft void
+.Fn scsipi_adapter_delref "struct scsipi_adapter *adapt"
 .Sh DESCRIPTION
 The
 .Nm
@@ -108,6 +112,14 @@ total number of commands the adapter can
 see below)
 .It Va int adapt_max_periph
 number of commands the adapter can handle per device
+.It Va int adapt_flags
+adapter properties
+.Bl -tag -width SCSIPI_ADAPT_POLL_ONLY -compact
+.It Dv SCSIPI_ADAPT_POLL_ONLY
+the HBA can't do interrupts
+.It Dv SCSIPI_ADAPT_MPSAFE
+don't acquire the kernel lock when doing HBA callbacks
+.El
 .El
 .Pp
 The following callbacks should be provided through the
@@ -402,6 +414,11 @@ Returns 0 if operation is successful, or
 This callback is optional, and is useful mostly for hot-plug devices.
 For example, this callback would power on or off
 the relevant PCMCIA socket for a PCMCIA controller.
+.Fn scsipi_adapter_addref
+and
+.Fn scsipi_adapter_delref
+maintain a reference count, the enable callback is called appropriately
+for the first reference and the last reference.
 .It int Fn adapt_getgeom "struct scsipi_periph *periph" "struct disk_parms *params" "u_long sectors"
 Optional callback, used by high-level drivers to get the fictitious geometry
 used by the controller's firmware for the specified periph.
@@ -565,7 +582,7 @@ will be called with
 and
 .Fa arg
 as arguments, from the channel completion thread.
-The callback is run at splbio.
+The callback is run at IPL_BIO with the channel lock held.
 .Fn scsipi_thread_call_callback
 will freeze the channel by one, it's up to the caller to thaw it when
 appropriate.

Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.122 src/sys/dev/scsipi/atapi_wdc.c:1.123
--- src/sys/dev/scsipi/atapi_wdc.c:1.122	Mon May  2 19:18:29 2016
+++ src/sys/dev/scsipi/atapi_wdc.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: atapi_wdc.c,v 1.122 2016/05/02 19:18:29 christos Exp $	*/
+/*	$NetBSD: atapi_wdc.c,v 1.123 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.122 2016/05/02 19:18:29 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123 2016/11/20 15:37:19 mlelstv Exp $");
 
 #ifndef ATADEBUG
 #define ATADEBUG
@@ -153,7 +153,7 @@ wdc_atapi_minphys(struct buf *bp)
 /*
  * Kill off all pending xfers for a periph.
  *
- * Must be called at splbio().
+ * Must be called with adapter lock held
  */
 static void
 wdc_atapi_kill_pending(struct scsipi_periph *periph)

Index: src/sys/dev/scsipi/atapiconf.c
diff -u src/sys/dev/scsipi/atapiconf.c:1.88 src/sys/dev/scsipi/atapiconf.c:1.89
--- src/sys/dev/scsipi/atapiconf.c:1.88	Sun Mar 13 09:01:04 2016
+++ src/sys/dev/scsipi/atapiconf.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: atapiconf.c,v 1.88 2016/03/13 09:01:04 tsutsui Exp $	*/
+/*	$NetBSD: atapiconf.c,v 1.89 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1996, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: atapiconf.c,v 1.88 2016/03/13 09:01:04 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapiconf.c,v 1.89 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -152,6 +152,11 @@ atapibusattach(device_t parent, device_t
 	aprint_naive("\n");
 	aprint_normal(": %d targets\n", chan->chan_ntargets);
 
+	mutex_init(&chan->chan_adapter->adapt_mtx, MUTEX_DEFAULT, IPL_BIO);
+	cv_init(&chan->chan_cv_thr, "scshut");
+	cv_init(&chan->chan_cv_comp, "sccomp");
+	cv_init(&chan->chan_cv_xs, "xscmd");
+
 	/* Initialize the channel. */
 	chan->chan_init_cb = NULL;
 	chan->chan_init_cb_arg = NULL;
@@ -172,20 +177,16 @@ atapibuschilddet(device_t self, device_t
 	struct scsipi_periph *periph;
 	int target;
 
-	/* XXXSMP scsipi */
-	KERNEL_LOCK(1, curlwp);
-
+	mutex_enter(chan_mtx(chan));
 	for (target = 0; target < chan->chan_ntargets; target++) {
-		periph = scsipi_lookup_periph(chan, target, 0);
+		periph = scsipi_lookup_periph_locked(chan, target, 0);
 		if (periph == NULL || periph->periph_dev != child)
 			continue;
 		scsipi_remove_periph(chan, periph);
-		free(periph, M_DEVBUF);
+		scsipi_free_periph(periph);
 		break;
 	}
-
-	/* XXXSMP scsipi */
-	KERNEL_UNLOCK_ONE(curlwp);
+	mutex_exit(chan_mtx(chan));
 }
 
 static int
@@ -201,23 +202,32 @@ atapibusdetach(device_t self, int flags)
 	 */
 	scsipi_channel_shutdown(chan);
 
-	/* XXXSMP scsipi */
+	/* for config_detach() */
 	KERNEL_LOCK(1, curlwp);
 
 	/*
 	 * Now detach all of the periphs.
 	 */
+	mutex_enter(chan_mtx(chan));
 	for (target = 0; target < chan->chan_ntargets; target++) {
-		periph = scsipi_lookup_periph(chan, target, 0);
+		periph = scsipi_lookup_periph_locked(chan, target, 0);
 		if (periph == NULL)
 			continue;
 		error = config_detach(periph->periph_dev, flags);
-		if (error)
+		if (error) {
+			mutex_exit(chan_mtx(chan));
 			goto out;
+		}
 		KASSERT(scsipi_lookup_periph(chan, target, 0) == NULL);
 	}
+	mutex_exit(chan_mtx(chan));
 
 out:
+	cv_destroy(&chan->chan_cv_xs);
+	cv_destroy(&chan->chan_cv_comp);
+	cv_destroy(&chan->chan_cv_thr);
+	mutex_destroy(chan_mtx(chan));
+
 	/* XXXSMP scsipi */
 	KERNEL_UNLOCK_ONE(curlwp);
 	return error;
@@ -289,7 +299,7 @@ atapi_probe_device(struct atapibus_softc
 	} else {
 		atapibusprint(sa, device_xname(sc->sc_dev));
 		aprint_normal(" not configured\n");
-		free(periph, M_DEVBUF);
+		scsipi_free_periph(periph);
 		return NULL;
 	}
 }

Index: src/sys/dev/scsipi/cd.c
diff -u src/sys/dev/scsipi/cd.c:1.332 src/sys/dev/scsipi/cd.c:1.333
--- src/sys/dev/scsipi/cd.c:1.332	Sun Nov 20 02:38:24 2016
+++ src/sys/dev/scsipi/cd.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: cd.c,v 1.332 2016/11/20 02:38:24 pgoyette Exp $	*/
+/*	$NetBSD: cd.c,v 1.333 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2001, 2003, 2004, 2005, 2008 The NetBSD Foundation,
@@ -50,7 +50,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.332 2016/11/20 02:38:24 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.333 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -211,7 +211,7 @@ const struct bdevsw cd_bdevsw = {
 	.d_dump = cddump,
 	.d_psize = cdsize,
 	.d_discard = nodiscard,
-	.d_flag = D_DISK
+	.d_flag = D_DISK | D_MPSAFE
 };
 
 const struct cdevsw cd_cdevsw = {
@@ -226,7 +226,7 @@ const struct cdevsw cd_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = nokqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_DISK
+	.d_flag = D_DISK | D_MPSAFE
 };
 
 static struct dkdriver cddkdriver = {
@@ -316,7 +316,9 @@ static int
 cddetach(device_t self, int flags)
 {
 	struct cd_softc *cd = device_private(self);
-	int s, bmaj, cmaj, i, mn;
+	struct scsipi_periph *periph = cd->sc_periph;
+	struct scsipi_channel *chan = periph->periph_channel;
+	int bmaj, cmaj, i, mn;
 
 	if (cd->sc_dk.dk_openmask != 0 && (flags & DETACH_FORCE) == 0)
 		return EBUSY;
@@ -334,7 +336,7 @@ cddetach(device_t self, int flags)
 	/* kill any pending restart */
 	callout_stop(&cd->sc_callout);
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 
 	/* Kill off any queued buffers. */
 	bufq_drain(cd->buf_queue);
@@ -342,7 +344,7 @@ cddetach(device_t self, int flags)
 	/* Kill off any pending commands. */
 	scsipi_kill_pending(cd->sc_periph);
 
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 
 	bufq_free(cd->buf_queue);
 
@@ -576,8 +578,8 @@ cdstrategy(struct buf *bp)
 	struct cd_softc *cd = device_lookup_private(&cd_cd,CDUNIT(bp->b_dev));
 	struct disklabel *lp;
 	struct scsipi_periph *periph = cd->sc_periph;
+	struct scsipi_channel *chan = periph->periph_channel;
 	daddr_t blkno;
-	int s;
 
 	SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cdstrategy "));
 	SC_DEBUG(cd->sc_periph, SCSIPI_DB1,
@@ -719,7 +721,7 @@ cdstrategy(struct buf *bp)
 				cd->params.blksize;
 		}
 	}
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 
 	/*
 	 * Place it in the queue of disk activities for this disk.
@@ -733,9 +735,9 @@ cdstrategy(struct buf *bp)
 	 * Tell the device to get going on the transfer if it's
 	 * not doing anything, otherwise just wait for completion
 	 */
-	cdstart(cd->sc_periph);
+	cdstart(periph);
 
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 	return;
 
 done:
@@ -759,8 +761,8 @@ done:
  * have been made of the scsi driver, to ensure that the queue
  * continues to be drained.
  *
- * must be called at the correct (highish) spl level
- * cdstart() is called at splbio from cdstrategy, cdrestart and scsipi_done
+ * must be called with channel lock held
+ * cdstart() is called from cdstrategy, cdrestart and scsipi_done
  */
 static void
 cdstart(struct scsipi_periph *periph)
@@ -774,6 +776,7 @@ cdstart(struct scsipi_periph *periph)
 	int flags, nblks, cmdlen, error __diagused;
 
 	SC_DEBUG(periph, SCSIPI_DB2, ("cdstart "));
+
 	/*
 	 * Check if the device has room for another command
 	 */
@@ -785,7 +788,7 @@ cdstart(struct scsipi_periph *periph)
 		 */
 		if (periph->periph_flags & PERIPH_WAITING) {
 			periph->periph_flags &= ~PERIPH_WAITING;
-			wakeup((void *)periph);
+			cv_broadcast(periph_cv_periph(periph));
 			return;
 		}
 
@@ -864,7 +867,7 @@ cdstart(struct scsipi_periph *periph)
 		 * Call the routine that chats with the adapter.
 		 * Note: we cannot sleep as we may be an interrupt
 		 */
-		xs = scsipi_make_xs(periph, cmdp, cmdlen,
+		xs = scsipi_make_xs_locked(periph, cmdp, cmdlen,
 		    (u_char *)bp->b_data, bp->b_bcount,
 		    CDRETRIES, 30000, bp, flags);
 		if (__predict_false(xs == NULL)) {
@@ -896,9 +899,12 @@ cdstart(struct scsipi_periph *periph)
 static void
 cdrestart(void *v)
 {
-	int s = splbio();
+	struct scsipi_periph *periph = (struct scsipi_periph *)v;
+	struct scsipi_channel *chan = periph->periph_channel;
+
+	mutex_enter(chan_mtx(chan));
 	cdstart((struct scsipi_periph *)v);
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 }
 
 static void
@@ -951,7 +957,6 @@ cdbounce(struct buf *bp)
 		struct buf *nbp;
 		daddr_t blkno;
 		long count;
-		int s;
 
 		blkno = obp->b_rawblkno +
 		    ((obp->b_bcount - bounce->resid) / lp->d_secsize);
@@ -995,10 +1000,10 @@ cdbounce(struct buf *bp)
 		putiobuf(bp);
 
 		/* enqueue the request and return */
-		s = splbio();
+		mutex_enter(chan_mtx(cd->sc_periph->periph_channel));
 		bufq_put(cd->buf_queue, nbp);
 		cdstart(cd->sc_periph);
-		splx(s);
+		mutex_exit(chan_mtx(cd->sc_periph->periph_channel));
 
 		return;
 	}
@@ -1270,7 +1275,6 @@ cdioctl(dev_t dev, u_long cmd, void *add
 	struct cd_formatted_toc toc;
 	int part = CDPART(dev);
 	int error;
-	int s;
 #ifdef __HAVE_OLD_DISKLABEL
 	struct disklabel *newlabel = NULL;
 #endif
@@ -1638,6 +1642,7 @@ cdioctl(dev_t dev, u_long cmd, void *add
 	case DIOCGSTRATEGY:
 	    {
 		struct disk_strategy *dks = addr;
+		int s;
 
 		s = splbio();
 		strlcpy(dks->dks_name, bufq_getstrategyname(cd->buf_queue),
@@ -1652,6 +1657,7 @@ cdioctl(dev_t dev, u_long cmd, void *add
 		struct disk_strategy *dks = addr;
 		struct bufq_state *new;
 		struct bufq_state *old;
+		int s;
 
 		if ((flag & FWRITE) == 0) {
 			return EBADF;

Index: src/sys/dev/scsipi/ch.c
diff -u src/sys/dev/scsipi/ch.c:1.90 src/sys/dev/scsipi/ch.c:1.91
--- src/sys/dev/scsipi/ch.c:1.90	Fri Jul 25 08:10:38 2014
+++ src/sys/dev/scsipi/ch.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ch.c,v 1.90 2014/07/25 08:10:38 dholland Exp $	*/
+/*	$NetBSD: ch.c,v 1.91 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ch.c,v 1.90 2014/07/25 08:10:38 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ch.c,v 1.91 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -132,7 +132,7 @@ const struct cdevsw ch_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = chkqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_OTHER
+	.d_flag = D_OTHER | D_MPSAFE
 };
 
 /* SCSI glue */
Index: src/sys/dev/scsipi/scsi_base.c
diff -u src/sys/dev/scsipi/scsi_base.c:1.90 src/sys/dev/scsipi/scsi_base.c:1.91
--- src/sys/dev/scsipi/scsi_base.c:1.90	Fri Apr 20 20:23:21 2012
+++ src/sys/dev/scsipi/scsi_base.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsi_base.c,v 1.90 2012/04/20 20:23:21 bouyer Exp $	*/
+/*	$NetBSD: scsi_base.c,v 1.91 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scsi_base.c,v 1.90 2012/04/20 20:23:21 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scsi_base.c,v 1.91 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -111,7 +111,7 @@ scsi_print_addr(struct scsipi_periph *pe
 /*
  * Kill off all pending xfers for a periph.
  *
- * Must be called at splbio().
+ * Must be called with channel lock held
  */
 void
 scsi_kill_pending(struct scsipi_periph *periph)
@@ -181,7 +181,7 @@ scsi_async_event_xfer_mode(struct scsipi
 	int lun, announce, mode, period, offset;
 
 	for (lun = 0; lun < chan->chan_nluns; lun++) {
-		periph = scsipi_lookup_periph(chan, xm->xm_target, lun);
+		periph = scsipi_lookup_periph_locked(chan, xm->xm_target, lun);
 		if (periph == NULL)
 			continue;
 		announce = 0;
@@ -232,7 +232,7 @@ scsi_fc_sas_async_event_xfer_mode(struct
 	int lun, announce, mode;
 
 	for (lun = 0; lun < chan->chan_nluns; lun++) {
-		periph = scsipi_lookup_periph(chan, xm->xm_target, lun);
+		periph = scsipi_lookup_periph_locked(chan, xm->xm_target, lun);
 		if (periph == NULL)
 			continue;
 		announce = 0;

Index: src/sys/dev/scsipi/if_se.c
diff -u src/sys/dev/scsipi/if_se.c:1.92 src/sys/dev/scsipi/if_se.c:1.93
--- src/sys/dev/scsipi/if_se.c:1.92	Sun Oct  2 14:16:03 2016
+++ src/sys/dev/scsipi/if_se.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_se.c,v 1.92 2016/10/02 14:16:03 christos Exp $	*/
+/*	$NetBSD: if_se.c,v 1.93 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1997 Ian W. Dall <ian.d...@dsto.defence.gov.au>
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_se.c,v 1.92 2016/10/02 14:16:03 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_se.c,v 1.93 2016/11/20 15:37:19 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -375,11 +375,9 @@ se_scsipi_cmd(struct scsipi_periph *peri
     struct buf *bp, int flags)
 {
 	int error;
-	int s = splbio();
 
 	error = scsipi_command(periph, cmd, cmdlen, data_addr,
 	    datalen, retries, timeout, bp, flags);
-	splx(s);
 	return (error);
 }
 

Index: src/sys/dev/scsipi/scsiconf.c
diff -u src/sys/dev/scsipi/scsiconf.c:1.275 src/sys/dev/scsipi/scsiconf.c:1.276
--- src/sys/dev/scsipi/scsiconf.c:1.275	Sun Jun 26 07:31:35 2016
+++ src/sys/dev/scsipi/scsiconf.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsiconf.c,v 1.275 2016/06/26 07:31:35 mlelstv Exp $	*/
+/*	$NetBSD: scsiconf.c,v 1.276 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2004 The NetBSD Foundation, Inc.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scsiconf.c,v 1.275 2016/06/26 07:31:35 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scsiconf.c,v 1.276 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -117,7 +117,7 @@ const struct cdevsw scsibus_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = nokqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_OTHER
+	.d_flag = D_OTHER | D_MPSAFE
 };
 
 static int	scsibusprint(void *, const char *);
@@ -240,6 +240,12 @@ scsibusattach(device_t parent, device_t 
 			chan->chan_adapter->adapt_max_periph = 256;
 	}
 
+	mutex_init(chan_mtx(chan), MUTEX_DEFAULT, IPL_BIO);
+	cv_init(&chan->chan_cv_thr, "scshut");
+	cv_init(&chan->chan_cv_comp, "sccomp");
+	cv_init(&chan->chan_cv_xs, "xscmd");
+	chan_running(chan) = true;
+
 	if (scsipi_adapter_addref(chan->chan_adapter))
 		return;
 
@@ -293,8 +299,7 @@ scsibus_config(struct scsibus_softc *sc)
 		    "waiting %d seconds for devices to settle...\n",
 		    SCSI_DELAY);
 		/* ...an identifier we know no one will use... */
-		(void) tsleep(scsibus_config, PRIBIO,
-		    "scsidly", SCSI_DELAY * hz);
+		kpause("scsidly", false, SCSI_DELAY * hz, NULL);
 	}
 
 	/* Make sure the devices probe in scsibus order to avoid jitter. */
@@ -331,18 +336,11 @@ scsibusdetach(device_t self, int flags)
 	struct scsipi_xfer *xs;
 	int error;
 
-	/* XXXSMP scsipi */
-	KERNEL_LOCK(1, curlwp);
-
 	/*
 	 * Detach all of the periphs.
 	 */
-	if ((error = scsipi_target_detach(chan, -1, -1, flags)) != 0) {
-		/* XXXSMP scsipi */
-		KERNEL_UNLOCK_ONE(curlwp);
-
+	if ((error = scsipi_target_detach(chan, -1, -1, flags)) != 0)
 		return error;
-	}
 
 	pmf_device_deregister(self);
 
@@ -373,8 +371,11 @@ scsibusdetach(device_t self, int flags)
 	 */
 	scsipi_channel_shutdown(chan);
 
-	/* XXXSMP scsipi */
-	KERNEL_UNLOCK_ONE(curlwp);
+	chan_running(chan) = false;
+	cv_destroy(&chan->chan_cv_xs);
+	cv_destroy(&chan->chan_cv_comp);
+	cv_destroy(&chan->chan_cv_thr);
+	mutex_destroy(chan_mtx(chan));
 
 	return 0;
 }
@@ -390,9 +391,6 @@ scsi_probe_bus(struct scsibus_softc *sc,
 	int maxtarget, mintarget, maxlun, minlun;
 	int error;
 
-	/* XXXSMP scsipi */
-	KERNEL_LOCK(1, curlwp);
-
 	if (target == -1) {
 		maxtarget = chan->chan_ntargets - 1;
 		mintarget = 0;
@@ -415,9 +413,7 @@ scsi_probe_bus(struct scsibus_softc *sc,
 	 * Some HBAs provide an abstracted view of the bus; give them an
 	 * oppertunity to re-scan it before we do.
 	 */
-	if (chan->chan_adapter->adapt_ioctl != NULL)
-		(*chan->chan_adapter->adapt_ioctl)(chan, SCBUSIOLLSCAN, NULL,
-		    0, curproc);
+	scsipi_adapter_ioctl(chan, SCBUSIOLLSCAN, NULL, 0, curproc);
 
 	if ((error = scsipi_adapter_addref(chan->chan_adapter)) != 0)
 		goto ret;
@@ -442,7 +438,6 @@ scsi_probe_bus(struct scsibus_softc *sc,
 	}
 	scsipi_adapter_delref(chan->chan_adapter);
 ret:
-	KERNEL_UNLOCK_ONE(curlwp);
 	return (error);
 }
 
@@ -469,17 +464,15 @@ scsidevdetached(device_t self, device_t 
 	target = device_locator(child, SCSIBUSCF_TARGET);
 	lun = device_locator(child, SCSIBUSCF_LUN);
 
-	/* XXXSMP scsipi */
-	KERNEL_LOCK(1, curlwp);
+	mutex_enter(chan_mtx(chan));
 
-	periph = scsipi_lookup_periph(chan, target, lun);
+	periph = scsipi_lookup_periph_locked(chan, target, lun);
 	KASSERT(periph->periph_dev == child);
 
 	scsipi_remove_periph(chan, periph);
-	free(periph, M_DEVBUF);
+	scsipi_free_periph(periph);
 
-	/* XXXSMP scsipi */
-	KERNEL_UNLOCK_ONE(curlwp);
+	mutex_exit(chan_mtx(chan));
 }
 
 /*
@@ -1044,7 +1037,7 @@ scsi_probe_device(struct scsibus_softc *
 	return (docontinue);
 
 bad:
-	free(periph, M_DEVBUF);
+	scsipi_free_periph(periph);
 	return (docontinue);
 }
 
@@ -1132,11 +1125,7 @@ scsibusioctl(dev_t dev, u_long cmd, void
 	case SCBUSIORESET:
 		/* FALLTHROUGH */
 	default:
-		if (chan->chan_adapter->adapt_ioctl == NULL)
-			error = ENOTTY;
-		else
-			error = (*chan->chan_adapter->adapt_ioctl)(chan,
-			    cmd, addr, flag, l->l_proc);
+		error = scsipi_adapter_ioctl(chan, cmd, addr, flag, l->l_proc);
 		break;
 	}
 

Index: src/sys/dev/scsipi/scsipi_base.c
diff -u src/sys/dev/scsipi/scsipi_base.c:1.166 src/sys/dev/scsipi/scsipi_base.c:1.167
--- src/sys/dev/scsipi/scsipi_base.c:1.166	Sun Oct  2 19:40:35 2016
+++ src/sys/dev/scsipi/scsipi_base.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsipi_base.c,v 1.166 2016/10/02 19:40:35 jdolecek Exp $	*/
+/*	$NetBSD: scsipi_base.c,v 1.167 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.166 2016/10/02 19:40:35 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.167 2016/11/20 15:37:19 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_scsi.h"
@@ -49,6 +49,7 @@ __KERNEL_RCSID(0, "$NetBSD: scsipi_base.
 #include <sys/proc.h>
 #include <sys/kthread.h>
 #include <sys/hash.h>
+#include <sys/atomic.h>
 
 #include <dev/scsipi/scsi_spc.h>
 #include <dev/scsipi/scsipi_all.h>
@@ -78,8 +79,15 @@ static void	scsipi_async_event_max_openi
 		    struct scsipi_max_openings *);
 static void	scsipi_async_event_channel_reset(struct scsipi_channel *);
 
+static void	scsipi_channel_freeze_locked(struct scsipi_channel *, int);
+
+static void	scsipi_adapter_lock(struct scsipi_adapter *adapt);
+static void	scsipi_adapter_unlock(struct scsipi_adapter *adapt);
+
 static struct pool scsipi_xfer_pool;
 
+int scsipi_xs_count = 0;
+
 /*
  * scsipi_init:
  *
@@ -102,6 +110,8 @@ scsipi_init(void)
 	    PAGE_SIZE / sizeof(struct scsipi_xfer)) == ENOMEM) {
 		printf("WARNING: not enough memory for scsipi_xfer_pool\n");
 	}
+
+	scsipi_ioctl_init();
 }
 
 /*
@@ -147,17 +157,19 @@ void
 scsipi_channel_shutdown(struct scsipi_channel *chan)
 {
 
+	mutex_enter(chan_mtx(chan));
 	/*
 	 * Shut down the completion thread.
 	 */
 	chan->chan_tflags |= SCSIPI_CHANT_SHUTDOWN;
-	wakeup(&chan->chan_complete);
+	cv_broadcast(chan_cv_complete(chan));
 
 	/*
 	 * Now wait for the thread to exit.
 	 */
 	while (chan->chan_thread != NULL)
-		(void) tsleep(&chan->chan_thread, PRIBIO, "scshut", 0);
+		cv_wait(chan_cv_thread(chan), chan_mtx(chan));
+	mutex_exit(chan_mtx(chan));
 }
 
 static uint32_t
@@ -180,14 +192,13 @@ void
 scsipi_insert_periph(struct scsipi_channel *chan, struct scsipi_periph *periph)
 {
 	uint32_t hash;
-	int s;
 
 	hash = scsipi_chan_periph_hash(periph->periph_target,
 	    periph->periph_lun);
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 	LIST_INSERT_HEAD(&chan->chan_periphtab[hash], periph, periph_hash);
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 }
 
 /*
@@ -199,11 +210,8 @@ void
 scsipi_remove_periph(struct scsipi_channel *chan,
     struct scsipi_periph *periph)
 {
-	int s;
 
-	s = splbio();
 	LIST_REMOVE(periph, periph_hash);
-	splx(s);
 }
 
 /*
@@ -211,14 +219,11 @@ scsipi_remove_periph(struct scsipi_chann
  *
  *	Lookup a periph on the specified channel.
  */
-struct scsipi_periph *
-scsipi_lookup_periph(struct scsipi_channel *chan, int target, int lun)
+static struct scsipi_periph *
+scsipi_lookup_periph_internal(struct scsipi_channel *chan, int target, int lun, bool lock)
 {
 	struct scsipi_periph *periph;
 	uint32_t hash;
-	int s;
-
-	KASSERT(cold || KERNEL_LOCKED_P());
 
 	if (target >= chan->chan_ntargets ||
 	    lun >= chan->chan_nluns)
@@ -226,23 +231,37 @@ scsipi_lookup_periph(struct scsipi_chann
 
 	hash = scsipi_chan_periph_hash(target, lun);
 
-	s = splbio();
+	if (lock)
+		mutex_enter(chan_mtx(chan));
 	LIST_FOREACH(periph, &chan->chan_periphtab[hash], periph_hash) {
 		if (periph->periph_target == target &&
 		    periph->periph_lun == lun)
 			break;
 	}
-	splx(s);
+	if (lock)
+		mutex_exit(chan_mtx(chan));
 
 	return (periph);
 }
 
+struct scsipi_periph *
+scsipi_lookup_periph_locked(struct scsipi_channel *chan, int target, int lun)
+{
+	return scsipi_lookup_periph_internal(chan, target, lun, false);
+}
+
+struct scsipi_periph *
+scsipi_lookup_periph(struct scsipi_channel *chan, int target, int lun)
+{
+	return scsipi_lookup_periph_internal(chan, target, lun, true);
+}
+
 /*
  * scsipi_get_resource:
  *
  *	Allocate a single xfer `resource' from the channel.
  *
- *	NOTE: Must be called at splbio().
+ *	NOTE: Must be called with channel lock held
  */
 static int
 scsipi_get_resource(struct scsipi_channel *chan)
@@ -270,7 +289,7 @@ scsipi_get_resource(struct scsipi_channe
  *	Attempt to grow resources for a channel.  If this succeeds,
  *	we allocate one for our caller.
  *
- *	NOTE: Must be called at splbio().
+ *	NOTE: Must be called with channel lock held
  */
 static inline int
 scsipi_grow_resources(struct scsipi_channel *chan)
@@ -278,17 +297,19 @@ scsipi_grow_resources(struct scsipi_chan
 
 	if (chan->chan_flags & SCSIPI_CHAN_CANGROW) {
 		if ((chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
+			mutex_exit(chan_mtx(chan));
 			scsipi_adapter_request(chan,
 			    ADAPTER_REQ_GROW_RESOURCES, NULL);
+			mutex_enter(chan_mtx(chan));
 			return (scsipi_get_resource(chan));
 		}
 		/*
 		 * ask the channel thread to do it. It'll have to thaw the
 		 * queue
 		 */
-		scsipi_channel_freeze(chan, 1);
+		scsipi_channel_freeze_locked(chan, 1);
 		chan->chan_tflags |= SCSIPI_CHANT_GROWRES;
-		wakeup(&chan->chan_complete);
+		cv_broadcast(chan_cv_complete(chan));
 		return (0);
 	}
 
@@ -300,7 +321,7 @@ scsipi_grow_resources(struct scsipi_chan
  *
  *	Free a single xfer `resource' to the channel.
  *
- *	NOTE: Must be called at splbio().
+ *	NOTE: Must be called with channel lock held
  */
 static void
 scsipi_put_resource(struct scsipi_channel *chan)
@@ -318,7 +339,7 @@ scsipi_put_resource(struct scsipi_channe
  *
  *	Get a tag ID for the specified xfer.
  *
- *	NOTE: Must be called at splbio().
+ *	NOTE: Must be called with channel lock held
  */
 static void
 scsipi_get_tag(struct scsipi_xfer *xs)
@@ -360,7 +381,7 @@ scsipi_get_tag(struct scsipi_xfer *xs)
  *
  *	Put the tag ID for the specified xfer back into the pool.
  *
- *	NOTE: Must be called at splbio().
+ *	NOTE: Must be called with channel lock held
  */
 static void
 scsipi_put_tag(struct scsipi_xfer *xs)
@@ -381,12 +402,14 @@ scsipi_put_tag(struct scsipi_xfer *xs)
  *	specified peripheral.  If the peripheral has no more
  *	available command openings, we either block waiting for
  *	one to become available, or fail.
+ *
+ *	When this routine is called with the channel lock held
+ *	the flags must include XS_CTL_NOSLEEP.
  */
 struct scsipi_xfer *
 scsipi_get_xs(struct scsipi_periph *periph, int flags)
 {
 	struct scsipi_xfer *xs;
-	int s;
 
 	SC_DEBUG(periph, SCSIPI_DB3, ("scsipi_get_xs\n"));
 
@@ -404,7 +427,6 @@ scsipi_get_xs(struct scsipi_periph *peri
 	}
 #endif
 
-	s = splbio();
 	/*
 	 * Wait for a command opening to become available.  Rules:
 	 *
@@ -445,13 +467,16 @@ scsipi_get_xs(struct scsipi_periph *peri
 
  wait_for_opening:
 		if (flags & XS_CTL_NOSLEEP) {
-			splx(s);
 			return (NULL);
 		}
 		SC_DEBUG(periph, SCSIPI_DB3, ("sleeping\n"));
+		mutex_enter(chan_mtx(periph->periph_channel));
 		periph->periph_flags |= PERIPH_WAITING;
-		(void) tsleep(periph, PRIBIO, "getxs", 0);
+		cv_wait(periph_cv_periph(periph),
+		    chan_mtx(periph->periph_channel));
+		mutex_exit(chan_mtx(periph->periph_channel));
 	}
+
 	SC_DEBUG(periph, SCSIPI_DB3, ("calling pool_get\n"));
 	xs = pool_get(&scsipi_xfer_pool,
 	    ((flags & XS_CTL_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
@@ -465,7 +490,6 @@ scsipi_get_xs(struct scsipi_periph *peri
 		printf("unable to allocate %sscsipi_xfer\n",
 		    (flags & XS_CTL_URGENT) ? "URGENT " : "");
 	}
-	splx(s);
 
 	SC_DEBUG(periph, SCSIPI_DB3, ("returning\n"));
 
@@ -475,9 +499,11 @@ scsipi_get_xs(struct scsipi_periph *peri
 		xs->xs_periph = periph;
 		xs->xs_control = flags;
 		xs->xs_status = 0;
-		s = splbio();
+		if ((flags & XS_CTL_NOSLEEP) == 0)
+			mutex_enter(chan_mtx(periph->periph_channel));
 		TAILQ_INSERT_TAIL(&periph->periph_xferq, xs, device_q);
-		splx(s);
+		if ((flags & XS_CTL_NOSLEEP) == 0)
+			mutex_exit(chan_mtx(periph->periph_channel));
 	}
 	return (xs);
 }
@@ -490,7 +516,7 @@ scsipi_get_xs(struct scsipi_periph *peri
  *	an opening, wake it up.  If not, kick any queued I/O the
  *	peripheral may have.
  *
- *	NOTE: Must be called at splbio().
+ *	NOTE: Must be called with channel lock held
  */
 void
 scsipi_put_xs(struct scsipi_xfer *xs)
@@ -521,12 +547,12 @@ scsipi_put_xs(struct scsipi_xfer *xs)
 	if (periph->periph_active == 0 &&
 	    (periph->periph_flags & PERIPH_WAITDRAIN) != 0) {
 		periph->periph_flags &= ~PERIPH_WAITDRAIN;
-		wakeup(&periph->periph_active);
+		cv_broadcast(periph_cv_active(periph));
 	}
 
 	if (periph->periph_flags & PERIPH_WAITING) {
 		periph->periph_flags &= ~PERIPH_WAITING;
-		wakeup(periph);
+		cv_broadcast(periph_cv_periph(periph));
 	} else {
 		if (periph->periph_switch->psw_start != NULL &&
 		    device_is_active(periph->periph_dev)) {
@@ -545,11 +571,20 @@ scsipi_put_xs(struct scsipi_xfer *xs)
 void
 scsipi_channel_freeze(struct scsipi_channel *chan, int count)
 {
-	int s;
+	bool lock = chan_running(chan);
+
+	if (lock)
+		mutex_enter(chan_mtx(chan));
+	chan->chan_qfreeze += count;
+	if (lock)
+		mutex_exit(chan_mtx(chan));
+}
+
+static void
+scsipi_channel_freeze_locked(struct scsipi_channel *chan, int count)
+{
 
-	s = splbio();
 	chan->chan_qfreeze += count;
-	splx(s);
 }
 
 /*
@@ -560,9 +595,10 @@ scsipi_channel_freeze(struct scsipi_chan
 void
 scsipi_channel_thaw(struct scsipi_channel *chan, int count)
 {
-	int s;
+	bool lock = chan_running(chan);
 
-	s = splbio();
+	if (lock)
+		mutex_enter(chan_mtx(chan));
 	chan->chan_qfreeze -= count;
 	/*
 	 * Don't let the freeze count go negative.
@@ -574,7 +610,15 @@ scsipi_channel_thaw(struct scsipi_channe
 	if (chan->chan_qfreeze < 0) {
 		chan->chan_qfreeze = 0;
 	}
-	splx(s);
+	if (lock)
+		mutex_exit(chan_mtx(chan));
+
+	/*
+	 * until the channel is running
+	 */
+	if (!lock)
+		return;
+
 	/*
 	 * Kick the channel's queue here.  Note, we may be running in
 	 * interrupt context (softclock or HBA's interrupt), so the adapter
@@ -604,13 +648,10 @@ scsipi_channel_timed_thaw(void *arg)
  *	Freeze a device's xfer queue.
  */
 void
-scsipi_periph_freeze(struct scsipi_periph *periph, int count)
+scsipi_periph_freeze_locked(struct scsipi_periph *periph, int count)
 {
-	int s;
 
-	s = splbio();
 	periph->periph_qfreeze += count;
-	splx(s);
 }
 
 /*
@@ -619,11 +660,9 @@ scsipi_periph_freeze(struct scsipi_perip
  *	Thaw a device's xfer queue.
  */
 void
-scsipi_periph_thaw(struct scsipi_periph *periph, int count)
+scsipi_periph_thaw_locked(struct scsipi_periph *periph, int count)
 {
-	int s;
 
-	s = splbio();
 	periph->periph_qfreeze -= count;
 #ifdef DIAGNOSTIC
 	if (periph->periph_qfreeze < 0) {
@@ -635,8 +674,25 @@ scsipi_periph_thaw(struct scsipi_periph 
 #endif
 	if (periph->periph_qfreeze == 0 &&
 	    (periph->periph_flags & PERIPH_WAITING) != 0)
-		wakeup(periph);
-	splx(s);
+		cv_broadcast(periph_cv_periph(periph));
+}
+
+void
+scsipi_periph_freeze(struct scsipi_periph *periph, int count)
+{
+
+	mutex_enter(chan_mtx(periph->periph_channel));
+	scsipi_periph_freeze_locked(periph, count);
+	mutex_exit(chan_mtx(periph->periph_channel));
+}
+
+void
+scsipi_periph_thaw(struct scsipi_periph *periph, int count)
+{
+
+	mutex_enter(chan_mtx(periph->periph_channel));
+	scsipi_periph_thaw_locked(periph, count);
+	mutex_exit(chan_mtx(periph->periph_channel));
 }
 
 /*
@@ -647,28 +703,29 @@ scsipi_periph_thaw(struct scsipi_periph 
 void
 scsipi_periph_timed_thaw(void *arg)
 {
-	int s;
 	struct scsipi_periph *periph = arg;
+	struct scsipi_channel *chan = periph->periph_channel;
 
 	callout_stop(&periph->periph_callout);
 
-	s = splbio();
-	scsipi_periph_thaw(periph, 1);
+	mutex_enter(chan_mtx(chan));
+	scsipi_periph_thaw_locked(periph, 1);
 	if ((periph->periph_channel->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
 		/*
 		 * Kick the channel's queue here.  Note, we're running in
 		 * interrupt context (softclock), so the adapter driver
 		 * had better not sleep.
 		 */
+		mutex_exit(chan_mtx(chan));
 		scsipi_run_queue(periph->periph_channel);
 	} else {
 		/*
 		 * Tell the completion thread to kick the channel's queue here.
 		 */
 		periph->periph_channel->chan_tflags |= SCSIPI_CHANT_KICK;
-		wakeup(&periph->periph_channel->chan_complete);
+		cv_broadcast(chan_cv_complete(chan));
+		mutex_exit(chan_mtx(chan));
 	}
-	splx(s);
 }
 
 /*
@@ -679,14 +736,14 @@ scsipi_periph_timed_thaw(void *arg)
 void
 scsipi_wait_drain(struct scsipi_periph *periph)
 {
-	int s;
+	struct scsipi_channel *chan = periph->periph_channel;
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 	while (periph->periph_active != 0) {
 		periph->periph_flags |= PERIPH_WAITDRAIN;
-		(void) tsleep(&periph->periph_active, PRIBIO, "sxdrn", 0);
+		cv_wait(periph_cv_active(periph), chan_mtx(chan));
 	}
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 }
 
 /*
@@ -694,14 +751,18 @@ scsipi_wait_drain(struct scsipi_periph *
  *
  *	Kill off all pending xfers for a periph.
  *
- *	NOTE: Must be called at splbio().
+ *	NOTE: Must be called with channel lock held
  */
 void
 scsipi_kill_pending(struct scsipi_periph *periph)
 {
+	struct scsipi_channel *chan = periph->periph_channel;
 
-	(*periph->periph_channel->chan_bustype->bustype_kill_pending)(periph);
-	scsipi_wait_drain(periph);
+	(*chan->chan_bustype->bustype_kill_pending)(periph);
+	while (periph->periph_active != 0) {
+		periph->periph_flags |= PERIPH_WAITDRAIN;
+		cv_wait(periph_cv_active(periph), chan_mtx(chan));
+	}
 }
 
 /*
@@ -1285,9 +1346,7 @@ scsipi_done(struct scsipi_xfer *xs)
 {
 	struct scsipi_periph *periph = xs->xs_periph;
 	struct scsipi_channel *chan = periph->periph_channel;
-	int s, freezecnt;
-
-	KASSERT(cold || KERNEL_LOCKED_P());
+	int freezecnt;
 
 	SC_DEBUG(periph, SCSIPI_DB2, ("scsipi_done\n"));
 #ifdef SCSIPI_DEBUG
@@ -1295,7 +1354,7 @@ scsipi_done(struct scsipi_xfer *xs)
 		show_scsipi_cmd(xs);
 #endif
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 	/*
 	 * The resource this command was using is now free.
 	 */
@@ -1310,7 +1369,7 @@ scsipi_done(struct scsipi_xfer *xs)
 		 * that this won't ever happen (and can be turned into
 		 * a KASSERT().
 		 */
-		splx(s);
+		mutex_exit(chan_mtx(chan));
 		goto out;
 	}
 	scsipi_put_resource(chan);
@@ -1344,7 +1403,7 @@ scsipi_done(struct scsipi_xfer *xs)
 	if (xs->xs_control & XS_CTL_FREEZE_PERIPH)
 		freezecnt++;
 	if (freezecnt != 0)
-		scsipi_periph_freeze(periph, freezecnt);
+		scsipi_periph_freeze_locked(periph, freezecnt);
 
 	/*
 	 * record the xfer with a pending sense, in case a SCSI reset is
@@ -1361,7 +1420,6 @@ scsipi_done(struct scsipi_xfer *xs)
 	 * in its context.
 	 */
 	if ((xs->xs_control & XS_CTL_ASYNC) == 0) {
-		splx(s);
 		/*
 		 * If it's a polling job, just return, to unwind the
 		 * call graph.  We don't need to restart the queue,
@@ -1370,9 +1428,12 @@ scsipi_done(struct scsipi_xfer *xs)
 		 * (XXX or during boot-time autconfiguration of
 		 * ATAPI devices).
 		 */
-		if (xs->xs_control & XS_CTL_POLL)
+		if (xs->xs_control & XS_CTL_POLL) {
+			mutex_exit(chan_mtx(chan));
 			return;
-		wakeup(xs);
+		}
+		cv_broadcast(xs_cv(xs));
+		mutex_exit(chan_mtx(chan));
 		goto out;
 	}
 
@@ -1382,7 +1443,7 @@ scsipi_done(struct scsipi_xfer *xs)
 	 * if we can handle it in interrupt context.
 	 */
 	if (xs->error == XS_NOERROR) {
-		splx(s);
+		mutex_exit(chan_mtx(chan));
 		(void) scsipi_complete(xs);
 		goto out;
 	}
@@ -1392,8 +1453,8 @@ scsipi_done(struct scsipi_xfer *xs)
 	 * completion queue, and wake up the completion thread.
 	 */
 	TAILQ_INSERT_TAIL(&chan->chan_complete, xs, channel_q);
-	splx(s);
-	wakeup(&chan->chan_complete);
+	mutex_exit(chan_mtx(chan));
+	cv_broadcast(chan_cv_complete(chan));
 
  out:
 	/*
@@ -1437,7 +1498,7 @@ scsipi_complete(struct scsipi_xfer *xs)
 {
 	struct scsipi_periph *periph = xs->xs_periph;
 	struct scsipi_channel *chan = periph->periph_channel;
-	int error, s;
+	int error;
 
 #ifdef DIAGNOSTIC
 	if ((xs->xs_control & XS_CTL_ASYNC) != 0 && xs->bp == NULL)
@@ -1447,10 +1508,10 @@ scsipi_complete(struct scsipi_xfer *xs)
 	 * If command terminated with a CHECK CONDITION, we need to issue a
 	 * REQUEST_SENSE command. Once the REQUEST_SENSE has been processed
 	 * we'll have the real status.
-	 * Must be processed at splbio() to avoid missing a SCSI bus reset
-	 * for this command.
+	 * Must be processed with channel lock held to avoid missing
+	 * a SCSI bus reset for this command.
 	 */
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 	if (xs->error == XS_BUSY && xs->status == SCSI_CHECK) {
 		/* request sense for a request sense ? */
 		if (xs->xs_control & XS_CTL_REQSENSE) {
@@ -1458,8 +1519,8 @@ scsipi_complete(struct scsipi_xfer *xs)
 			printf("request sense for a request sense ?\n");
 			/* XXX maybe we should reset the device ? */
 			/* we've been frozen because xs->error != XS_NOERROR */
-			scsipi_periph_thaw(periph, 1);
-			splx(s);
+			scsipi_periph_thaw_locked(periph, 1);
+			mutex_exit(chan_mtx(chan));
 			if (xs->resid < xs->datalen) {
 				printf("we read %d bytes of sense anyway:\n",
 				    xs->datalen - xs->resid);
@@ -1467,9 +1528,10 @@ scsipi_complete(struct scsipi_xfer *xs)
 			}
 			return EINVAL;
 		}
+		mutex_exit(chan_mtx(chan)); // XXX allows other commands to queue or run
 		scsipi_request_sense(xs);
-	}
-	splx(s);
+	} else
+		mutex_exit(chan_mtx(chan));
 
 	/*
 	 * If it's a user level request, bypass all usual completion
@@ -1477,8 +1539,10 @@ scsipi_complete(struct scsipi_xfer *xs)
 	 */
 	if ((xs->xs_control & XS_CTL_USERCMD) != 0) {
 		SC_DEBUG(periph, SCSIPI_DB3, ("calling user done()\n"));
+		mutex_enter(chan_mtx(chan));
 		if (xs->error != XS_NOERROR)
-			scsipi_periph_thaw(periph, 1);
+			scsipi_periph_thaw_locked(periph, 1);
+		mutex_exit(chan_mtx(chan));
 		scsipi_user_done(xs);
 		SC_DEBUG(periph, SCSIPI_DB3, ("returned from user done()\n "));
 		return 0;
@@ -1537,15 +1601,17 @@ scsipi_complete(struct scsipi_xfer *xs)
 			/*
 			 * Wait one second, and try again.
 			 */
+			mutex_enter(chan_mtx(chan));
 			if ((xs->xs_control & XS_CTL_POLL) ||
 			    (chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
 				/* XXX: quite extreme */
-				kpause("xsbusy", false, hz, NULL);
+				kpause("xsbusy", false, hz, chan_mtx(chan));
 			} else if (!callout_pending(&periph->periph_callout)) {
-				scsipi_periph_freeze(periph, 1);
+				scsipi_periph_freeze_locked(periph, 1);
 				callout_reset(&periph->periph_callout,
 				    hz, scsipi_periph_timed_thaw, periph);
 			}
+			mutex_exit(chan_mtx(chan));
 			error = ERESTART;
 		} else
 			error = EBUSY;
@@ -1600,7 +1666,7 @@ scsipi_complete(struct scsipi_xfer *xs)
 		break;
 	}
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 	if (error == ERESTART) {
 		/*
 		 * If we get here, the periph has been thawed and frozen
@@ -1616,8 +1682,8 @@ scsipi_complete(struct scsipi_xfer *xs)
 		xs->xs_requeuecnt++;
 		error = scsipi_enqueue(xs);
 		if (error == 0) {
-			scsipi_periph_thaw(periph, 1);
-			splx(s);
+			scsipi_periph_thaw_locked(periph, 1);
+			mutex_exit(chan_mtx(chan));
 			return (ERESTART);
 		}
 	}
@@ -1627,14 +1693,16 @@ scsipi_complete(struct scsipi_xfer *xs)
 	 * Thaw it here.
 	 */
 	if (xs->error != XS_NOERROR)
-		scsipi_periph_thaw(periph, 1);
+		scsipi_periph_thaw_locked(periph, 1);
+	mutex_exit(chan_mtx(chan));
 
 	if (periph->periph_switch->psw_done)
 		periph->periph_switch->psw_done(xs, error);
 
+	mutex_enter(chan_mtx(chan));
 	if (xs->xs_control & XS_CTL_ASYNC)
 		scsipi_put_xs(xs);
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 
 	return (error);
 }
@@ -1642,7 +1710,7 @@ scsipi_complete(struct scsipi_xfer *xs)
 /*
  * Issue a request sense for the given scsipi_xfer. Called when the xfer
  * returns with a CHECK_CONDITION status. Must be called in valid thread
- * context and at splbio().
+ * context and with channel lock held.
  */
 
 static void
@@ -1708,9 +1776,6 @@ scsipi_enqueue(struct scsipi_xfer *xs)
 {
 	struct scsipi_channel *chan = xs->xs_periph->periph_channel;
 	struct scsipi_xfer *qxs;
-	int s;
-
-	s = splbio();
 
 	/*
 	 * If the xfer is to be polled, and there are already jobs on
@@ -1718,7 +1783,6 @@ scsipi_enqueue(struct scsipi_xfer *xs)
 	 */
 	if ((xs->xs_control & XS_CTL_POLL) != 0 &&
 	    TAILQ_FIRST(&chan->chan_queue) != NULL) {
-		splx(s);
 		xs->error = XS_DRIVER_STUFFUP;
 		return (EAGAIN);
 	}
@@ -1758,8 +1822,7 @@ scsipi_enqueue(struct scsipi_xfer *xs)
 	TAILQ_INSERT_TAIL(&chan->chan_queue, xs, channel_q);
  out:
 	if (xs->xs_control & XS_CTL_THAW_PERIPH)
-		scsipi_periph_thaw(xs->xs_periph, 1);
-	splx(s);
+		scsipi_periph_thaw_locked(xs->xs_periph, 1);
 	return (0);
 }
 
@@ -1773,17 +1836,16 @@ scsipi_run_queue(struct scsipi_channel *
 {
 	struct scsipi_xfer *xs;
 	struct scsipi_periph *periph;
-	int s;
 
 	for (;;) {
-		s = splbio();
+		mutex_enter(chan_mtx(chan));
 
 		/*
 		 * If the channel is frozen, we can't do any work right
 		 * now.
 		 */
 		if (chan->chan_qfreeze != 0) {
-			splx(s);
+			mutex_exit(chan_mtx(chan));
 			return;
 		}
 
@@ -1813,7 +1875,7 @@ scsipi_run_queue(struct scsipi_channel *
 		/*
 		 * Can't find any work to do right now.
 		 */
-		splx(s);
+		mutex_exit(chan_mtx(chan));
 		return;
 
  got_one:
@@ -1838,7 +1900,7 @@ scsipi_run_queue(struct scsipi_channel *
 					    "adapter resources");
 					/* We'll panic shortly... */
 				}
-				splx(s);
+				mutex_exit(chan_mtx(chan));
 
 				/*
 				 * XXX: We should be able to note that
@@ -1866,7 +1928,7 @@ scsipi_run_queue(struct scsipi_channel *
 		else
 			periph->periph_flags |= PERIPH_UNTAG;
 		periph->periph_sent++;
-		splx(s);
+		mutex_exit(chan_mtx(chan));
 
 		scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs);
 	}
@@ -1885,10 +1947,9 @@ scsipi_execute_xs(struct scsipi_xfer *xs
 {
 	struct scsipi_periph *periph = xs->xs_periph;
 	struct scsipi_channel *chan = periph->periph_channel;
-	int oasync, async, poll, error, s;
+	int oasync, async, poll, error;
 
 	KASSERT(!cold);
-	KASSERT(KERNEL_LOCKED_P());
 
 	(chan->chan_bustype->bustype_cmd)(xs);
 
@@ -1992,8 +2053,10 @@ scsipi_execute_xs(struct scsipi_xfer *xs
 		goto free_xs;
 	}
 
+	mutex_exit(chan_mtx(chan));
  restarted:
 	scsipi_run_queue(chan);
+	mutex_enter(chan_mtx(chan));
 
 	/*
 	 * The xfer is enqueued, and possibly running.  If it's to be
@@ -2005,21 +2068,20 @@ scsipi_execute_xs(struct scsipi_xfer *xs
 	/*
 	 * Not an asynchronous command; wait for it to complete.
 	 */
-	s = splbio();
 	while ((xs->xs_status & XS_STS_DONE) == 0) {
 		if (poll) {
 			scsipi_printaddr(periph);
 			printf("polling command not done\n");
 			panic("scsipi_execute_xs");
 		}
-		(void) tsleep(xs, PRIBIO, "xscmd", 0);
+		cv_wait(xs_cv(xs), chan_mtx(chan));
 	}
-	splx(s);
 
 	/*
 	 * Command is complete.  scsipi_done() has awakened us to perform
 	 * the error handling.
 	 */
+	mutex_exit(chan_mtx(chan));
 	error = scsipi_complete(xs);
 	if (error == ERESTART)
 		goto restarted;
@@ -2034,10 +2096,10 @@ scsipi_execute_xs(struct scsipi_xfer *xs
 	 * Command completed successfully or fatal error occurred.  Fall
 	 * into....
 	 */
+	mutex_enter(chan_mtx(chan));
  free_xs:
-	s = splbio();
 	scsipi_put_xs(xs);
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 
 	/*
 	 * Kick the queue, keep it running in case it stopped for some
@@ -2045,6 +2107,7 @@ scsipi_execute_xs(struct scsipi_xfer *xs
 	 */
 	scsipi_run_queue(chan);
 
+	mutex_enter(chan_mtx(chan));
 	return (error);
 }
 
@@ -2060,38 +2123,36 @@ scsipi_completion_thread(void *arg)
 {
 	struct scsipi_channel *chan = arg;
 	struct scsipi_xfer *xs;
-	int s;
 
 	if (chan->chan_init_cb)
 		(*chan->chan_init_cb)(chan, chan->chan_init_cb_arg);
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 	chan->chan_flags |= SCSIPI_CHAN_TACTIVE;
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 	for (;;) {
-		s = splbio();
+		mutex_enter(chan_mtx(chan));
 		xs = TAILQ_FIRST(&chan->chan_complete);
 		if (xs == NULL && chan->chan_tflags  == 0) {
 			/* nothing to do; wait */
-			(void) tsleep(&chan->chan_complete, PRIBIO,
-			    "sccomp", 0);
-			splx(s);
+			cv_wait(chan_cv_complete(chan), chan_mtx(chan));
+			mutex_exit(chan_mtx(chan));
 			continue;
 		}
 		if (chan->chan_tflags & SCSIPI_CHANT_CALLBACK) {
 			/* call chan_callback from thread context */
 			chan->chan_tflags &= ~SCSIPI_CHANT_CALLBACK;
 			chan->chan_callback(chan, chan->chan_callback_arg);
-			splx(s);
+			mutex_exit(chan_mtx(chan));
 			continue;
 		}
 		if (chan->chan_tflags & SCSIPI_CHANT_GROWRES) {
 			/* attempt to get more openings for this channel */
 			chan->chan_tflags &= ~SCSIPI_CHANT_GROWRES;
+			mutex_exit(chan_mtx(chan));
 			scsipi_adapter_request(chan,
 			    ADAPTER_REQ_GROW_RESOURCES, NULL);
 			scsipi_channel_thaw(chan, 1);
-			splx(s);
 			if (chan->chan_tflags & SCSIPI_CHANT_GROWRES)
 				kpause("scsizzz", FALSE, hz/10, NULL);
 			continue;
@@ -2099,17 +2160,17 @@ scsipi_completion_thread(void *arg)
 		if (chan->chan_tflags & SCSIPI_CHANT_KICK) {
 			/* explicitly run the queues for this channel */
 			chan->chan_tflags &= ~SCSIPI_CHANT_KICK;
+			mutex_exit(chan_mtx(chan));
 			scsipi_run_queue(chan);
-			splx(s);
 			continue;
 		}
 		if (chan->chan_tflags & SCSIPI_CHANT_SHUTDOWN) {
-			splx(s);
+			mutex_exit(chan_mtx(chan));
 			break;
 		}
 		if (xs) {
 			TAILQ_REMOVE(&chan->chan_complete, xs, channel_q);
-			splx(s);
+			mutex_exit(chan_mtx(chan));
 
 			/*
 			 * Have an xfer with an error; process it.
@@ -2122,14 +2183,14 @@ scsipi_completion_thread(void *arg)
 			 */
 			scsipi_run_queue(chan);
 		} else {
-			splx(s);
+			mutex_exit(chan_mtx(chan));
 		}
 	}
 
 	chan->chan_thread = NULL;
 
 	/* In case parent is waiting for us to exit. */
-	wakeup(&chan->chan_thread);
+	cv_broadcast(chan_cv_thread(chan));
 
 	kthread_exit(0);
 }
@@ -2142,24 +2203,23 @@ int
 scsipi_thread_call_callback(struct scsipi_channel *chan,
     void (*callback)(struct scsipi_channel *, void *), void *arg)
 {
-	int s;
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 	if ((chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
 		/* kernel thread doesn't exist yet */
-		splx(s);
+		mutex_exit(chan_mtx(chan));
 		return ESRCH;
 	}
 	if (chan->chan_tflags & SCSIPI_CHANT_CALLBACK) {
-		splx(s);
+		mutex_exit(chan_mtx(chan));
 		return EBUSY;
 	}
 	scsipi_channel_freeze(chan, 1);
 	chan->chan_callback = callback;
 	chan->chan_callback_arg = arg;
 	chan->chan_tflags |= SCSIPI_CHANT_CALLBACK;
-	wakeup(&chan->chan_complete);
-	splx(s);
+	cv_broadcast(chan_cv_complete(chan));
+	mutex_exit(chan_mtx(chan));
 	return(0);
 }
 
@@ -2172,9 +2232,8 @@ void
 scsipi_async_event(struct scsipi_channel *chan, scsipi_async_event_t event,
     void *arg)
 {
-	int s;
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 	switch (event) {
 	case ASYNC_EVENT_MAX_OPENINGS:
 		scsipi_async_event_max_openings(chan,
@@ -2191,7 +2250,7 @@ scsipi_async_event(struct scsipi_channel
 		scsipi_async_event_channel_reset(chan);
 		break;
 	}
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 }
 
 /*
@@ -2240,7 +2299,7 @@ scsipi_set_xfer_mode(struct scsipi_chann
 {
 	struct scsipi_xfer_mode xm;
 	struct scsipi_periph *itperiph;
-	int lun, s;
+	int lun;
 
 	/*
 	 * Go to the minimal xfer mode.
@@ -2263,9 +2322,7 @@ scsipi_set_xfer_mode(struct scsipi_chann
 		/*
 		 * Now issue the request to the adapter.
 		 */
-		s = splbio();
 		scsipi_adapter_request(chan, ADAPTER_REQ_SET_XFER_MODE, &xm);
-		splx(s);
 		/*
 		 * If we want this to happen immediately, issue a dummy
 		 * command, since most adapters can't really negotiate unless
@@ -2284,7 +2341,7 @@ scsipi_set_xfer_mode(struct scsipi_chann
  * scsipi_channel_reset:
  *
  *	handle scsi bus reset
- * called at splbio
+ * called with channel lock held
  */
 static void
 scsipi_async_event_channel_reset(struct scsipi_channel *chan)
@@ -2310,7 +2367,7 @@ scsipi_async_event_channel_reset(struct 
 				    channel_q);
 		}
 	}
-	wakeup(&chan->chan_complete);
+	cv_broadcast(chan_cv_complete(chan));
 	/* Catch xs with pending sense which may not have a REQSENSE xs yet */
 	for (target = 0; target < chan->chan_ntargets; target++) {
 		if (target == chan->chan_id)
@@ -2388,15 +2445,16 @@ scsipi_target_detach(struct scsipi_chann
 int
 scsipi_adapter_addref(struct scsipi_adapter *adapt)
 {
-	int s, error = 0;
+	int error = 0;
 
-	s = splbio();
-	if (adapt->adapt_refcnt++ == 0 && adapt->adapt_enable != NULL) {
-		error = (*adapt->adapt_enable)(adapt->adapt_dev, 1);
+	if (atomic_inc_uint_nv(&adapt->adapt_refcnt) == 1
+	    && adapt->adapt_enable != NULL) {
+		scsipi_adapter_lock(adapt);
+		error = scsipi_adapter_enable(adapt, 1);
+		scsipi_adapter_unlock(adapt);
 		if (error)
-			adapt->adapt_refcnt--;
+			atomic_dec_uint(&adapt->adapt_refcnt);
 	}
-	splx(s);
 	return (error);
 }
 
@@ -2409,12 +2467,13 @@ scsipi_adapter_addref(struct scsipi_adap
 void
 scsipi_adapter_delref(struct scsipi_adapter *adapt)
 {
-	int s;
 
-	s = splbio();
-	if (adapt->adapt_refcnt-- == 1 && adapt->adapt_enable != NULL)
-		(void) (*adapt->adapt_enable)(adapt->adapt_dev, 0);
-	splx(s);
+	if (atomic_dec_uint_nv(&adapt->adapt_refcnt) == 0
+	    && adapt->adapt_enable != NULL) {
+		scsipi_adapter_lock(adapt);
+		(void) scsipi_adapter_enable(adapt, 0);
+		scsipi_adapter_unlock(adapt);
+	}
 }
 
 static struct scsipi_syncparam {
@@ -2469,6 +2528,71 @@ scsipi_sync_factor_to_freq(int factor)
 	return (10000000 / ((factor * 4) * 10));
 }
 
+static inline void
+scsipi_adapter_lock(struct scsipi_adapter *adapt)
+{
+
+	if ((adapt->adapt_flags & SCSIPI_ADAPT_MPSAFE) == 0)
+		KERNEL_LOCK(1, NULL);
+}
+
+static inline void
+scsipi_adapter_unlock(struct scsipi_adapter *adapt)
+{
+
+	if ((adapt->adapt_flags & SCSIPI_ADAPT_MPSAFE) == 0)
+		KERNEL_UNLOCK_ONE(NULL);
+}
+
+void
+scsipi_adapter_minphys(struct scsipi_channel *chan, struct buf *bp)
+{
+	struct scsipi_adapter *adapt = chan->chan_adapter;
+
+	scsipi_adapter_lock(adapt);
+	(adapt->adapt_minphys)(bp);
+	scsipi_adapter_unlock(chan->chan_adapter);
+}
+
+void
+scsipi_adapter_request(struct scsipi_channel *chan, 
+	scsipi_adapter_req_t req, void *arg)
+
+{
+	struct scsipi_adapter *adapt = chan->chan_adapter;
+
+	scsipi_adapter_lock(adapt);
+	(adapt->adapt_request)(chan, req, arg);
+	scsipi_adapter_unlock(adapt);
+}
+
+int
+scsipi_adapter_ioctl(struct scsipi_channel *chan, u_long cmd,
+	void *data, int flag, struct proc *p)
+{
+	struct scsipi_adapter *adapt = chan->chan_adapter;
+	int error;
+
+	if (adapt->adapt_ioctl == NULL)
+		return ENOTTY;
+
+	scsipi_adapter_lock(adapt);
+	error = (adapt->adapt_ioctl)(chan, cmd, data, flag, p);
+	scsipi_adapter_unlock(adapt);
+	return error;
+}
+
+int
+scsipi_adapter_enable(struct scsipi_adapter *adapt, int enable)
+{
+	int error;
+
+	scsipi_adapter_lock(adapt);
+	error = (adapt->adapt_enable)(adapt->adapt_dev, enable);
+	scsipi_adapter_unlock(adapt);
+	return error;
+}
+
 #ifdef SCSIPI_DEBUG
 /*
  * Given a scsipi_xfer, dump the request, in all its glory

Index: src/sys/dev/scsipi/scsipi_base.h
diff -u src/sys/dev/scsipi/scsipi_base.h:1.22 src/sys/dev/scsipi/scsipi_base.h:1.23
--- src/sys/dev/scsipi/scsipi_base.h:1.22	Mon Apr 28 20:23:58 2008
+++ src/sys/dev/scsipi/scsipi_base.h	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsipi_base.h,v 1.22 2008/04/28 20:23:58 martin Exp $	*/
+/*	$NetBSD: scsipi_base.h,v 1.23 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@@ -35,7 +35,17 @@
 struct scsipi_xfer *scsipi_get_xs(struct scsipi_periph *, int);
 void	scsipi_put_xs(struct scsipi_xfer *);
 
-static __inline struct scsipi_xfer *scsipi_make_xs(struct scsipi_periph *,
+static __inline struct scsipi_xfer *scsipi_make_xs_internal(struct scsipi_periph *,
+	    struct scsipi_generic *, int cmdlen, u_char *data_addr,
+	    int datalen, int retries, int timeout, struct buf *,
+	    int flags) __unused;
+
+static __inline struct scsipi_xfer *scsipi_make_xs_unlocked(struct scsipi_periph *,
+	    struct scsipi_generic *, int cmdlen, u_char *data_addr,
+	    int datalen, int retries, int timeout, struct buf *,
+	    int flags) __unused;
+
+static __inline struct scsipi_xfer *scsipi_make_xs_locked(struct scsipi_periph *,
 	    struct scsipi_generic *, int cmdlen, u_char *data_addr,
 	    int datalen, int retries, int timeout, struct buf *,
 	    int flags) __unused;
@@ -45,7 +55,7 @@ static __inline struct scsipi_xfer *scsi
  */
 
 static __inline struct scsipi_xfer *
-scsipi_make_xs(struct scsipi_periph *periph, struct scsipi_generic *cmd,
+scsipi_make_xs_internal(struct scsipi_periph *periph, struct scsipi_generic *cmd,
     int cmdlen, u_char *data_addr, int datalen, int retries, int timeout,
     struct buf *bp, int flags)
 {
@@ -70,4 +80,24 @@ scsipi_make_xs(struct scsipi_periph *per
 	return (xs);
 }
 
+static __inline struct scsipi_xfer *
+scsipi_make_xs_unlocked(struct scsipi_periph *periph, struct scsipi_generic *cmd,
+    int cmdlen, u_char *data_addr, int datalen, int retries, int timeout,
+    struct buf *bp, int flags)
+{
+
+	return scsipi_make_xs_internal(periph, cmd, cmdlen, data_addr,
+	    datalen, retries, timeout, bp, flags & ~XS_CTL_NOSLEEP);
+}
+
+static __inline struct scsipi_xfer *
+scsipi_make_xs_locked(struct scsipi_periph *periph, struct scsipi_generic *cmd,
+    int cmdlen, u_char *data_addr, int datalen, int retries, int timeout,
+    struct buf *bp, int flags)
+{
+
+	return scsipi_make_xs_internal(periph, cmd, cmdlen, data_addr,
+	    datalen, retries, timeout, bp, flags | XS_CTL_NOSLEEP);
+}
+
 #endif /* _DEV_SCSIPI_SCSIPI_BASE_H_ */

Index: src/sys/dev/scsipi/scsipi_ioctl.c
diff -u src/sys/dev/scsipi/scsipi_ioctl.c:1.68 src/sys/dev/scsipi/scsipi_ioctl.c:1.69
--- src/sys/dev/scsipi/scsipi_ioctl.c:1.68	Mon Aug 24 22:50:33 2015
+++ src/sys/dev/scsipi/scsipi_ioctl.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsipi_ioctl.c,v 1.68 2015/08/24 22:50:33 pooka Exp $	*/
+/*	$NetBSD: scsipi_ioctl.c,v 1.69 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scsipi_ioctl.c,v 1.68 2015/08/24 22:50:33 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scsipi_ioctl.c,v 1.69 2016/11/20 15:37:19 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_freebsd.h"
@@ -72,29 +72,35 @@ struct scsi_ioctl {
 };
 
 static LIST_HEAD(, scsi_ioctl) si_head;
+static kmutex_t si_lock;
+
+void
+scsipi_ioctl_init(void)
+{
+
+	mutex_init(&si_lock, MUTEX_DEFAULT, IPL_BIO);
+}
 
 static struct scsi_ioctl *
 si_get(void)
 {
 	struct scsi_ioctl *si;
-	int s;
 
 	si = malloc(sizeof(struct scsi_ioctl), M_TEMP, M_WAITOK|M_ZERO);
 	buf_init(&si->si_bp);
-	s = splbio();
+	mutex_enter(&si_lock);
 	LIST_INSERT_HEAD(&si_head, si, si_list);
-	splx(s);
+	mutex_exit(&si_lock);
 	return (si);
 }
 
 static void
 si_free(struct scsi_ioctl *si)
 {
-	int s;
 
-	s = splbio();
+	mutex_enter(&si_lock);
 	LIST_REMOVE(si, si_list);
-	splx(s);
+	mutex_exit(&si_lock);
 	buf_destroy(&si->si_bp);
 	free(si, M_TEMP);
 }
@@ -103,13 +109,12 @@ static struct scsi_ioctl *
 si_find(struct buf *bp)
 {
 	struct scsi_ioctl *si;
-	int s;
 
-	s = splbio();
+	mutex_enter(&si_lock);
 	for (si = si_head.lh_first; si != 0; si = si->si_list.le_next)
 		if (bp == &si->si_bp)
 			break;
-	splx(s);
+	mutex_exit(&si_lock);
 	return (si);
 }
 
@@ -128,7 +133,6 @@ scsipi_user_done(struct scsipi_xfer *xs)
 	struct scsi_ioctl *si;
 	scsireq_t *screq;
 	struct scsipi_periph *periph = xs->xs_periph;
-	int s;
 
 	bp = xs->bp;
 #ifdef DIAGNOSTIC
@@ -200,9 +204,9 @@ scsipi_user_done(struct scsipi_xfer *xs)
 	}
 
 	if (xs->xs_control & XS_CTL_ASYNC) {
-		s = splbio();
+		mutex_enter(chan_mtx(periph->periph_channel));
 		scsipi_put_xs(xs);
-		splx(s);
+		mutex_exit(chan_mtx(periph->periph_channel));
 	}
 }
 

Index: src/sys/dev/scsipi/scsipiconf.c
diff -u src/sys/dev/scsipi/scsipiconf.c:1.41 src/sys/dev/scsipi/scsipiconf.c:1.42
--- src/sys/dev/scsipi/scsipiconf.c:1.41	Mon May  2 19:18:29 2016
+++ src/sys/dev/scsipi/scsipiconf.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsipiconf.c,v 1.41 2016/05/02 19:18:29 christos Exp $	*/
+/*	$NetBSD: scsipiconf.c,v 1.42 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2004 The NetBSD Foundation, Inc.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scsipiconf.c,v 1.41 2016/05/02 19:18:29 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scsipiconf.c,v 1.42 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -69,7 +69,8 @@ void (*scsipi_print_sense_data)(struct s
 
 int scsi_verbose_loaded = 0; 
 
-int scsipi_print_sense_stub(struct scsipi_xfer * xs, int verbosity)
+int
+scsipi_print_sense_stub(struct scsipi_xfer * xs, int verbosity)
 {
 	scsipi_load_verbose();
 	if (scsi_verbose_loaded)
@@ -78,7 +79,8 @@ int scsipi_print_sense_stub(struct scsip
 		return 0;
 }
 
-void scsipi_print_sense_data_stub(struct scsi_sense_data *sense, int verbosity)
+void
+scsipi_print_sense_data_stub(struct scsi_sense_data *sense, int verbosity)
 {
 	scsipi_load_verbose();
 	if (scsi_verbose_loaded)
@@ -91,13 +93,21 @@ scsipi_command(struct scsipi_periph *per
     struct buf *bp, int flags)
 {
 	struct scsipi_xfer *xs;
+	int rc;
 
-	xs = scsipi_make_xs(periph, cmd, cmdlen, data_addr, datalen, retries,
+	/*
+	 * execute unlocked to allow waiting for memory
+	 */
+	xs = scsipi_make_xs_unlocked(periph, cmd, cmdlen, data_addr, datalen, retries,
 	    timeout, bp, flags);
 	if (!xs)
 		return (ENOMEM);
 
-	return (scsipi_execute_xs(xs));
+	mutex_enter(chan_mtx(periph->periph_channel));
+	rc = scsipi_execute_xs(xs);
+	mutex_exit(chan_mtx(periph->periph_channel));
+
+	return rc;
 }
 
 /* 
@@ -137,11 +147,22 @@ scsipi_alloc_periph(int malloc_flag)
 
 	TAILQ_INIT(&periph->periph_xferq);
 	callout_init(&periph->periph_callout, 0);
+	cv_init(&periph->periph_cv, "periph");
 
 	return periph;
 }
 
 /*
+ * cleanup and free scsipi_periph structure
+ */
+void
+scsipi_free_periph(struct scsipi_periph *periph)
+{
+	cv_destroy(&periph->periph_cv);
+	free(periph, M_DEVBUF);
+}
+
+/*
  * Return a priority based on how much of the inquiry data matches
  * the patterns for the particular driver.
  */

Index: src/sys/dev/scsipi/scsipiconf.h
diff -u src/sys/dev/scsipi/scsipiconf.h:1.123 src/sys/dev/scsipi/scsipiconf.h:1.124
--- src/sys/dev/scsipi/scsipiconf.h:1.123	Mon May  2 19:18:29 2016
+++ src/sys/dev/scsipi/scsipiconf.h	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsipiconf.h,v 1.123 2016/05/02 19:18:29 christos Exp $	*/
+/*	$NetBSD: scsipiconf.h,v 1.124 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2004 The NetBSD Foundation, Inc.
@@ -54,6 +54,7 @@ typedef	int	boolean;
 
 #include <sys/callout.h>
 #include <sys/queue.h>
+#include <sys/condvar.h>
 #include <dev/scsipi/scsi_spc.h>
 #include <dev/scsipi/scsipi_debug.h>
 
@@ -188,7 +189,7 @@ struct scsipi_inquiry_pattern;
 struct scsipi_adapter {
 	device_t adapt_dev;	/* pointer to adapter's device */
 	int	adapt_nchannels;	/* number of adapter channels */
-	int	adapt_refcnt;		/* adapter's reference count */
+	volatile int	adapt_refcnt;		/* adapter's reference count */
 	int	adapt_openings;		/* total # of command openings */
 	int	adapt_max_periph;	/* max openings per periph */
 	int	adapt_flags;
@@ -203,23 +204,22 @@ struct scsipi_adapter {
 			struct disk_parms *, u_long);
 	int	(*adapt_accesschk)(struct scsipi_periph *,
 			struct scsipi_inquiry_pattern *);
+
+	kmutex_t adapt_mtx;
+	bool	adapt_running;	/* attachment initialized */
 };
 #endif
 
 /* adapt_flags */
 #define SCSIPI_ADAPT_POLL_ONLY	0x01 /* Adaptor can't do interrupts. */
+#define SCSIPI_ADAPT_MPSAFE     0x02 /* Adaptor doesn't need kernel lock */
 
-#define	scsipi_adapter_minphys(chan, bp)				\
-	(*(chan)->chan_adapter->adapt_minphys)((bp))
-
-#define	scsipi_adapter_request(chan, req, arg)				\
-	(*(chan)->chan_adapter->adapt_request)((chan), (req), (arg))
-
-#define	scsipi_adapter_ioctl(chan, cmd, data, flag, p)			\
-	(*(chan)->chan_adapter->adapt_ioctl)((chan), (cmd), (data), (flag), (p))
-
-#define	scsipi_adapter_enable(chan, enable)				\
-	(*(chan)->chan_adapt->adapt_enable)((chan), (enable))
+void scsipi_adapter_minphys(struct scsipi_channel *, struct buf *);
+void scsipi_adapter_request(struct scsipi_channel *,
+	scsipi_adapter_req_t, void *);
+int scsipi_adapter_ioctl(struct scsipi_channel *, u_long,
+	void *, int, struct proc *);
+int scsipi_adapter_enable(struct scsipi_adapter *, int);
 
 
 /*
@@ -307,7 +307,17 @@ struct scsipi_channel {
 	/* callback we may have to call after forking the kthread */
 	void (*chan_init_cb)(struct scsipi_channel *, void *);
 	void *chan_init_cb_arg;
+
+	kcondvar_t chan_cv_comp;
+	kcondvar_t chan_cv_thr;
+	kcondvar_t chan_cv_xs;
+
+#define chan_cv_complete(ch) (&(ch)->chan_cv_comp)
+#define chan_cv_thread(ch) (&(ch)->chan_cv_thr)
 };
+
+#define chan_running(ch) ((ch)->chan_adapter->adapt_running)
+#define chan_mtx(ch) (&(ch)->chan_adapter->adapt_mtx)
 #endif
 
 /* chan_flags */
@@ -401,6 +411,9 @@ struct scsipi_periph {
 	/* xfer which has a pending CHECK_CONDITION */
 	struct scsipi_xfer *periph_xscheck;
 
+	kcondvar_t periph_cv;
+#define periph_cv_periph(p) (&(p)->periph_cv)
+#define periph_cv_active(p) (&(p)->periph_cv)
 };
 #endif
 
@@ -482,6 +495,7 @@ typedef enum {
 	XS_REQUEUE		/* requeue this command */
 } scsipi_xfer_result_t;
 
+#ifdef _KERNEL
 /*
  * Each scsipi transaction is fully described by one of these structures
  * It includes information about the source of the command and also the
@@ -544,7 +558,10 @@ struct scsipi_xfer {
 
 	struct	scsipi_generic cmdstore
 	    __aligned(4);		/* stash the command in here */
+
+#define xs_cv(xs) (&(xs)->xs_periph->periph_channel->chan_cv_xs)
 };
+#endif
 
 /*
  * scsipi_xfer control flags
@@ -635,6 +652,7 @@ struct scsi_quirk_inquiry_pattern {
 
 #ifdef _KERNEL
 void	scsipi_init(void);
+void	scsipi_ioctl_init(void);
 void	scsipi_load_verbose(void);
 int	scsipi_command(struct scsipi_periph *, struct scsipi_generic *, int,
 	    u_char *, int, int, int, struct buf *, int);
@@ -662,6 +680,7 @@ int	scsipi_interpret_sense(struct scsipi
 void	scsipi_wait_drain(struct scsipi_periph *);
 void	scsipi_kill_pending(struct scsipi_periph *);
 struct scsipi_periph *scsipi_alloc_periph(int);
+void	scsipi_free_periph(struct scsipi_periph *);
 
 /* Function pointers for scsiverbose module */
 extern int	(*scsipi_print_sense)(struct scsipi_xfer *, int);
@@ -692,6 +711,8 @@ void	scsipi_remove_periph(struct scsipi_
 	    struct scsipi_periph *);
 struct scsipi_periph *scsipi_lookup_periph(struct scsipi_channel *,
 	    int, int);
+struct scsipi_periph *scsipi_lookup_periph_locked(struct scsipi_channel *,
+	    int, int);
 int	scsipi_target_detach(struct scsipi_channel *, int, int, int);
 
 int	scsipi_adapter_addref(struct scsipi_adapter *);
@@ -705,6 +726,9 @@ void	scsipi_periph_freeze(struct scsipi_
 void	scsipi_periph_thaw(struct scsipi_periph *, int);
 void	scsipi_periph_timed_thaw(void *);
 
+void	scsipi_periph_freeze_locked(struct scsipi_periph *, int);
+void	scsipi_periph_thaw_locked(struct scsipi_periph *, int);
+
 int	scsipi_sync_period_to_factor(int);
 int	scsipi_sync_factor_to_period(int);
 int	scsipi_sync_factor_to_freq(int);

Index: src/sys/dev/scsipi/sd.c
diff -u src/sys/dev/scsipi/sd.c:1.318 src/sys/dev/scsipi/sd.c:1.319
--- src/sys/dev/scsipi/sd.c:1.318	Sun Nov 20 02:38:24 2016
+++ src/sys/dev/scsipi/sd.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: sd.c,v 1.318 2016/11/20 02:38:24 pgoyette Exp $	*/
+/*	$NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc.
@@ -47,12 +47,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.318 2016/11/20 02:38:24 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_scsi.h"
 #endif
 
+#define SD_MPSAFE D_MPSAFE
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
@@ -165,7 +167,7 @@ const struct bdevsw sd_bdevsw = {
 	.d_dump = sddump,
 	.d_psize = sdsize,
 	.d_discard = nodiscard,
-	.d_flag = D_DISK
+	.d_flag = D_DISK | SD_MPSAFE
 };
 
 const struct cdevsw sd_cdevsw = {
@@ -180,7 +182,7 @@ const struct cdevsw sd_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = nokqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_DISK
+	.d_flag = D_DISK | SD_MPSAFE
 };
 
 static struct dkdriver sddkdriver = {
@@ -356,7 +358,9 @@ static int
 sddetach(device_t self, int flags)
 {
 	struct sd_softc *sd = device_private(self);
-	int s, bmaj, cmaj, i, mn, rc;
+	struct scsipi_periph *periph = sd->sc_periph;
+	struct scsipi_channel *chan = periph->periph_channel;
+	int bmaj, cmaj, i, mn, rc;
 
 	rnd_add_uint32(&sd->rnd_source, 0);
 
@@ -380,7 +384,7 @@ sddetach(device_t self, int flags)
 	/* Delete all of our wedges. */
 	dkwedge_delall(&sd->sc_dk);
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 
 	/* Kill off any queued buffers. */
 	bufq_drain(sd->buf_queue);
@@ -388,7 +392,7 @@ sddetach(device_t self, int flags)
 	/* Kill off any pending commands. */
 	scsipi_kill_pending(sd->sc_periph);
 
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 
 	bufq_free(sd->buf_queue);
 
@@ -669,9 +673,9 @@ sdstrategy(struct buf *bp)
 {
 	struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(bp->b_dev));
 	struct scsipi_periph *periph = sd->sc_periph;
+	struct scsipi_channel *chan = periph->periph_channel;
 	struct disklabel *lp;
 	daddr_t blkno;
-	int s;
 	bool sector_aligned;
 
 	SC_DEBUG(sd->sc_periph, SCSIPI_DB2, ("sdstrategy "));
@@ -740,7 +744,7 @@ sdstrategy(struct buf *bp)
 
 	bp->b_rawblkno = blkno;
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 
 	/*
 	 * Place it in the queue of disk activities for this disk.
@@ -754,9 +758,9 @@ sdstrategy(struct buf *bp)
 	 * Tell the device to get going on the transfer if it's
 	 * not doing anything, otherwise just wait for completion
 	 */
-	sdstart(sd->sc_periph);
+	sdstart(periph);
 
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 	return;
 
 done:
@@ -780,8 +784,8 @@ done:
  * have been made of the scsi driver, to ensure that the queue
  * continues to be drained.
  *
- * must be called at the correct (highish) spl level
- * sdstart() is called at splbio from sdstrategy, sdrestart and scsipi_done
+ * must be called with channel lock held
+ * sdstart() is called from sdstrategy, sdrestart and scsipi_done
  */
 static void
 sdstart(struct scsipi_periph *periph)
@@ -797,6 +801,7 @@ sdstart(struct scsipi_periph *periph)
 	int nblks, cmdlen, error __diagused, flags;
 
 	SC_DEBUG(periph, SCSIPI_DB2, ("sdstart "));
+
 	/*
 	 * Check if the device has room for another command
 	 */
@@ -808,7 +813,7 @@ sdstart(struct scsipi_periph *periph)
 		 */
 		if (periph->periph_flags & PERIPH_WAITING) {
 			periph->periph_flags &= ~PERIPH_WAITING;
-			wakeup((void *)periph);
+			cv_broadcast(periph_cv_periph(periph));
 			return;
 		}
 
@@ -902,7 +907,7 @@ sdstart(struct scsipi_periph *periph)
 		 * Call the routine that chats with the adapter.
 		 * Note: we cannot sleep as we may be an interrupt
 		 */
-		xs = scsipi_make_xs(periph, cmdp, cmdlen,
+		xs = scsipi_make_xs_locked(periph, cmdp, cmdlen,
 		    (u_char *)bp->b_data, bp->b_bcount,
 		    SDRETRIES, SD_IO_TIMEOUT, bp, flags);
 		if (__predict_false(xs == NULL)) {
@@ -934,9 +939,12 @@ sdstart(struct scsipi_periph *periph)
 static void
 sdrestart(void *v)
 {
-	int s = splbio();
+	struct scsipi_periph *periph = v;
+	struct scsipi_channel *chan = periph->periph_channel;
+
+	mutex_enter(chan_mtx(chan));
 	sdstart((struct scsipi_periph *)v);
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 }
 
 static void
@@ -1020,7 +1028,6 @@ sdioctl(dev_t dev, u_long cmd, void *add
 	struct scsipi_periph *periph = sd->sc_periph;
 	int part = SDPART(dev);
 	int error;
-	int s;
 #ifdef __HAVE_OLD_DISKLABEL
 	struct disklabel *newlabel = NULL;
 #endif
@@ -1206,6 +1213,7 @@ sdioctl(dev_t dev, u_long cmd, void *add
 	case DIOCGSTRATEGY:
 	    {
 		struct disk_strategy *dks = addr;
+		int s;
 
 		s = splbio();
 		strlcpy(dks->dks_name, bufq_getstrategyname(sd->buf_queue),
@@ -1221,6 +1229,7 @@ sdioctl(dev_t dev, u_long cmd, void *add
 		struct disk_strategy *dks = addr;
 		struct bufq_state *new_bufq;
 		struct bufq_state *old_bufq;
+		int s;
 
 		if ((flag & FWRITE) == 0) {
 			return EBADF;
@@ -1367,9 +1376,10 @@ static int
 sd_interpret_sense(struct scsipi_xfer *xs)
 {
 	struct scsipi_periph *periph = xs->xs_periph;
+	struct scsipi_channel *chan = periph->periph_channel;
 	struct scsi_sense_data *sense = &xs->sense.scsi_sense;
 	struct sd_softc *sd = device_private(periph->periph_dev);
-	int s, error, retval = EJUSTRETURN;
+	int error, retval = EJUSTRETURN;
 
 	/*
 	 * If the periph is already recovering, just do the normal
@@ -1427,9 +1437,9 @@ sd_interpret_sense(struct scsipi_xfer *x
 		} else if (sense->ascq == 0x02) {
 			printf("%s: pack is stopped, restarting...\n",
 			    device_xname(sd->sc_dev));
-			s = splbio();
+			mutex_enter(chan_mtx(chan));
 			periph->periph_flags |= PERIPH_RECOVERING;
-			splx(s);
+			mutex_exit(chan_mtx(chan));
 			error = scsipi_start(periph, SSS_START,
 			    XS_CTL_URGENT|XS_CTL_HEAD_TAG|
 			    XS_CTL_THAW_PERIPH|XS_CTL_FREEZE_PERIPH);
@@ -1439,9 +1449,9 @@ sd_interpret_sense(struct scsipi_xfer *x
 				retval = error;
 			} else
 				retval = ERESTART;
-			s = splbio();
+			mutex_enter(chan_mtx(chan));
 			periph->periph_flags &= ~PERIPH_RECOVERING;
-			splx(s);
+			mutex_exit(chan_mtx(chan));
 		}
 	}
 	if (SSD_SENSE_KEY(sense->flags) == SKEY_MEDIUM_ERROR &&

Index: src/sys/dev/scsipi/ses.c
diff -u src/sys/dev/scsipi/ses.c:1.49 src/sys/dev/scsipi/ses.c:1.50
--- src/sys/dev/scsipi/ses.c:1.49	Thu Jul 14 10:19:06 2016
+++ src/sys/dev/scsipi/ses.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ses.c,v 1.49 2016/07/14 10:19:06 msaitoh Exp $ */
+/*	$NetBSD: ses.c,v 1.50 2016/11/20 15:37:19 mlelstv Exp $ */
 /*
  * Copyright (C) 2000 National Aeronautics & Space Administration
  * All rights reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ses.c,v 1.49 2016/07/14 10:19:06 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ses.c,v 1.50 2016/11/20 15:37:19 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_scsi.h"
@@ -150,7 +150,7 @@ const struct cdevsw ses_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = nokqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_OTHER
+	.d_flag = D_OTHER | D_MPSAFE
 };
 
 static int ses_runcmd(struct ses_softc *, char *, int, char *, int *);

Index: src/sys/dev/scsipi/ss.c
diff -u src/sys/dev/scsipi/ss.c:1.87 src/sys/dev/scsipi/ss.c:1.88
--- src/sys/dev/scsipi/ss.c:1.87	Sun Nov 20 02:38:24 2016
+++ src/sys/dev/scsipi/ss.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ss.c,v 1.87 2016/11/20 02:38:24 pgoyette Exp $	*/
+/*	$NetBSD: ss.c,v 1.88 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1995 Kenneth Stailey.  All rights reserved.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ss.c,v 1.87 2016/11/20 02:38:24 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ss.c,v 1.88 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -100,7 +100,7 @@ const struct cdevsw ss_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = nokqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_OTHER
+	.d_flag = D_OTHER | D_MPSAFE
 };
 
 static void	ssstrategy(struct buf *);
@@ -199,7 +199,9 @@ static int
 ssdetach(device_t self, int flags)
 {
 	struct ss_softc *ss = device_private(self);
-	int s, cmaj, mn;
+	struct scsipi_periph *periph = ss->sc_periph;
+	struct scsipi_channel *chan = periph->periph_channel;
+	int cmaj, mn;
 
 	/* locate the major number */
 	cmaj = cdevsw_lookup_major(&ss_cdevsw);
@@ -207,15 +209,15 @@ ssdetach(device_t self, int flags)
 	/* kill any pending restart */
 	callout_stop(&ss->sc_callout);
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 
 	/* Kill off any queued buffers. */
 	bufq_drain(ss->buf_queue);
 
 	/* Kill off any pending commands. */
-	scsipi_kill_pending(ss->sc_periph);
+	scsipi_kill_pending(periph);
 
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 
 	bufq_free(ss->buf_queue);
 
@@ -388,7 +390,7 @@ ssstrategy(struct buf *bp)
 {
 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(bp->b_dev));
 	struct scsipi_periph *periph = ss->sc_periph;
-	int s;
+	struct scsipi_channel *chan = periph->periph_channel;
 
 	SC_DEBUG(ss->sc_periph, SCSIPI_DB1,
 	    ("ssstrategy %d bytes @ blk %" PRId64 "\n", bp->b_bcount,
@@ -416,7 +418,7 @@ ssstrategy(struct buf *bp)
 	if (bp->b_bcount == 0)
 		goto done;
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 
 	/*
 	 * Place it in the queue of activities for this scanner
@@ -430,9 +432,9 @@ ssstrategy(struct buf *bp)
 	 * not doing anything, otherwise just wait for completion
 	 * (All a bit silly if we're only allowing 1 open but..)
 	 */
-	ssstart(ss->sc_periph);
+	ssstart(periph);
 
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 	return;
 done:
 	/* Correctly set the buf to indicate a completed xfer */
@@ -452,7 +454,7 @@ done:
  * This routine is also called after other non-queued requests
  * have been made of the scsi driver, to ensure that the queue
  * continues to be drained.
- * ssstart() is called at splbio
+ * ssstart() is called with channel lock held.
  */
 static void
 ssstart(struct scsipi_periph *periph)
@@ -467,7 +469,7 @@ ssstart(struct scsipi_periph *periph)
 		/* if a special awaits, let it proceed first */
 		if (periph->periph_flags & PERIPH_WAITING) {
 			periph->periph_flags &= ~PERIPH_WAITING;
-			wakeup((void *)periph);
+			cv_broadcast(periph_cv_periph(periph));
 			return;
 		}
 
@@ -487,9 +489,12 @@ ssstart(struct scsipi_periph *periph)
 void
 ssrestart(void *v)
 {
-	int s = splbio();
-	ssstart((struct scsipi_periph *)v);
-	splx(s);
+	struct scsipi_periph *periph = v;
+	struct scsipi_channel *chan = periph->periph_channel;
+
+	mutex_enter(chan_mtx(chan));
+	ssstart(periph);
+	mutex_exit(chan_mtx(chan));
 }
 
 static void

Index: src/sys/dev/scsipi/ss_mustek.c
diff -u src/sys/dev/scsipi/ss_mustek.c:1.42 src/sys/dev/scsipi/ss_mustek.c:1.43
--- src/sys/dev/scsipi/ss_mustek.c:1.42	Fri Oct 25 16:04:57 2013
+++ src/sys/dev/scsipi/ss_mustek.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ss_mustek.c,v 1.42 2013/10/25 16:04:57 martin Exp $	*/
+/*	$NetBSD: ss_mustek.c,v 1.43 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1995 Joachim Koenig-Baltes.  All rights reserved.
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ss_mustek.c,v 1.42 2013/10/25 16:04:57 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ss_mustek.c,v 1.43 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -466,7 +466,7 @@ mustek_read(struct ss_softc *ss, struct 
 	_lto3b(lines_to_read, cmd.length);
 
 	/* go ask the adapter to do all this for us */
-	xs = scsipi_make_xs(periph,
+	xs = scsipi_make_xs_locked(periph,
 	    (struct scsipi_generic *) &cmd, sizeof(cmd),
 	    (u_char *) bp->b_data, bp->b_bcount,
 	    MUSTEK_RETRIES, 10000, bp,
@@ -532,7 +532,7 @@ mustek_get_status(struct ss_softc *ss, i
 		    (timeout-- <= 0))
 			break;
 		/* please wait a second */
-		tsleep((void *)mustek_get_status, PRIBIO + 1, "mtkrdy", hz);
+		kpause("mtkrdy", false, hz, NULL);
 	}
 
 	if (update) {

Index: src/sys/dev/scsipi/ss_scanjet.c
diff -u src/sys/dev/scsipi/ss_scanjet.c:1.53 src/sys/dev/scsipi/ss_scanjet.c:1.54
--- src/sys/dev/scsipi/ss_scanjet.c:1.53	Fri Oct 25 16:05:47 2013
+++ src/sys/dev/scsipi/ss_scanjet.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ss_scanjet.c,v 1.53 2013/10/25 16:05:47 martin Exp $	*/
+/*	$NetBSD: ss_scanjet.c,v 1.54 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1995 Kenneth Stailey.  All rights reserved.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ss_scanjet.c,v 1.53 2013/10/25 16:05:47 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ss_scanjet.c,v 1.54 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -266,7 +266,7 @@ scanjet_read(struct ss_softc *ss, struct
 	_lto3b(bp->b_bcount, cmd.len);
 
 	/* go ask the adapter to do all this for us */
-	xs = scsipi_make_xs(periph,
+	xs = scsipi_make_xs_locked(periph,
 	    (struct scsipi_generic *)&cmd, sizeof(cmd),
 	    (u_char *)bp->b_data, bp->b_bcount,
 	    SCANJET_RETRIES, 100000, bp,

Index: src/sys/dev/scsipi/st.c
diff -u src/sys/dev/scsipi/st.c:1.229 src/sys/dev/scsipi/st.c:1.230
--- src/sys/dev/scsipi/st.c:1.229	Sun Nov 20 02:38:24 2016
+++ src/sys/dev/scsipi/st.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: st.c,v 1.229 2016/11/20 02:38:24 pgoyette Exp $ */
+/*	$NetBSD: st.c,v 1.230 2016/11/20 15:37:19 mlelstv Exp $ */
 
 /*-
  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@@ -50,7 +50,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: st.c,v 1.229 2016/11/20 02:38:24 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: st.c,v 1.230 2016/11/20 15:37:19 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_scsi.h"
@@ -114,7 +114,7 @@ const struct bdevsw st_bdevsw = {
 	.d_dump = stdump,
 	.d_psize = nosize,
 	.d_discard = nodiscard,
-	.d_flag = D_TAPE
+	.d_flag = D_TAPE | D_MPSAFE
 };
 
 const struct cdevsw st_cdevsw = {
@@ -129,7 +129,7 @@ const struct cdevsw st_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = nokqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_TAPE
+	.d_flag = D_TAPE | D_MPSAFE
 };
 
 /*
@@ -431,7 +431,9 @@ int
 stdetach(device_t self, int flags)
 {
 	struct st_softc *st = device_private(self);
-	int s, bmaj, cmaj, mn;
+	struct scsipi_periph *periph = st->sc_periph;
+	struct scsipi_channel *chan = periph->periph_channel;
+	int bmaj, cmaj, mn;
 
 	/* locate the major number */
 	bmaj = bdevsw_lookup_major(&st_bdevsw);
@@ -440,7 +442,7 @@ stdetach(device_t self, int flags)
 	/* kill any pending restart */
 	callout_stop(&st->sc_callout);
 
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 
 	/* Kill off any queued buffers. */
 	bufq_drain(st->buf_queue);
@@ -448,7 +450,7 @@ stdetach(device_t self, int flags)
 	/* Kill off any pending commands. */
 	scsipi_kill_pending(st->sc_periph);
 
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 
 	bufq_free(st->buf_queue);
 
@@ -1042,9 +1044,10 @@ static void
 ststrategy(struct buf *bp)
 {
 	struct st_softc *st = device_lookup_private(&st_cd, STUNIT(bp->b_dev));
-	int s;
+	struct scsipi_periph *periph = st->sc_periph;
+	struct scsipi_channel *chan = periph->periph_channel;
 
-	SC_DEBUG(st->sc_periph, SCSIPI_DB1,
+	SC_DEBUG(periph, SCSIPI_DB1,
 	    ("ststrategy %d bytes @ blk %" PRId64 "\n", bp->b_bcount,
 	        bp->b_blkno));
 	/* If it's a null transfer, return immediately */
@@ -1074,7 +1077,7 @@ ststrategy(struct buf *bp)
 		bp->b_error = EIO;
 		goto abort;
 	}
-	s = splbio();
+	mutex_enter(chan_mtx(chan));
 
 	/*
 	 * Place it in the queue of activities for this tape
@@ -1088,9 +1091,9 @@ ststrategy(struct buf *bp)
 	 * not doing anything, otherwise just wait for completion
 	 * (All a bit silly if we're only allowing 1 open but..)
 	 */
-	ststart(st->sc_periph);
+	ststart(periph);
 
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 	return;
 abort:
 	/*
@@ -1114,7 +1117,7 @@ abort:
  * This routine is also called after other non-queued requests
  * have been made of the scsi driver, to ensure that the queue
  * continues to be drained.
- * ststart() is called at splbio
+ * ststart() is called with channel lock held
  */
 static void
 ststart(struct scsipi_periph *periph)
@@ -1131,7 +1134,7 @@ ststart(struct scsipi_periph *periph)
 		/* if a special awaits, let it proceed first */
 		if (periph->periph_flags & PERIPH_WAITING) {
 			periph->periph_flags &= ~PERIPH_WAITING;
-			wakeup((void *)periph);
+			cv_broadcast(periph_cv_periph(periph));
 			return;
 		}
 
@@ -1230,7 +1233,7 @@ ststart(struct scsipi_periph *periph)
 		st->flags &= ~ST_POSUPDATED;
 
 		/* go ask the adapter to do all this for us */
-		xs = scsipi_make_xs(periph,
+		xs = scsipi_make_xs_locked(periph,
 		    (struct scsipi_generic *)&cmd, sizeof(cmd),
 		    (u_char *)bp->b_data, bp->b_bcount,
 		    0, ST_IO_TIME, bp, flags);
@@ -1263,9 +1266,12 @@ ststart(struct scsipi_periph *periph)
 static void
 strestart(void *v)
 {
-	int s = splbio();
+	struct scsipi_periph *periph = (struct scsipi_periph *)v;
+	struct scsipi_channel *chan = periph->periph_channel;
+
+	mutex_enter(chan_mtx(chan));
 	ststart((struct scsipi_periph *)v);
-	splx(s);
+	mutex_exit(chan_mtx(chan));
 }
 
 static void

Index: src/sys/dev/scsipi/uk.c
diff -u src/sys/dev/scsipi/uk.c:1.64 src/sys/dev/scsipi/uk.c:1.65
--- src/sys/dev/scsipi/uk.c:1.64	Fri Aug  5 17:04:58 2016
+++ src/sys/dev/scsipi/uk.c	Sun Nov 20 15:37:19 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: uk.c,v 1.64 2016/08/05 17:04:58 maya Exp $	*/
+/*	$NetBSD: uk.c,v 1.65 2016/11/20 15:37:19 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uk.c,v 1.64 2016/08/05 17:04:58 maya Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uk.c,v 1.65 2016/11/20 15:37:19 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -87,7 +87,7 @@ const struct cdevsw uk_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = nokqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_OTHER
+	.d_flag = D_OTHER | D_MPSAFE
 };
 
 static int

Reply via email to