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?