Module Name:    src
Committed By:   jdolecek
Date:           Sat Mar 25 18:15:31 UTC 2017

Modified Files:
        src/sys/dev/pci: vioscsi.c
Added Files:
        src/sys/modules/vioscsi: Makefile vioscsi.ioconf

Log Message:
add support for loading vioscsi driver dynamically


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/sys/dev/pci/vioscsi.c
cvs rdiff -u -r0 -r1.1 src/sys/modules/vioscsi/Makefile \
    src/sys/modules/vioscsi/vioscsi.ioconf

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

Modified files:

Index: src/sys/dev/pci/vioscsi.c
diff -u src/sys/dev/pci/vioscsi.c:1.14 src/sys/dev/pci/vioscsi.c:1.15
--- src/sys/dev/pci/vioscsi.c:1.14	Sat Mar 25 18:13:53 2017
+++ src/sys/dev/pci/vioscsi.c	Sat Mar 25 18:15:31 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: vioscsi.c,v 1.14 2017/03/25 18:13:53 jdolecek Exp $	*/
+/*	$NetBSD: vioscsi.c,v 1.15 2017/03/25 18:15:31 jdolecek Exp $	*/
 /*	$OpenBSD: vioscsi.c,v 1.3 2015/03/14 03:38:49 jsg Exp $	*/
 
 /*
@@ -18,13 +18,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vioscsi.c,v 1.14 2017/03/25 18:13:53 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vioscsi.c,v 1.15 2017/03/25 18:15:31 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
 #include <sys/bus.h>
 #include <sys/buf.h>
+#include <sys/module.h>
 
 #include <dev/pci/pcidevs.h>
 #include <dev/pci/pcireg.h>
@@ -66,6 +67,8 @@ struct vioscsi_softc {
 	bus_dma_segment_t        sc_reqs_segs[1];
 
 	u_int32_t		 sc_seg_max;
+
+	kmutex_t		 sc_mutex;
 };
 
 /*      
@@ -76,9 +79,10 @@ struct vioscsi_softc {
 
 static int	 vioscsi_match(device_t, cfdata_t, void *);
 static void	 vioscsi_attach(device_t, device_t, void *);
+static int	 vioscsi_detach(device_t, int);
 
 static int	 vioscsi_alloc_reqs(struct vioscsi_softc *,
-    struct virtio_softc *, int, uint32_t);
+    struct virtio_softc *, int);
 static void	 vioscsi_free_reqs(struct vioscsi_softc *,
     struct virtio_softc *);
 static void	 vioscsi_scsipi_request(struct scsipi_channel *,
@@ -87,6 +91,7 @@ static int	 vioscsi_vq_done(struct virtq
 static void	 vioscsi_req_done(struct vioscsi_softc *, struct virtio_softc *,
     struct vioscsi_req *);
 static struct vioscsi_req *vioscsi_req_get(struct vioscsi_softc *);
+static void	 vioscsi_bad_target(struct scsipi_xfer *);
 
 static const char *const vioscsi_vq_names[] = {
 	"control",
@@ -94,8 +99,9 @@ static const char *const vioscsi_vq_name
 	"request",
 };
 
-CFATTACH_DECL_NEW(vioscsi, sizeof(struct vioscsi_softc),
-    vioscsi_match, vioscsi_attach, NULL, NULL);
+CFATTACH_DECL3_NEW(vioscsi, sizeof(struct vioscsi_softc),
+    vioscsi_match, vioscsi_attach, vioscsi_detach, NULL, NULL, NULL,
+    DVF_DETACH_SHUTDOWN);
 
 static int
 vioscsi_match(device_t parent, cfdata_t match, void *aux)
@@ -127,9 +133,11 @@ vioscsi_attach(device_t parent, device_t
 	sc->sc_dev = self;
 
 	virtio_child_attach_start(vsc, self, ipl, sc->sc_vqs,
-    	    NULL, virtio_vq_intr, VIRTIO_F_PCI_INTR_MSIX,
+	    NULL, virtio_vq_intr, VIRTIO_F_PCI_INTR_MSIX,
 	    0, VIRTIO_COMMON_FLAG_BITS);
 
+	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, ipl);
+
 	uint32_t cmd_per_lun = virtio_read_device_config_4(vsc,
 	    VIRTIO_SCSI_CONFIG_CMD_PER_LUN);
 
@@ -144,13 +152,14 @@ vioscsi_attach(device_t parent, device_t
 
 	sc->sc_seg_max = seg_max;
 
-	for (i = 0; i < __arraycount(sc->sc_vqs); i++) {
+	for(i=0; i < __arraycount(sc->sc_vqs); i++) {
 		rv = virtio_alloc_vq(vsc, &sc->sc_vqs[i], i, MAXPHYS,
-		    1 + howmany(MAXPHYS, NBPG), vioscsi_vq_names[i]);
+		    1 + howmany(MAXPHYS, NBPG),
+		    vioscsi_vq_names[i]);
 		if (rv) {
 			aprint_error_dev(sc->sc_dev,
-			    "failed to allocate virtqueue %zu\n", i);
-			return;
+			    "failed to allocate virtqueue %d\n", i);
+			goto err;
 		}
 
 		if (i == VIOSCSI_VQ_REQUEST)
@@ -158,8 +167,8 @@ vioscsi_attach(device_t parent, device_t
 	}
 
 	qsize = sc->sc_vqs[VIOSCSI_VQ_REQUEST].vq_num;
-	if (vioscsi_alloc_reqs(sc, vsc, qsize, seg_max))
-		return;
+	if (vioscsi_alloc_reqs(sc, vsc, qsize))
+		goto err;
 
 	aprint_normal_dev(sc->sc_dev,
 	    "cmd_per_lun %zu qsize %zu seg_max %zu max_target %zu"
@@ -188,7 +197,7 @@ vioscsi_attach(device_t parent, device_t
 	chan->chan_bustype = &scsi_bustype;
 	chan->chan_channel = 0;
 	chan->chan_ntargets = MIN(max_target, 16);	/* cap reasonably */
