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/2f92d85605c4
branches:  trunk
changeset: 822574:2f92d85605c4
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 dd982dcb0fd5 -r 2f92d85605c4 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