summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2017-05-26 10:59:56 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2017-05-26 10:59:56 +0000
commit4cf2c3c49b34d5cd5af54eab85772d0bac0df98f (patch)
tree0530b60ceabec3f4b5dff6a13f523dce7fd3846c /sys/dev
parente6363ef8fd9795cf04e7990704e056c7dafc67cb (diff)
Move vioblk and vioscsi more fully into the world of iopool and
'modern' scsi. Eliminates use of XS_NO_CCB. Resource optimization to follow. ok sf@, "makes sense" dlg@ earlier version
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pv/vioblk.c106
-rw-r--r--sys/dev/pv/vioscsi.c37
-rw-r--r--sys/dev/pv/virtio.c33
-rw-r--r--sys/dev/pv/virtiovar.h3
4 files changed, 140 insertions, 39 deletions
diff --git a/sys/dev/pv/vioblk.c b/sys/dev/pv/vioblk.c
index 3a7c820376f..c791f4c9ec3 100644
--- a/sys/dev/pv/vioblk.c
+++ b/sys/dev/pv/vioblk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vioblk.c,v 1.2 2017/01/21 11:33:01 reyk Exp $ */
+/* $OpenBSD: vioblk.c,v 1.3 2017/05/26 10:59:55 krw Exp $ */
/*
* Copyright (c) 2012 Stefan Fritsch.
@@ -102,6 +102,7 @@ struct vioblk_softc {
struct scsi_adapter sc_switch;
struct scsi_link sc_link;
+ struct scsi_iopool sc_iopool;
int sc_notify_on_empty;
@@ -122,6 +123,9 @@ void vioblk_scsi_cmd(struct scsi_xfer *);
int vioblk_dev_probe(struct scsi_link *);
void vioblk_dev_free(struct scsi_link *);
+void *vioblk_req_get(void *);
+void vioblk_req_put(void *, void *);
+
void vioblk_scsi_inq(struct scsi_xfer *);
void vioblk_scsi_capacity(struct scsi_xfer *);
void vioblk_scsi_capacity16(struct scsi_xfer *);
@@ -227,7 +231,10 @@ vioblk_attach(struct device *parent, struct device *self, void *aux)
sc->sc_switch.dev_probe = vioblk_dev_probe;
sc->sc_switch.dev_free = vioblk_dev_free;
+ scsi_iopool_init(&sc->sc_iopool, sc, vioblk_req_get, vioblk_req_put);
+
sc->sc_link.adapter = &sc->sc_switch;
+ sc->sc_link.pool = &sc->sc_iopool;
sc->sc_link.adapter_softc = self;
sc->sc_link.adapter_buswidth = 2;
sc->sc_link.luns = 1;
@@ -248,6 +255,64 @@ err:
return;
}
+/*
+ * vioblk_req_get() provides the SCSI layer with all the
+ * resources necessary to start an I/O on the device.
+ *
+ * Since the size of the I/O is unknown at this time the
+ * resouces allocated (a.k.a. reserved) must be sufficient
+ * to allow the maximum possible I/O size.
+ *
+ * When the I/O is actually attempted via vioblk_scsi_cmd()
+ * excess resources will be returned via virtio_enqueue_trim().
+ */
+void *
+vioblk_req_get(void *cookie)
+{
+ struct vioblk_softc *sc = cookie;
+ struct virtqueue *vq = &sc->sc_vq[0];
+ struct virtio_blk_req *vr = NULL;
+ int r, s, slot;
+
+ s = splbio();
+
+ r = virtio_enqueue_prep(vq, &slot);
+ if (r) {
+ DBGPRINT("virtio_enqueue_prep: %d, vq_num: %d, sc_queued: %d",
+ r, vq->vq_num, sc->sc_queued);
+ splx(s);
+ return NULL;
+ }
+ vr = &sc->sc_reqs[slot];
+ r = virtio_enqueue_reserve(vq, slot, ALLOC_SEGS);
+ if (r) {
+ DBGPRINT("virtio_enqueue_reserve: %d", r);
+ splx(s);
+ return NULL;
+ }
+
+ splx(s);
+
+ return vr;
+}
+
+void
+vioblk_req_put(void *cookie, void *io)
+{
+ struct vioblk_softc *sc = cookie;
+ struct virtqueue *vq = &sc->sc_vq[0];
+ struct virtio_blk_req *vr = io;
+ int s, slot = vr - sc->sc_reqs;
+
+ s = splbio();
+
+ vr->vr_len = VIOBLK_DONE;
+ virtio_enqueue_trim(vq, slot, ALLOC_SEGS);
+ virtio_dequeue_commit(vq, slot);
+
+ splx(s);
+}
+
int
vioblk_vq_done(struct virtqueue *vq)
{
@@ -285,6 +350,7 @@ vioblk_vq_done1(struct vioblk_softc *sc, struct virtio_softc *vsc,
bus_dmamap_sync(vsc->sc_dmat, vr->vr_payload, 0, vr->vr_len,
(vr->vr_hdr.type == VIRTIO_BLK_T_IN) ?
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(vsc->sc_dmat, vr->vr_payload);
}
bus_dmamap_sync(vsc->sc_dmat, vr->vr_cmdsts,
sizeof(struct virtio_blk_req_hdr), sizeof(uint8_t),
@@ -300,9 +366,6 @@ vioblk_vq_done1(struct vioblk_softc *sc, struct virtio_softc *vsc,
xs->resid = xs->datalen - vr->vr_len;
}
scsi_done(xs);
- vr->vr_len = VIOBLK_DONE;
-
- virtio_dequeue_commit(vq, slot);
}
void
@@ -327,7 +390,6 @@ vioblk_reset(struct vioblk_softc *sc)
xs->error = XS_DRIVER_STUFFUP;
xs->resid = xs->datalen;
scsi_done(xs);
- vr->vr_len = VIOBLK_DONE;
}
}
@@ -339,7 +401,7 @@ vioblk_scsi_cmd(struct scsi_xfer *xs)
struct virtio_softc *vsc = sc->sc_virtio;
struct virtio_blk_req *vr;
int len, s, timeout, isread, slot, ret, nsegs;
- int error = XS_NO_CCB;
+ int error = XS_DRIVER_STUFFUP;
struct scsi_rw *rw;
struct scsi_rw_big *rwb;
struct scsi_rw_12 *rw12;
@@ -420,15 +482,8 @@ vioblk_scsi_cmd(struct scsi_xfer *xs)
}
s = splbio();
- ret = virtio_enqueue_prep(vq, &slot);
- if (ret) {
- DBGPRINT("virtio_enqueue_prep: %d, vq_num: %d, sc_queued: %d",
- ret, vq->vq_num, sc->sc_queued);
- vioblk_scsi_done(xs, XS_NO_CCB);
- splx(s);
- return;
- }
- vr = &sc->sc_reqs[slot];
+ vr = xs->io;
+ slot = vr - sc->sc_reqs;
if (operation != VIRTIO_BLK_T_FLUSH) {
len = MIN(xs->datalen, sector_count * VIRTIO_BLK_SECTOR_SIZE);
ret = bus_dmamap_load(vsc->sc_dmat, vr->vr_payload,
@@ -438,19 +493,21 @@ vioblk_scsi_cmd(struct scsi_xfer *xs)
if (ret) {
printf("%s: bus_dmamap_load: %d", __func__, ret);
error = XS_DRIVER_STUFFUP;
- goto out_enq_abort;
+ goto out_done;
}
nsegs = vr->vr_payload->dm_nsegs + 2;
} else {
len = 0;
nsegs = 2;
}
- ret = virtio_enqueue_reserve(vq, slot, nsegs);
- if (ret) {
- DBGPRINT("virtio_enqueue_reserve: %d", ret);
- bus_dmamap_unload(vsc->sc_dmat, vr->vr_payload);
- goto out_done;
- }
+
+ /*
+ * Adjust reservation to the number needed, or virtio gets upset. Note
+ * that it may trim UP if 'xs' is being recycled w/o getting a new
+ * reservation!
+ */
+ virtio_enqueue_trim(vq, slot, nsegs);
+
vr->vr_xs = xs;
vr->vr_hdr.type = operation;
vr->vr_hdr.ioprio = 0;
@@ -504,12 +561,9 @@ vioblk_scsi_cmd(struct scsi_xfer *xs)
splx(s);
return;
-out_enq_abort:
- virtio_enqueue_abort(vq, slot);
out_done:
- vioblk_scsi_done(xs, error);
- vr->vr_len = VIOBLK_DONE;
splx(s);
+ vioblk_scsi_done(xs, error);
}
void
diff --git a/sys/dev/pv/vioscsi.c b/sys/dev/pv/vioscsi.c
index 1b8daab6502..8add3ed2b95 100644
--- a/sys/dev/pv/vioscsi.c
+++ b/sys/dev/pv/vioscsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vioscsi.c,v 1.7 2017/05/15 19:02:16 sf Exp $ */
+/* $OpenBSD: vioscsi.c,v 1.8 2017/05/26 10:59:55 krw Exp $ */
/*
* Copyright (c) 2013 Google Inc.
*
@@ -237,15 +237,14 @@ vioscsi_scsi_cmd(struct scsi_xfer *xs)
nsegs += vr->vr_data->dm_nsegs;
}
+ /*
+ * Adjust reservation to the number needed, or virtio gets upset. Note
+ * that it may trim UP if 'xs' is being recycled w/o getting a new
+ * reservation!
+ */
int s = splbio();
- int r = virtio_enqueue_reserve(vq, slot, nsegs);
+ virtio_enqueue_trim(vq, slot, nsegs);
splx(s);
- if (r) {
- xs->error = XS_NO_CCB;
- xs->resid = xs->datalen;
- scsi_done(xs);
- return;
- }
bus_dmamap_sync(vsc->sc_dmat, vr->vr_control,
offsetof(struct vioscsi_req, vr_req),
@@ -370,19 +369,34 @@ vioscsi_vq_done(struct virtqueue *vq)
return (ret);
}
+/*
+ * vioscso_req_get() provides the SCSI layer with all the
+ * resources necessary to start an I/O on the device.
+ *
+ * Since the size of the I/O is unknown at this time the
+ * resouces allocated (a.k.a. reserved) must be sufficient
+ * to allow the maximum possible I/O size.
+ *
+ * When the I/O is actually attempted via vioscsi_scsi_cmd()
+ * excess resources will be returned via virtio_enqueue_trim().
+ */
void *
vioscsi_req_get(void *cookie)
{
struct vioscsi_softc *sc = cookie;
struct virtqueue *vq = &sc->sc_vqs[2];
struct vioscsi_req *vr = NULL;
- int s, slot;
+ int r, s, slot;
s = splbio();
- if (virtio_enqueue_prep(vq, &slot) == 0)
- vr = &sc->sc_reqs[slot];
+ r = virtio_enqueue_prep(vq, &slot);
+ if (r == 0)
+ r = virtio_enqueue_reserve(vq, slot, ALLOC_SEGS);
splx(s);
+ if (r != 0)
+ return NULL;
+ vr = &sc->sc_reqs[slot];
if (vr == NULL)
return NULL;
@@ -407,6 +421,7 @@ vioscsi_req_put(void *cookie, void *io)
DPRINTF("vioscsi_req_put: %p, %d\n", vr, slot);
int s = splbio();
+ virtio_enqueue_trim(vq, slot, ALLOC_SEGS);
if (vr->vr_state == DONE) {
virtio_dequeue_commit(vq, slot);
} else if (vr->vr_state != ALLOC) {
diff --git a/sys/dev/pv/virtio.c b/sys/dev/pv/virtio.c
index e892971726f..3ee0d253064 100644
--- a/sys/dev/pv/virtio.c
+++ b/sys/dev/pv/virtio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: virtio.c,v 1.1 2017/01/21 11:23:01 reyk Exp $ */
+/* $OpenBSD: virtio.c,v 1.2 2017/05/26 10:59:55 krw Exp $ */
/* $NetBSD: virtio.c,v 1.3 2011/11/02 23:05:52 njoly Exp $ */
/*
@@ -709,6 +709,37 @@ virtio_enqueue_abort(struct virtqueue *vq, int slot)
}
/*
+ * enqueue_trim: adjust buffer size to given # of segments, a.k.a.
+ * descriptors.
+ */
+void
+virtio_enqueue_trim(struct virtqueue *vq, int slot, int nsegs)
+{
+ struct vring_desc *vd = &vq->vq_desc[0];
+ int i;
+
+ if ((vd[slot].flags & VRING_DESC_F_INDIRECT) == 0) {
+ for (i = 0; i < nsegs; i++) {
+ vd[slot].flags = VRING_DESC_F_NEXT;
+ if (i == (nsegs - 1))
+ vd[slot].flags = 0;
+ slot = vd[slot].next;
+ }
+ } else {
+ struct vq_entry *qe1 = &vq->vq_entries[slot];
+ vd = &vq->vq_desc[qe1->qe_index];
+ vd->len = sizeof(struct vring_desc) * nsegs;
+ vd = vq->vq_indirect;
+ vd += vq->vq_maxnsegs * qe1->qe_index;
+ for (i = 0; i < nsegs; i++) {
+ vd[i].flags = VRING_DESC_F_NEXT;
+ if (i == (nsegs - 1))
+ vd[i].flags = 0;
+ }
+ }
+}
+
+/*
* Dequeue a request.
*/
/*
diff --git a/sys/dev/pv/virtiovar.h b/sys/dev/pv/virtiovar.h
index 8de8cbf158a..036a5c9a52c 100644
--- a/sys/dev/pv/virtiovar.h
+++ b/sys/dev/pv/virtiovar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: virtiovar.h,v 1.1 2017/01/21 11:23:10 reyk Exp $ */
+/* $OpenBSD: virtiovar.h,v 1.2 2017/05/26 10:59:55 krw Exp $ */
/* $NetBSD: virtiovar.h,v 1.1 2011/10/30 12:12:21 hannken Exp $ */
/*
@@ -204,6 +204,7 @@ void virtio_enqueue_commit(struct virtio_softc*, struct virtqueue*, int, int);
#define virtio_notify(sc,vq) virtio_enqueue_commit(sc, vq, -1, 1)
int virtio_enqueue_abort(struct virtqueue*, int);
+void virtio_enqueue_trim(struct virtqueue*, int, int);
int virtio_dequeue(struct virtio_softc*, struct virtqueue*, int *, int *);
int virtio_dequeue_commit(struct virtqueue*, int);