-	chan->chan_nluns = MIN(max_lun, 16);		/* cap reasonably */
+	chan->chan_nluns = MIN(max_lun, 1024);		/* cap reasonably */
 	chan->chan_id = 0;
 	chan->chan_flags = SCSIPI_CHAN_NOSETTLE;
 
@@ -205,7 +214,40 @@ err:
 	}
 
 	virtio_child_attach_failed(vsc);
+}
+
+static int
+vioscsi_detach(device_t self, int flags)
+{
+	struct vioscsi_softc *sc = device_private(self);
+	struct virtio_softc *vsc = device_private(device_parent(sc->sc_dev));
+	int rc, i;
+
+	/*
+	 * Dequeue all pending finished requests. Must be done
+	 * before we try to detach children so that we process
+	 * their pending requests while they still exist.
+	 */
+	if (sc->sc_vqs[VIOSCSI_VQ_REQUEST].vq_num > 0)
+		vioscsi_vq_done(&sc->sc_vqs[VIOSCSI_VQ_REQUEST]);
 
+	if ((rc = config_detach_children(self, flags)) != 0)
+		return rc;
+
+	virtio_reset(vsc);
+
+	for (i = 0; i < __arraycount(sc->sc_vqs); i++) {
+		if (sc->sc_vqs[i].vq_num > 0)
+			virtio_free_vq(vsc, &sc->sc_vqs[i]);
+	}
+
+	vioscsi_free_reqs(sc, vsc);
+
+	virtio_child_detach(vsc);
+
+	mutex_destroy(&sc->sc_mutex);
+
+	return 0;
 }
 
 #define XS2DMA(xs) \
@@ -268,25 +310,23 @@ vioscsi_scsipi_request(struct scsipi_cha
 	req = &vr->vr_req;
 	slot = vr - sc->sc_reqs;
 
-	vr->vr_xs = xs;
-
 	/*
 	 * "The only supported format for the LUN field is: first byte set to
 	 * 1, second byte set to target, third and fourth byte representing a
 	 * single level LUN structure, followed by four zero bytes."
 	 */
-	if (periph->periph_target >= 256 || periph->periph_lun >= 16384) {
-		DPRINTF(("%s: bad target %u or lun %u\n", __func__,
-		    periph->periph_target, periph->periph_lun));
+	if (periph->periph_target >= 256 || periph->periph_lun >= 16384
+	    || periph->periph_target < 0 || periph->periph_lun < 0) {
 		goto stuffup;
 	}
+
 	req->lun[0] = 1;
 	req->lun[1] = periph->periph_target - 1;
 	req->lun[2] = 0x40 | ((periph->periph_lun >> 8) & 0x3F);
 	req->lun[3] = periph->periph_lun & 0xFF;
 	memset(req->lun + 4, 0, 4);
-	DPRINTF(("%s: command for %u:%u at slot %d\n", __func__,
-	    periph->periph_target - 1, periph->periph_lun, slot));
+	DPRINTF(("%s: command %p for %d:%d at slot %d\n", __func__,
+	    xs, periph->periph_target, periph->periph_lun, slot));
 
 	/* tag */
 	switch (XS_CTL_TAGTYPE(xs)) {
@@ -352,6 +392,8 @@ nomore:
 		goto nomore;
 	}
 
+	vr->vr_xs = xs;
+
 	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_control,
 	    offsetof(struct vioscsi_req, vr_req),
 	    sizeof(struct virtio_scsi_req_hdr),
@@ -396,7 +438,8 @@ nomore:
 		DPRINTF(("%s: polling timeout\n", __func__));
 		scsipi_done(xs);
 	}
-	DPRINTF(("%s: done (timeout=%d)\n", __func__, timeout));
+	DPRINTF(("%s: command %p done (timeout=%d)\n", __func__,
+	    xs, timeout));
 }
 
 static void
