Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys add support for loading vioscsi driver dynamically
details: https://anonhg.NetBSD.org/src/rev/e64cfa8eebd3
branches: trunk
changeset: 352323:e64cfa8eebd3
user: jdolecek <jdolecek%NetBSD.org@localhost>
date: Sat Mar 25 18:15:31 2017 +0000
description:
add support for loading vioscsi driver dynamically
diffstat:
sys/dev/pci/vioscsi.c | 173 ++++++++++++++++++++++++++++--------
sys/modules/vioscsi/Makefile | 14 ++
sys/modules/vioscsi/vioscsi.ioconf | 10 ++
3 files changed, 157 insertions(+), 40 deletions(-)
diffs (truncated from 418 to 300 lines):
diff -r b5baa1f26197 -r e64cfa8eebd3 sys/dev/pci/vioscsi.c
--- a/sys/dev/pci/vioscsi.c Sat Mar 25 18:13:53 2017 +0000
+++ b/sys/dev/pci/vioscsi.c Sat Mar 25 18:15:31 2017 +0000
@@ -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 @@
bus_dma_segment_t sc_reqs_segs[1];
u_int32_t sc_seg_max;
+
+ kmutex_t sc_mutex;
};
/*
@@ -76,9 +79,10 @@
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 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 @@
"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 @@
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 @@
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 @@
}
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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;
Home |
Main Index |
Thread Index |
Old Index