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