@@ -404,7 +447,6 @@ vioscsi_req_done(struct vioscsi_softc *s
     struct vioscsi_req *vr)
 {
 	struct scsipi_xfer *xs = vr->vr_xs;
-	struct scsi_sense_data *sense = &xs->sense.scsi_sense;
 	size_t sense_len;
 
 	DPRINTF(("%s: enter\n", __func__));
@@ -430,13 +472,7 @@ vioscsi_req_done(struct vioscsi_softc *s
 		xs->error = (sense_len == 0) ? XS_NOERROR : XS_SENSE;
 		break;
 	case VIRTIO_SCSI_S_BAD_TARGET:
-		DPRINTF(("%s: bad target\n", __func__));
-		memset(sense, 0, sizeof(*sense));
-		sense->response_code = 0x70;
-		sense->flags = SKEY_ILLEGAL_REQUEST;
-		xs->error = XS_SENSE;
-		xs->status = 0;
-		xs->resid = 0;
+		vioscsi_bad_target(xs);
 		break;
 	default:
 		DPRINTF(("%s: stuffup: %d\n", __func__, vr->vr_res.response));
@@ -445,13 +481,31 @@ vioscsi_req_done(struct vioscsi_softc *s
 		break;
 	}
 
-	DPRINTF(("%s: done %d, %d, %d\n", __func__,
-	    xs->error, xs->status, xs->resid));
+	DPRINTF(("%s: command %p done %d, %d, %d\n", __func__,
+	    xs, xs->error, xs->status, xs->resid));
 
 	bus_dmamap_unload(virtio_dmat(vsc), vr->vr_data);
 	vr->vr_xs = NULL;
 
+	mutex_exit(&sc->sc_mutex);
 	scsipi_done(xs);
+	mutex_enter(&sc->sc_mutex);
+}
+
+static void
+vioscsi_bad_target(struct scsipi_xfer *xs)
+{
+	struct scsi_sense_data *sense = &xs->sense.scsi_sense;
+
+	DPRINTF(("%s: bad target %d:%d\n", __func__,
+	    xs->xs_periph->periph_target, xs->xs_periph->periph_lun));
+
+	memset(sense, 0, sizeof(*sense));
+	sense->response_code = 0x70;
+	sense->flags = SKEY_ILLEGAL_REQUEST;
+	xs->error = XS_SENSE;
+	xs->status = 0;
+	xs->resid = 0;
 }
 
 static int
@@ -461,10 +515,13 @@ vioscsi_vq_done(struct virtqueue *vq)
 	struct vioscsi_softc *sc = device_private(virtio_child(vsc));
 	int ret = 0;
 
-	DPRINTF(("%s: enter\n", __func__));
+	DPRINTF(("%s: enter %d\n", __func__, vq->vq_index));
+
+	mutex_enter(&sc->sc_mutex);
 
 	for (;;) {
 		int r, slot;
+
 		r = virtio_dequeue(vsc, vq, &slot, NULL);
 		if (r != 0)
 			break;
@@ -478,7 +535,9 @@ vioscsi_vq_done(struct virtqueue *vq)
 		ret = 1;
 	}
 
-	DPRINTF(("%s: exit %d\n", __func__, ret));
+	mutex_exit(&sc->sc_mutex);
+
+	DPRINTF(("%s: exit %d: %d\n", __func__, vq->vq_index, ret));
 
 	return ret;
 }
