Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/dev/pci/ld_virtio.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/dev/pci/ld_virtio.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.6 retrieving revision 1.6.4.5 diff -u -p -r1.6 -r1.6.4.5 --- src/sys/dev/pci/ld_virtio.c 2014/07/22 01:55:54 1.6 +++ src/sys/dev/pci/ld_virtio.c 2016/12/05 10:55:03 1.6.4.5 @@ -1,4 +1,4 @@ -/* $NetBSD: ld_virtio.c,v 1.6 2014/07/22 01:55:54 ozaki-r Exp $ */ +/* $NetBSD: ld_virtio.c,v 1.6.4.5 2016/12/05 10:55:03 skrll Exp $ */ /* * Copyright (c) 2010 Minoura Makoto. @@ -26,17 +26,18 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.6 2014/07/22 01:55:54 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.6.4.5 2016/12/05 10:55:03 skrll Exp $"); #include #include #include #include +#include #include #include #include #include -#include +#include #include #include @@ -46,6 +47,8 @@ __KERNEL_RCSID(0, "$NetBSD: ld_virtio.c, #include #include +#include "ioconf.h" + /* * ld_virtioreg: */ @@ -68,6 +71,23 @@ __KERNEL_RCSID(0, "$NetBSD: ld_virtio.c, #define VIRTIO_BLK_F_SCSI (1<<7) #define VIRTIO_BLK_F_FLUSH (1<<9) +/* + * Each block request uses at least two segments - one for the header + * and one for the status. +*/ +#define VIRTIO_BLK_MIN_SEGMENTS 2 + +#define VIRTIO_BLK_FLAG_BITS \ + VIRTIO_COMMON_FLAG_BITS \ + "\x0a""FLUSH" \ + "\x08""SCSI" \ + "\x07""BLK_SIZE" \ + "\x06""RO" \ + "\x05""GEOMETRY" \ + "\x03""SEG_MAX" \ + "\x02""SIZE_MAX" \ + "\x01""BARRIER" + /* Command */ #define VIRTIO_BLK_T_IN 0 #define VIRTIO_BLK_T_OUT 1 @@ -102,12 +122,10 @@ struct ld_virtio_softc { device_t sc_dev; struct virtio_softc *sc_virtio; - struct virtqueue sc_vq[1]; + struct virtqueue sc_vq; struct virtio_blk_req *sc_reqs; - bus_dma_segment_t sc_reqs_segs[1]; - - kmutex_t sc_lock; + bus_dma_segment_t sc_reqs_seg; int sc_readonly; }; @@ -143,7 +161,7 @@ ld_virtio_alloc_reqs(struct ld_virtio_so allocsize = sizeof(struct virtio_blk_req) * qsize; r = bus_dmamem_alloc(sc->sc_virtio->sc_dmat, allocsize, 0, 0, - &sc->sc_reqs_segs[0], 1, &rsegs, BUS_DMA_NOWAIT); + &sc->sc_reqs_seg, 1, &rsegs, BUS_DMA_NOWAIT); if (r != 0) { aprint_error_dev(sc->sc_dev, "DMA memory allocation failed, size %d, " @@ -151,7 +169,7 @@ ld_virtio_alloc_reqs(struct ld_virtio_so goto err_none; } r = bus_dmamem_map(sc->sc_virtio->sc_dmat, - &sc->sc_reqs_segs[0], 1, allocsize, + &sc->sc_reqs_seg, 1, allocsize, &vaddr, BUS_DMA_NOWAIT); if (r != 0) { aprint_error_dev(sc->sc_dev, @@ -188,7 +206,8 @@ ld_virtio_alloc_reqs(struct ld_virtio_so } r = bus_dmamap_create(sc->sc_virtio->sc_dmat, ld->sc_maxxfer, - (ld->sc_maxxfer / NBPG) + 2, + (ld->sc_maxxfer / NBPG) + + VIRTIO_BLK_MIN_SEGMENTS, ld->sc_maxxfer, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, @@ -218,7 +237,7 @@ err_reqs: } bus_dmamem_unmap(sc->sc_virtio->sc_dmat, sc->sc_reqs, allocsize); err_dmamem_alloc: - bus_dmamem_free(sc->sc_virtio->sc_dmat, &sc->sc_reqs_segs[0], 1); + bus_dmamem_free(sc->sc_virtio->sc_dmat, &sc->sc_reqs_seg, 1); err_none: return -1; } @@ -230,25 +249,23 @@ ld_virtio_attach(device_t parent, device struct ld_softc *ld = &sc->sc_ld; struct virtio_softc *vsc = device_private(parent); uint32_t features; - int qsize, maxxfersize; + char buf[256]; + int qsize, maxxfersize, maxnsegs; if (vsc->sc_child != NULL) { aprint_normal(": child already attached for %s; " - "something wrong...\n", - device_xname(parent)); + "something wrong...\n", device_xname(parent)); return; } - aprint_normal("\n"); - aprint_naive("\n"); sc->sc_dev = self; sc->sc_virtio = vsc; vsc->sc_child = self; vsc->sc_ipl = IPL_BIO; - vsc->sc_vqs = &sc->sc_vq[0]; + vsc->sc_vqs = &sc->sc_vq; vsc->sc_nvqs = 1; - vsc->sc_config_change = 0; + vsc->sc_config_change = NULL; vsc->sc_intrhand = virtio_vq_intr; vsc->sc_flags = 0; @@ -263,29 +280,57 @@ ld_virtio_attach(device_t parent, device else sc->sc_readonly = 0; - ld->sc_secsize = 512; + snprintb(buf, sizeof(buf), VIRTIO_BLK_FLAG_BITS, features); + aprint_normal(": Features: %s\n", buf); + aprint_naive("\n"); if (features & VIRTIO_BLK_F_BLK_SIZE) { ld->sc_secsize = virtio_read_device_config_4(vsc, VIRTIO_BLK_CONFIG_BLK_SIZE); - } - maxxfersize = MAXPHYS; -#if 0 /* At least genfs_io assumes maxxfer == MAXPHYS. */ - if (features & VIRTIO_BLK_F_SEG_MAX) { + } else + ld->sc_secsize = 512; + + /* At least genfs_io assumes maxxfer == MAXPHYS. */ + if (features & VIRTIO_BLK_F_SIZE_MAX) { maxxfersize = virtio_read_device_config_4(vsc, - VIRTIO_BLK_CONFIG_SEG_MAX) - * ld->sc_secsize; - if (maxxfersize > MAXPHYS) + VIRTIO_BLK_CONFIG_SIZE_MAX); + if (maxxfersize < MAXPHYS) { + aprint_error_dev(sc->sc_dev, + "Too small SIZE_MAX %dK minimum is %dK\n", + maxxfersize / 1024, MAXPHYS / 1024); + // goto err; maxxfersize = MAXPHYS; - } -#endif + } else if (maxxfersize > MAXPHYS) { + aprint_normal_dev(sc->sc_dev, + "Clip SEG_MAX from %dK to %dK\n", + maxxfersize / 1024, + MAXPHYS / 1024); + maxxfersize = MAXPHYS; + } + } else + maxxfersize = MAXPHYS; + + if (features & VIRTIO_BLK_F_SEG_MAX) { + maxnsegs = virtio_read_device_config_4(vsc, + VIRTIO_BLK_CONFIG_SEG_MAX); + if (maxnsegs < VIRTIO_BLK_MIN_SEGMENTS) { + aprint_error_dev(sc->sc_dev, + "Too small SEG_MAX %d minimum is %d\n", + maxnsegs, VIRTIO_BLK_MIN_SEGMENTS); + maxnsegs = maxxfersize / NBPG; + // goto err; + } + } else + maxnsegs = maxxfersize / NBPG; + + /* 2 for the minimum size */ + maxnsegs += VIRTIO_BLK_MIN_SEGMENTS; - if (virtio_alloc_vq(vsc, &sc->sc_vq[0], 0, - maxxfersize, maxxfersize / NBPG + 2, - "I/O request") != 0) { + if (virtio_alloc_vq(vsc, &sc->sc_vq, 0, maxxfersize, maxnsegs, + "I/O request") != 0) { goto err; } - qsize = sc->sc_vq[0].vq_num; - sc->sc_vq[0].vq_done = ld_virtio_vq_done; + qsize = sc->sc_vq.vq_num; + sc->sc_vq.vq_done = ld_virtio_vq_done; ld->sc_dv = self; ld->sc_secperunit = virtio_read_device_config_8(vsc, @@ -304,14 +349,12 @@ ld_virtio_attach(device_t parent, device if (ld_virtio_alloc_reqs(sc, qsize) < 0) goto err; - mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO); - ld->sc_dump = ld_virtio_dump; ld->sc_flush = NULL; ld->sc_start = ld_virtio_start; ld->sc_flags = LDF_ENABLED; - ldattach(ld); + ldattach(ld, BUFQ_DISK_DEFAULT_STRAT); return; @@ -326,7 +369,7 @@ ld_virtio_start(struct ld_softc *ld, str /* splbio */ struct ld_virtio_softc *sc = device_private(ld->sc_dv); struct virtio_softc *vsc = sc->sc_virtio; - struct virtqueue *vq = &sc->sc_vq[0]; + struct virtqueue *vq = &sc->sc_vq; struct virtio_blk_req *vr; int r; int isread = (bp->b_flags & B_READ); @@ -338,15 +381,23 @@ ld_virtio_start(struct ld_softc *ld, str r = virtio_enqueue_prep(vsc, vq, &slot); if (r != 0) return r; + vr = &sc->sc_reqs[slot]; + KASSERT(vr->vr_bp == NULL); + r = bus_dmamap_load(vsc->sc_dmat, vr->vr_payload, bp->b_data, bp->b_bcount, NULL, ((isread?BUS_DMA_READ:BUS_DMA_WRITE) |BUS_DMA_NOWAIT)); - if (r != 0) + if (r != 0) { + aprint_error_dev(sc->sc_dev, + "payload dmamap failed, error code %d\n", r); + virtio_enqueue_abort(vsc, vq, slot); return r; + } - r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + 2); + r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + + VIRTIO_BLK_MIN_SEGMENTS); if (r != 0) { bus_dmamap_unload(vsc->sc_dmat, vr->vr_payload); return r; @@ -388,6 +439,8 @@ ld_virtio_vq_done1(struct ld_virtio_soft struct virtio_blk_req *vr = &sc->sc_reqs[slot]; struct buf *bp = vr->vr_bp; + vr->vr_bp = NULL; + bus_dmamap_sync(vsc->sc_dmat, vr->vr_cmdsts, 0, sizeof(struct virtio_blk_req_hdr), BUS_DMASYNC_POSTWRITE); @@ -434,7 +487,7 @@ ld_virtio_dump(struct ld_softc *ld, void { struct ld_virtio_softc *sc = device_private(ld->sc_dv); struct virtio_softc *vsc = sc->sc_virtio; - struct virtqueue *vq = &sc->sc_vq[0]; + struct virtqueue *vq = &sc->sc_vq; struct virtio_blk_req *vr; int slot, r; @@ -459,7 +512,8 @@ ld_virtio_dump(struct ld_softc *ld, void if (r != 0) return r; - r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + 2); + r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + + VIRTIO_BLK_MIN_SEGMENTS); if (r != 0) { bus_dmamap_unload(vsc->sc_dmat, vr->vr_payload); return r; @@ -503,7 +557,7 @@ ld_virtio_dump(struct ld_softc *ld, void } else break; } - + bus_dmamap_sync(vsc->sc_dmat, vr->vr_cmdsts, 0, sizeof(struct virtio_blk_req_hdr), BUS_DMASYNC_POSTWRITE); @@ -531,12 +585,12 @@ ld_virtio_detach(device_t self, int flag bus_dma_tag_t dmat = sc->sc_virtio->sc_dmat; int r, i, qsize; - qsize = sc->sc_vq[0].vq_num; + qsize = sc->sc_vq.vq_num; r = ldbegindetach(ld, flags); if (r != 0) return r; virtio_reset(sc->sc_virtio); - virtio_free_vq(sc->sc_virtio, &sc->sc_vq[0]); + virtio_free_vq(sc->sc_virtio, &sc->sc_vq); for (i = 0; i < qsize; i++) { bus_dmamap_destroy(dmat, @@ -546,9 +600,52 @@ ld_virtio_detach(device_t self, int flag } bus_dmamem_unmap(dmat, sc->sc_reqs, sizeof(struct virtio_blk_req) * qsize); - bus_dmamem_free(dmat, &sc->sc_reqs_segs[0], 1); + bus_dmamem_free(dmat, &sc->sc_reqs_seg, 1); ldenddetach(ld); return 0; } + +MODULE(MODULE_CLASS_DRIVER, ld_virtio, "ld,virtio"); + +#ifdef _MODULE +/* + * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd" + * XXX it will be defined in the common-code module + */ +#undef CFDRIVER_DECL +#define CFDRIVER_DECL(name, class, attr) +#include "ioconf.c" +#endif + +static int +ld_virtio_modcmd(modcmd_t cmd, void *opaque) +{ +#ifdef _MODULE + /* + * We ignore the cfdriver_vec[] that ioconf provides, since + * the cfdrivers are attached already. + */ + static struct cfdriver * const no_cfdriver_vec[] = { NULL }; +#endif + int error = 0; + +#ifdef _MODULE + switch (cmd) { + case MODULE_CMD_INIT: + error = config_init_component(no_cfdriver_vec, + cfattach_ioconf_ld_virtio, cfdata_ioconf_ld_virtio); + break; + case MODULE_CMD_FINI: + error = config_fini_component(no_cfdriver_vec, + cfattach_ioconf_ld_virtio, cfdata_ioconf_ld_virtio); + break; + default: + error = ENOTTY; + break; + } +#endif + + return error; +}