diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2017-05-26 10:59:56 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2017-05-26 10:59:56 +0000 |
commit | 4cf2c3c49b34d5cd5af54eab85772d0bac0df98f (patch) | |
tree | 0530b60ceabec3f4b5dff6a13f523dce7fd3846c /sys/dev | |
parent | e6363ef8fd9795cf04e7990704e056c7dafc67cb (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.c | 106 | ||||
-rw-r--r-- | sys/dev/pv/vioscsi.c | 37 | ||||
-rw-r--r-- | sys/dev/pv/virtio.c | 33 | ||||
-rw-r--r-- | sys/dev/pv/virtiovar.h | 3 |
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); |