@@ -488,24 +547,29 @@ vioscsi_req_get(struct vioscsi_softc *sc
 {
 	struct virtio_softc *vsc = device_private(device_parent(sc->sc_dev));
 	struct virtqueue *vq = &sc->sc_vqs[VIOSCSI_VQ_REQUEST];
-	struct vioscsi_req *vr;
+	struct vioscsi_req *vr = NULL;
 	int r, slot;
 
+	mutex_enter(&sc->sc_mutex);
+
 	if ((r = virtio_enqueue_prep(vsc, vq, &slot)) != 0) {
 		DPRINTF(("%s: virtio_enqueue_get error %d\n", __func__, r));
-		return NULL;
+		goto out;
 	}
 	KASSERT(slot < sc->sc_nreqs);
 	vr = &sc->sc_reqs[slot];
 
 	DPRINTF(("%s: %p, %d\n", __func__, vr, slot));
 
+out:
+	mutex_exit(&sc->sc_mutex);
+
 	return vr;
 }
 
-int
+static int
 vioscsi_alloc_reqs(struct vioscsi_softc *sc, struct virtio_softc *vsc,
-    int qsize, uint32_t seg_max)
+    int qsize)
 {
 	size_t allocsize;
 	int r, rsegs, slot;
@@ -544,7 +608,7 @@ vioscsi_alloc_reqs(struct vioscsi_softc 
 		    BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &vr->vr_control);
 		if (r != 0) {
 			aprint_error_dev(sc->sc_dev,
-		    	    "%s: bus_dmamem_create failed, error %d\n",
+		    	    "%s: bus_dmamem_create ctrl failed, error %d\n",
 			    __func__, r);
 			goto cleanup;
 		}
@@ -553,7 +617,7 @@ vioscsi_alloc_reqs(struct vioscsi_softc 
 		    MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &vr->vr_data);
 		if (r != 0) {
 			aprint_error_dev(sc->sc_dev,
-		    	    "%s: bus_dmamem_map failed, error %d\n",
+		    	    "%s: bus_dmamem_create data failed, error %d\n",
 			    __func__, r);
 			goto cleanup;
 		}
@@ -563,7 +627,7 @@ vioscsi_alloc_reqs(struct vioscsi_softc 
 		    BUS_DMA_NOWAIT);
 		if (r != 0) {
 			aprint_error_dev(sc->sc_dev,
-		    	    "%s: bus_dmamap_create ctrl error %d\n",
+		    	    "%s: bus_dmamap_load ctrl error %d\n",
 			    __func__, r);
 			goto cleanup;
 		}
@@ -617,3 +681,32 @@ vioscsi_free_reqs(struct vioscsi_softc *
 	bus_dmamem_free(virtio_dmat(vsc), &sc->sc_reqs_segs[0], 1);
 }
 
+MODULE(MODULE_CLASS_DRIVER, vioscsi, "virtio");
+
+#ifdef _MODULE
+#include "ioconf.c"
+#endif
+
+static int
+vioscsi_modcmd(modcmd_t cmd, void *opaque)
+{
+        int error = 0;
+
+#ifdef _MODULE
+        switch (cmd) {
+        case MODULE_CMD_INIT:
+                error = config_init_component(cfdriver_ioconf_vioscsi,
+                    cfattach_ioconf_vioscsi, cfdata_ioconf_vioscsi);
+                break;
+        case MODULE_CMD_FINI:
+                error = config_fini_component(cfdriver_ioconf_vioscsi,
+                    cfattach_ioconf_vioscsi, cfdata_ioconf_vioscsi);
+                break;
+        default:
+                error = ENOTTY;
+                break;
+        }
+#endif
+
+        return error;
+}

Added files:

Index: src/sys/modules/vioscsi/Makefile
diff -u /dev/null src/sys/modules/vioscsi/Makefile:1.1
--- /dev/null	Sat Mar 25 18:15:31 2017
+++ src/sys/modules/vioscsi/Makefile	Sat Mar 25 18:15:31 2017
@@ -0,0 +1,14 @@
+#	$NetBSD: Makefile,v 1.1 2017/03/25 18:15:31 jdolecek Exp $
+
+.include "../Makefile.inc"
+
+.PATH:	${S}/dev/pci
+
+KMOD=	vioscsi
+IOCONF=	vioscsi.ioconf
+
+SRCS+=	vioscsi.c
+
+DBG+=	-DDEBUG -DDIAGNOSTIC -DLOCKDEBUG
+
+.include <bsd.kmodule.mk>
Index: src/sys/modules/vioscsi/vioscsi.ioconf
diff -u /dev/null src/sys/modules/vioscsi/vioscsi.ioconf:1.1
--- /dev/null	Sat Mar 25 18:15:31 2017
+++ src/sys/modules/vioscsi/vioscsi.ioconf	Sat Mar 25 18:15:31 2017
@@ -0,0 +1,10 @@
+#       $NetBSD: vioscsi.ioconf,v 1.1 2017/03/25 18:15:31 jdolecek Exp $
+
+ioconf vioscsi
+
+include "conf/files"
+include "dev/pci/files.pci"
+
+pseudo-root virtio*
+
+vioscsi* at virtio?

Reply via email to