[BACK]Return to ld_virtio.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / pci

Annotation of src/sys/dev/pci/ld_virtio.c, Revision 1.30

1.30    ! uwe         1: /*     $NetBSD: ld_virtio.c,v 1.29 2021/01/20 19:46:48 reinoud Exp $   */
1.1       hannken     2:
                      3: /*
                      4:  * Copyright (c) 2010 Minoura Makoto.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     21:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     22:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     23:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     25:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     26:  */
                     27:
                     28: #include <sys/cdefs.h>
1.30    ! uwe        29: __KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.29 2021/01/20 19:46:48 reinoud Exp $");
1.1       hannken    30:
                     31: #include <sys/param.h>
                     32: #include <sys/systm.h>
                     33: #include <sys/kernel.h>
                     34: #include <sys/buf.h>
1.11      jdolecek   35: #include <sys/bufq.h>
1.1       hannken    36: #include <sys/bus.h>
                     37: #include <sys/device.h>
                     38: #include <sys/disk.h>
                     39: #include <sys/mutex.h>
1.12      pgoyette   40: #include <sys/module.h>
1.1       hannken    41:
                     42: #include <dev/ldvar.h>
                     43: #include <dev/pci/virtioreg.h>
                     44: #include <dev/pci/virtiovar.h>
                     45:
1.12      pgoyette   46: #include "ioconf.h"
                     47:
1.1       hannken    48: /*
                     49:  * ld_virtioreg:
                     50:  */
                     51: /* Configuration registers */
                     52: #define VIRTIO_BLK_CONFIG_CAPACITY     0 /* 64bit */
                     53: #define VIRTIO_BLK_CONFIG_SIZE_MAX     8 /* 32bit */
                     54: #define VIRTIO_BLK_CONFIG_SEG_MAX      12 /* 32bit */
                     55: #define VIRTIO_BLK_CONFIG_GEOMETRY_C   16 /* 16bit */
                     56: #define VIRTIO_BLK_CONFIG_GEOMETRY_H   18 /* 8bit */
                     57: #define VIRTIO_BLK_CONFIG_GEOMETRY_S   19 /* 8bit */
                     58: #define VIRTIO_BLK_CONFIG_BLK_SIZE     20 /* 32bit */
1.18      jakllsch   59: #define VIRTIO_BLK_CONFIG_WRITEBACK    32 /* 8bit */
1.1       hannken    60:
                     61: /* Feature bits */
                     62: #define VIRTIO_BLK_F_BARRIER   (1<<0)
                     63: #define VIRTIO_BLK_F_SIZE_MAX  (1<<1)
                     64: #define VIRTIO_BLK_F_SEG_MAX   (1<<2)
                     65: #define VIRTIO_BLK_F_GEOMETRY  (1<<4)
                     66: #define VIRTIO_BLK_F_RO                (1<<5)
                     67: #define VIRTIO_BLK_F_BLK_SIZE  (1<<6)
                     68: #define VIRTIO_BLK_F_SCSI      (1<<7)
                     69: #define VIRTIO_BLK_F_FLUSH     (1<<9)
1.18      jakllsch   70: #define VIRTIO_BLK_F_TOPOLOGY  (1<<10)
                     71: #define VIRTIO_BLK_F_CONFIG_WCE        (1<<11)
1.1       hannken    72:
1.17      jakllsch   73: /*
1.9       christos   74:  * Each block request uses at least two segments - one for the header
                     75:  * and one for the status.
1.17      jakllsch   76: */
1.9       christos   77: #define        VIRTIO_BLK_MIN_SEGMENTS 2
                     78:
1.30    ! uwe        79: #define VIRTIO_BLK_FLAG_BITS                   \
        !            80:        VIRTIO_COMMON_FLAG_BITS                 \
        !            81:        "b\x0b" "CONFIG_WCE\0"                  \
        !            82:        "b\x0a" "TOPOLOGY\0"                    \
        !            83:        "b\x09" "FLUSH\0"                       \
        !            84:        "b\x07" "SCSI\0"                        \
        !            85:        "b\x06" "BLK_SIZE\0"                    \
        !            86:        "b\x05" "RO\0"                          \
        !            87:        "b\x04" "GEOMETRY\0"                    \
        !            88:        "b\x02" "SEG_MAX\0"                     \
        !            89:        "b\x01" "SIZE_MAX\0"                    \
        !            90:        "b\x00" "BARRIER\0"
1.9       christos   91:
1.1       hannken    92: /* Command */
                     93: #define VIRTIO_BLK_T_IN                0
                     94: #define VIRTIO_BLK_T_OUT       1
1.18      jakllsch   95: #define VIRTIO_BLK_T_FLUSH     4
1.1       hannken    96: #define VIRTIO_BLK_T_BARRIER   0x80000000
                     97:
1.21      jakllsch   98: /* Sector */
                     99: #define VIRTIO_BLK_BSIZE       512
                    100:
1.1       hannken   101: /* Status */
                    102: #define VIRTIO_BLK_S_OK                0
                    103: #define VIRTIO_BLK_S_IOERR     1
1.18      jakllsch  104: #define VIRTIO_BLK_S_UNSUPP    2
1.1       hannken   105:
                    106: /* Request header structure */
                    107: struct virtio_blk_req_hdr {
                    108:        uint32_t        type;   /* VIRTIO_BLK_T_* */
                    109:        uint32_t        ioprio;
                    110:        uint64_t        sector;
                    111: } __packed;
1.21      jakllsch  112: /* payload and 1 byte status follows */
1.1       hannken   113:
                    114:
                    115: /*
                    116:  * ld_virtiovar:
                    117:  */
                    118: struct virtio_blk_req {
                    119:        struct virtio_blk_req_hdr       vr_hdr;
                    120:        uint8_t                         vr_status;
                    121:        struct buf                      *vr_bp;
1.20      jakllsch  122: #define DUMMY_VR_BP                            ((void *)1)
1.1       hannken   123:        bus_dmamap_t                    vr_cmdsts;
                    124:        bus_dmamap_t                    vr_payload;
                    125: };
                    126:
                    127: struct ld_virtio_softc {
                    128:        struct ld_softc         sc_ld;
                    129:        device_t                sc_dev;
                    130:
                    131:        struct virtio_softc     *sc_virtio;
1.9       christos  132:        struct virtqueue        sc_vq;
1.1       hannken   133:
                    134:        struct virtio_blk_req   *sc_reqs;
1.9       christos  135:        bus_dma_segment_t       sc_reqs_seg;
1.1       hannken   136:
                    137:        int                     sc_readonly;
1.20      jakllsch  138:
                    139:        enum {
                    140:                SYNC_FREE, SYNC_BUSY, SYNC_DONE
                    141:        }                       sc_sync_use;
                    142:        kcondvar_t              sc_sync_wait;
                    143:        kmutex_t                sc_sync_wait_lock;
                    144:        uint8_t                 sc_sync_status;
1.1       hannken   145: };
                    146:
                    147: static int     ld_virtio_match(device_t, cfdata_t, void *);
                    148: static void    ld_virtio_attach(device_t, device_t, void *);
                    149: static int     ld_virtio_detach(device_t, int);
                    150:
                    151: CFATTACH_DECL_NEW(ld_virtio, sizeof(struct ld_virtio_softc),
                    152:     ld_virtio_match, ld_virtio_attach, ld_virtio_detach, NULL);
                    153:
                    154: static int
                    155: ld_virtio_match(device_t parent, cfdata_t match, void *aux)
                    156: {
1.15      jdolecek  157:        struct virtio_attach_args *va = aux;
1.1       hannken   158:
1.29      reinoud   159:        if (va->sc_childdevid == VIRTIO_DEVICE_ID_BLOCK)
1.1       hannken   160:                return 1;
                    161:
                    162:        return 0;
                    163: }
                    164:
                    165: static int ld_virtio_vq_done(struct virtqueue *);
                    166: static int ld_virtio_dump(struct ld_softc *, void *, int, int);
                    167: static int ld_virtio_start(struct ld_softc *, struct buf *);
1.20      jakllsch  168: static int ld_virtio_ioctl(struct ld_softc *, u_long, void *, int32_t, bool);
1.1       hannken   169:
                    170: static int
                    171: ld_virtio_alloc_reqs(struct ld_virtio_softc *sc, int qsize)
                    172: {
                    173:        int allocsize, r, rsegs, i;
                    174:        struct ld_softc *ld = &sc->sc_ld;
                    175:        void *vaddr;
                    176:
                    177:        allocsize = sizeof(struct virtio_blk_req) * qsize;
1.15      jdolecek  178:        r = bus_dmamem_alloc(virtio_dmat(sc->sc_virtio), allocsize, 0, 0,
1.28      skrll     179:                             &sc->sc_reqs_seg, 1, &rsegs, BUS_DMA_WAITOK);
1.1       hannken   180:        if (r != 0) {
                    181:                aprint_error_dev(sc->sc_dev,
                    182:                                 "DMA memory allocation failed, size %d, "
                    183:                                 "error code %d\n", allocsize, r);
                    184:                goto err_none;
                    185:        }
1.15      jdolecek  186:        r = bus_dmamem_map(virtio_dmat(sc->sc_virtio),
1.9       christos  187:                           &sc->sc_reqs_seg, 1, allocsize,
1.28      skrll     188:                           &vaddr, BUS_DMA_WAITOK);
1.1       hannken   189:        if (r != 0) {
                    190:                aprint_error_dev(sc->sc_dev,
                    191:                                 "DMA memory map failed, "
                    192:                                 "error code %d\n", r);
                    193:                goto err_dmamem_alloc;
                    194:        }
                    195:        sc->sc_reqs = vaddr;
                    196:        memset(vaddr, 0, allocsize);
                    197:        for (i = 0; i < qsize; i++) {
                    198:                struct virtio_blk_req *vr = &sc->sc_reqs[i];
1.15      jdolecek  199:                r = bus_dmamap_create(virtio_dmat(sc->sc_virtio),
1.1       hannken   200:                                      offsetof(struct virtio_blk_req, vr_bp),
                    201:                                      1,
                    202:                                      offsetof(struct virtio_blk_req, vr_bp),
                    203:                                      0,
1.28      skrll     204:                                      BUS_DMA_WAITOK|BUS_DMA_ALLOCNOW,
1.1       hannken   205:                                      &vr->vr_cmdsts);
                    206:                if (r != 0) {
                    207:                        aprint_error_dev(sc->sc_dev,
                    208:                                         "command dmamap creation failed, "
                    209:                                         "error code %d\n", r);
                    210:                        goto err_reqs;
                    211:                }
1.15      jdolecek  212:                r = bus_dmamap_load(virtio_dmat(sc->sc_virtio), vr->vr_cmdsts,
1.1       hannken   213:                                    &vr->vr_hdr,
                    214:                                    offsetof(struct virtio_blk_req, vr_bp),
1.28      skrll     215:                                    NULL, BUS_DMA_WAITOK);
1.1       hannken   216:                if (r != 0) {
                    217:                        aprint_error_dev(sc->sc_dev,
                    218:                                         "command dmamap load failed, "
                    219:                                         "error code %d\n", r);
                    220:                        goto err_reqs;
                    221:                }
1.15      jdolecek  222:                r = bus_dmamap_create(virtio_dmat(sc->sc_virtio),
1.1       hannken   223:                                      ld->sc_maxxfer,
1.9       christos  224:                                      (ld->sc_maxxfer / NBPG) +
                    225:                                      VIRTIO_BLK_MIN_SEGMENTS,
1.2       hannken   226:                                      ld->sc_maxxfer,
1.1       hannken   227:                                      0,
1.28      skrll     228:                                      BUS_DMA_WAITOK|BUS_DMA_ALLOCNOW,
1.1       hannken   229:                                      &vr->vr_payload);
                    230:                if (r != 0) {
                    231:                        aprint_error_dev(sc->sc_dev,
                    232:                                         "payload dmamap creation failed, "
                    233:                                         "error code %d\n", r);
                    234:                        goto err_reqs;
                    235:                }
                    236:        }
                    237:        return 0;
                    238:
                    239: err_reqs:
                    240:        for (i = 0; i < qsize; i++) {
                    241:                struct virtio_blk_req *vr = &sc->sc_reqs[i];
                    242:                if (vr->vr_cmdsts) {
1.15      jdolecek  243:                        bus_dmamap_destroy(virtio_dmat(sc->sc_virtio),
1.1       hannken   244:                                           vr->vr_cmdsts);
                    245:                        vr->vr_cmdsts = 0;
                    246:                }
                    247:                if (vr->vr_payload) {
1.15      jdolecek  248:                        bus_dmamap_destroy(virtio_dmat(sc->sc_virtio),
1.1       hannken   249:                                           vr->vr_payload);
                    250:                        vr->vr_payload = 0;
                    251:                }
                    252:        }
1.15      jdolecek  253:        bus_dmamem_unmap(virtio_dmat(sc->sc_virtio), sc->sc_reqs, allocsize);
1.1       hannken   254: err_dmamem_alloc:
1.15      jdolecek  255:        bus_dmamem_free(virtio_dmat(sc->sc_virtio), &sc->sc_reqs_seg, 1);
1.1       hannken   256: err_none:
                    257:        return -1;
                    258: }
                    259:
                    260: static void
                    261: ld_virtio_attach(device_t parent, device_t self, void *aux)
                    262: {
                    263:        struct ld_virtio_softc *sc = device_private(self);
                    264:        struct ld_softc *ld = &sc->sc_ld;
                    265:        struct virtio_softc *vsc = device_private(parent);
1.29      reinoud   266:        uint64_t features;
1.9       christos  267:        int qsize, maxxfersize, maxnsegs;
1.1       hannken   268:
1.15      jdolecek  269:        if (virtio_child(vsc) != NULL) {
1.1       hannken   270:                aprint_normal(": child already attached for %s; "
1.10      msaitoh   271:                              "something wrong...\n", device_xname(parent));
1.1       hannken   272:                return;
                    273:        }
                    274:
                    275:        sc->sc_dev = self;
                    276:        sc->sc_virtio = vsc;
                    277:
1.15      jdolecek  278:        virtio_child_attach_start(vsc, self, IPL_BIO, &sc->sc_vq,
1.29      reinoud   279:            NULL, virtio_vq_intr, VIRTIO_F_INTR_MSIX,
1.15      jdolecek  280:            (VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_SEG_MAX |
1.20      jakllsch  281:             VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_BLK_SIZE |
                    282:             VIRTIO_BLK_F_FLUSH | VIRTIO_BLK_F_CONFIG_WCE),
1.15      jdolecek  283:            VIRTIO_BLK_FLAG_BITS);
                    284:
                    285:        features = virtio_features(vsc);
1.29      reinoud   286:        if (features == 0)
                    287:                goto err;
1.15      jdolecek  288:
1.1       hannken   289:        if (features & VIRTIO_BLK_F_RO)
                    290:                sc->sc_readonly = 1;
                    291:        else
                    292:                sc->sc_readonly = 0;
                    293:
1.3       hannken   294:        if (features & VIRTIO_BLK_F_BLK_SIZE) {
                    295:                ld->sc_secsize = virtio_read_device_config_4(vsc,
                    296:                                        VIRTIO_BLK_CONFIG_BLK_SIZE);
1.9       christos  297:        } else
1.21      jakllsch  298:                ld->sc_secsize = VIRTIO_BLK_BSIZE;
1.9       christos  299:
                    300:        /* At least genfs_io assumes maxxfer == MAXPHYS. */
                    301:        if (features & VIRTIO_BLK_F_SIZE_MAX) {
1.1       hannken   302:                maxxfersize = virtio_read_device_config_4(vsc,
1.9       christos  303:                    VIRTIO_BLK_CONFIG_SIZE_MAX);
                    304:                if (maxxfersize < MAXPHYS) {
                    305:                        aprint_error_dev(sc->sc_dev,
                    306:                            "Too small SIZE_MAX %dK minimum is %dK\n",
                    307:                            maxxfersize / 1024, MAXPHYS / 1024);
                    308:                        // goto err;
                    309:                        maxxfersize = MAXPHYS;
                    310:                } else if (maxxfersize > MAXPHYS) {
                    311:                        aprint_normal_dev(sc->sc_dev,
                    312:                            "Clip SEG_MAX from %dK to %dK\n",
                    313:                            maxxfersize / 1024,
                    314:                            MAXPHYS / 1024);
1.1       hannken   315:                        maxxfersize = MAXPHYS;
1.9       christos  316:                }
                    317:        } else
                    318:                maxxfersize = MAXPHYS;
                    319:
                    320:        if (features & VIRTIO_BLK_F_SEG_MAX) {
                    321:                maxnsegs = virtio_read_device_config_4(vsc,
                    322:                    VIRTIO_BLK_CONFIG_SEG_MAX);
                    323:                if (maxnsegs < VIRTIO_BLK_MIN_SEGMENTS) {
                    324:                        aprint_error_dev(sc->sc_dev,
                    325:                            "Too small SEG_MAX %d minimum is %d\n",
                    326:                            maxnsegs, VIRTIO_BLK_MIN_SEGMENTS);
                    327:                        maxnsegs = maxxfersize / NBPG;
                    328:                        // goto err;
                    329:                }
                    330:        } else
                    331:                maxnsegs = maxxfersize / NBPG;
                    332:
                    333:        /* 2 for the minimum size */
                    334:        maxnsegs += VIRTIO_BLK_MIN_SEGMENTS;
1.1       hannken   335:
1.9       christos  336:        if (virtio_alloc_vq(vsc, &sc->sc_vq, 0, maxxfersize, maxnsegs,
                    337:            "I/O request") != 0) {
1.1       hannken   338:                goto err;
                    339:        }
1.9       christos  340:        qsize = sc->sc_vq.vq_num;
                    341:        sc->sc_vq.vq_done = ld_virtio_vq_done;
1.1       hannken   342:
1.15      jdolecek  343:        if (virtio_child_attach_finish(vsc) != 0)
                    344:                goto err;
                    345:
1.1       hannken   346:        ld->sc_dv = self;
                    347:        ld->sc_secperunit = virtio_read_device_config_8(vsc,
1.21      jakllsch  348:            VIRTIO_BLK_CONFIG_CAPACITY) / (ld->sc_secsize / VIRTIO_BLK_BSIZE);
1.1       hannken   349:        ld->sc_maxxfer = maxxfersize;
                    350:        if (features & VIRTIO_BLK_F_GEOMETRY) {
                    351:                ld->sc_ncylinders = virtio_read_device_config_2(vsc,
                    352:                                        VIRTIO_BLK_CONFIG_GEOMETRY_C);
                    353:                ld->sc_nheads     = virtio_read_device_config_1(vsc,
                    354:                                        VIRTIO_BLK_CONFIG_GEOMETRY_H);
                    355:                ld->sc_nsectors   = virtio_read_device_config_1(vsc,
                    356:                                        VIRTIO_BLK_CONFIG_GEOMETRY_S);
                    357:        }
1.20      jakllsch  358:        ld->sc_maxqueuecnt = qsize - 1; /* reserve slot for dumps, flushes */
1.1       hannken   359:
                    360:        if (ld_virtio_alloc_reqs(sc, qsize) < 0)
                    361:                goto err;
                    362:
1.20      jakllsch  363:        cv_init(&sc->sc_sync_wait, "vblksync");
                    364:        mutex_init(&sc->sc_sync_wait_lock, MUTEX_DEFAULT, IPL_BIO);
                    365:        sc->sc_sync_use = SYNC_FREE;
                    366:
1.1       hannken   367:        ld->sc_dump = ld_virtio_dump;
                    368:        ld->sc_start = ld_virtio_start;
1.20      jakllsch  369:        ld->sc_ioctl = ld_virtio_ioctl;
1.1       hannken   370:
1.16      mlelstv   371:        ld->sc_flags = LDF_ENABLED | LDF_MPSAFE;
1.11      jdolecek  372:        ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
1.1       hannken   373:
                    374:        return;
                    375:
                    376: err:
1.15      jdolecek  377:        virtio_child_attach_failed(vsc);
1.1       hannken   378:        return;
                    379: }
                    380:
                    381: static int
                    382: ld_virtio_start(struct ld_softc *ld, struct buf *bp)
                    383: {
                    384:        /* splbio */
                    385:        struct ld_virtio_softc *sc = device_private(ld->sc_dv);
                    386:        struct virtio_softc *vsc = sc->sc_virtio;
1.9       christos  387:        struct virtqueue *vq = &sc->sc_vq;
1.1       hannken   388:        struct virtio_blk_req *vr;
                    389:        int r;
                    390:        int isread = (bp->b_flags & B_READ);
                    391:        int slot;
                    392:
                    393:        if (sc->sc_readonly && !isread)
                    394:                return EIO;
                    395:
                    396:        r = virtio_enqueue_prep(vsc, vq, &slot);
                    397:        if (r != 0)
                    398:                return r;
1.9       christos  399:
1.1       hannken   400:        vr = &sc->sc_reqs[slot];
1.9       christos  401:        KASSERT(vr->vr_bp == NULL);
                    402:
1.15      jdolecek  403:        r = bus_dmamap_load(virtio_dmat(vsc), vr->vr_payload,
1.1       hannken   404:                            bp->b_data, bp->b_bcount, NULL,
                    405:                            ((isread?BUS_DMA_READ:BUS_DMA_WRITE)
                    406:                             |BUS_DMA_NOWAIT));
1.9       christos  407:        if (r != 0) {
                    408:                aprint_error_dev(sc->sc_dev,
                    409:                    "payload dmamap failed, error code %d\n", r);
                    410:                virtio_enqueue_abort(vsc, vq, slot);
1.1       hannken   411:                return r;
1.9       christos  412:        }
1.1       hannken   413:
1.9       christos  414:        r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs +
                    415:            VIRTIO_BLK_MIN_SEGMENTS);
1.1       hannken   416:        if (r != 0) {
1.15      jdolecek  417:                bus_dmamap_unload(virtio_dmat(vsc), vr->vr_payload);
1.1       hannken   418:                return r;
                    419:        }
                    420:
                    421:        vr->vr_bp = bp;
1.29      reinoud   422:        vr->vr_hdr.type   = virtio_rw32(vsc,
                    423:                        isread ? VIRTIO_BLK_T_IN : VIRTIO_BLK_T_OUT);
                    424:        vr->vr_hdr.ioprio = virtio_rw32(vsc, 0);
                    425:        vr->vr_hdr.sector = virtio_rw64(vsc,
                    426:                        bp->b_rawblkno * sc->sc_ld.sc_secsize /
                    427:                        VIRTIO_BLK_BSIZE);
1.1       hannken   428:
1.15      jdolecek  429:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
1.1       hannken   430:                        0, sizeof(struct virtio_blk_req_hdr),
                    431:                        BUS_DMASYNC_PREWRITE);
1.15      jdolecek  432:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload,
1.1       hannken   433:                        0, bp->b_bcount,
                    434:                        isread?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
1.15      jdolecek  435:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
1.1       hannken   436:                        offsetof(struct virtio_blk_req, vr_status),
                    437:                        sizeof(uint8_t),
                    438:                        BUS_DMASYNC_PREREAD);
                    439:
                    440:        virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts,
                    441:                         0, sizeof(struct virtio_blk_req_hdr),
                    442:                         true);
                    443:        virtio_enqueue(vsc, vq, slot, vr->vr_payload, !isread);
                    444:        virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts,
                    445:                         offsetof(struct virtio_blk_req, vr_status),
                    446:                         sizeof(uint8_t),
                    447:                         false);
1.25      jakllsch  448:        virtio_enqueue_commit(vsc, vq, slot, true);
1.1       hannken   449:
                    450:        return 0;
                    451: }
                    452:
                    453: static void
                    454: ld_virtio_vq_done1(struct ld_virtio_softc *sc, struct virtio_softc *vsc,
                    455:                   struct virtqueue *vq, int slot)
                    456: {
                    457:        struct virtio_blk_req *vr = &sc->sc_reqs[slot];
                    458:        struct buf *bp = vr->vr_bp;
                    459:
1.9       christos  460:        vr->vr_bp = NULL;
                    461:
1.15      jdolecek  462:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
1.1       hannken   463:                        0, sizeof(struct virtio_blk_req_hdr),
                    464:                        BUS_DMASYNC_POSTWRITE);
1.20      jakllsch  465:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
                    466:                        sizeof(struct virtio_blk_req_hdr), sizeof(uint8_t),
                    467:                        BUS_DMASYNC_POSTREAD);
                    468:        if (bp == DUMMY_VR_BP) {
                    469:                mutex_enter(&sc->sc_sync_wait_lock);
                    470:                sc->sc_sync_status = vr->vr_status;
                    471:                sc->sc_sync_use = SYNC_DONE;
1.27      hannken   472:                cv_broadcast(&sc->sc_sync_wait);
1.20      jakllsch  473:                mutex_exit(&sc->sc_sync_wait_lock);
                    474:                virtio_dequeue_commit(vsc, vq, slot);
                    475:                return;
                    476:        }
1.15      jdolecek  477:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload,
1.1       hannken   478:                        0, bp->b_bcount,
                    479:                        (bp->b_flags & B_READ)?BUS_DMASYNC_POSTREAD
                    480:                                              :BUS_DMASYNC_POSTWRITE);
1.19      jakllsch  481:        bus_dmamap_unload(virtio_dmat(vsc), vr->vr_payload);
1.1       hannken   482:
                    483:        if (vr->vr_status != VIRTIO_BLK_S_OK) {
                    484:                bp->b_error = EIO;
                    485:                bp->b_resid = bp->b_bcount;
                    486:        } else {
                    487:                bp->b_error = 0;
                    488:                bp->b_resid = 0;
                    489:        }
                    490:
                    491:        virtio_dequeue_commit(vsc, vq, slot);
                    492:
                    493:        lddone(&sc->sc_ld, bp);
                    494: }
                    495:
                    496: static int
                    497: ld_virtio_vq_done(struct virtqueue *vq)
                    498: {
                    499:        struct virtio_softc *vsc = vq->vq_owner;
1.15      jdolecek  500:        struct ld_virtio_softc *sc = device_private(virtio_child(vsc));
1.1       hannken   501:        int r = 0;
                    502:        int slot;
                    503:
                    504: again:
                    505:        if (virtio_dequeue(vsc, vq, &slot, NULL))
                    506:                return r;
                    507:        r = 1;
                    508:
                    509:        ld_virtio_vq_done1(sc, vsc, vq, slot);
                    510:        goto again;
                    511: }
                    512:
                    513: static int
                    514: ld_virtio_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
                    515: {
                    516:        struct ld_virtio_softc *sc = device_private(ld->sc_dv);
                    517:        struct virtio_softc *vsc = sc->sc_virtio;
1.9       christos  518:        struct virtqueue *vq = &sc->sc_vq;
1.1       hannken   519:        struct virtio_blk_req *vr;
                    520:        int slot, r;
                    521:
                    522:        if (sc->sc_readonly)
                    523:                return EIO;
                    524:
                    525:        r = virtio_enqueue_prep(vsc, vq, &slot);
                    526:        if (r != 0) {
                    527:                if (r == EAGAIN) { /* no free slot; dequeue first */
                    528:                        delay(100);
                    529:                        ld_virtio_vq_done(vq);
                    530:                        r = virtio_enqueue_prep(vsc, vq, &slot);
                    531:                        if (r != 0)
                    532:                                return r;
                    533:                }
                    534:                return r;
                    535:        }
                    536:        vr = &sc->sc_reqs[slot];
1.15      jdolecek  537:        r = bus_dmamap_load(virtio_dmat(vsc), vr->vr_payload,
1.1       hannken   538:                            data, blkcnt*ld->sc_secsize, NULL,
                    539:                            BUS_DMA_WRITE|BUS_DMA_NOWAIT);
                    540:        if (r != 0)
                    541:                return r;
                    542:
1.17      jakllsch  543:        r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs +
1.9       christos  544:            VIRTIO_BLK_MIN_SEGMENTS);
1.1       hannken   545:        if (r != 0) {
1.15      jdolecek  546:                bus_dmamap_unload(virtio_dmat(vsc), vr->vr_payload);
1.1       hannken   547:                return r;
                    548:        }
                    549:
                    550:        vr->vr_bp = (void*)0xdeadbeef;
1.29      reinoud   551:        vr->vr_hdr.type   = virtio_rw32(vsc, VIRTIO_BLK_T_OUT);
                    552:        vr->vr_hdr.ioprio = virtio_rw32(vsc, 0);
                    553:        vr->vr_hdr.sector = virtio_rw64(vsc,
                    554:                        (daddr_t) blkno * ld->sc_secsize /
                    555:                        VIRTIO_BLK_BSIZE);
1.1       hannken   556:
1.15      jdolecek  557:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
1.1       hannken   558:                        0, sizeof(struct virtio_blk_req_hdr),
                    559:                        BUS_DMASYNC_PREWRITE);
1.15      jdolecek  560:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload,
1.1       hannken   561:                        0, blkcnt*ld->sc_secsize,
                    562:                        BUS_DMASYNC_PREWRITE);
1.15      jdolecek  563:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
1.1       hannken   564:                        offsetof(struct virtio_blk_req, vr_status),
                    565:                        sizeof(uint8_t),
                    566:                        BUS_DMASYNC_PREREAD);
                    567:
                    568:        virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts,
                    569:                         0, sizeof(struct virtio_blk_req_hdr),
                    570:                         true);
                    571:        virtio_enqueue(vsc, vq, slot, vr->vr_payload, true);
                    572:        virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts,
                    573:                         offsetof(struct virtio_blk_req, vr_status),
                    574:                         sizeof(uint8_t),
                    575:                         false);
                    576:        virtio_enqueue_commit(vsc, vq, slot, true);
                    577:
                    578:        for ( ; ; ) {
                    579:                int dslot;
                    580:
                    581:                r = virtio_dequeue(vsc, vq, &dslot, NULL);
                    582:                if (r != 0)
                    583:                        continue;
                    584:                if (dslot != slot) {
                    585:                        ld_virtio_vq_done1(sc, vsc, vq, dslot);
                    586:                        continue;
                    587:                } else
                    588:                        break;
                    589:        }
1.17      jakllsch  590:
1.15      jdolecek  591:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
1.1       hannken   592:                        0, sizeof(struct virtio_blk_req_hdr),
                    593:                        BUS_DMASYNC_POSTWRITE);
1.15      jdolecek  594:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload,
1.1       hannken   595:                        0, blkcnt*ld->sc_secsize,
                    596:                        BUS_DMASYNC_POSTWRITE);
1.15      jdolecek  597:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
1.1       hannken   598:                        offsetof(struct virtio_blk_req, vr_status),
                    599:                        sizeof(uint8_t),
                    600:                        BUS_DMASYNC_POSTREAD);
                    601:        if (vr->vr_status == VIRTIO_BLK_S_OK)
                    602:                r = 0;
                    603:        else
                    604:                r = EIO;
                    605:        virtio_dequeue_commit(vsc, vq, slot);
                    606:
                    607:        return r;
                    608: }
                    609:
                    610: static int
                    611: ld_virtio_detach(device_t self, int flags)
                    612: {
                    613:        struct ld_virtio_softc *sc = device_private(self);
                    614:        struct ld_softc *ld = &sc->sc_ld;
1.15      jdolecek  615:        bus_dma_tag_t dmat = virtio_dmat(sc->sc_virtio);
1.1       hannken   616:        int r, i, qsize;
                    617:
1.9       christos  618:        qsize = sc->sc_vq.vq_num;
1.1       hannken   619:        r = ldbegindetach(ld, flags);
                    620:        if (r != 0)
                    621:                return r;
                    622:        virtio_reset(sc->sc_virtio);
1.9       christos  623:        virtio_free_vq(sc->sc_virtio, &sc->sc_vq);
1.1       hannken   624:
                    625:        for (i = 0; i < qsize; i++) {
                    626:                bus_dmamap_destroy(dmat,
                    627:                                   sc->sc_reqs[i].vr_cmdsts);
                    628:                bus_dmamap_destroy(dmat,
                    629:                                   sc->sc_reqs[i].vr_payload);
                    630:        }
                    631:        bus_dmamem_unmap(dmat, sc->sc_reqs,
                    632:                         sizeof(struct virtio_blk_req) * qsize);
1.9       christos  633:        bus_dmamem_free(dmat, &sc->sc_reqs_seg, 1);
1.1       hannken   634:
                    635:        ldenddetach(ld);
                    636:
1.23      jakllsch  637:        cv_destroy(&sc->sc_sync_wait);
                    638:        mutex_destroy(&sc->sc_sync_wait_lock);
                    639:
1.15      jdolecek  640:        virtio_child_detach(sc->sc_virtio);
                    641:
1.1       hannken   642:        return 0;
                    643: }
1.12      pgoyette  644:
1.20      jakllsch  645: static int
                    646: ld_virtio_flush(struct ld_softc *ld, bool poll)
                    647: {
                    648:        struct ld_virtio_softc * const sc = device_private(ld->sc_dv);
                    649:        struct virtio_softc * const vsc = sc->sc_virtio;
1.29      reinoud   650:        const uint64_t features = virtio_features(vsc);
1.20      jakllsch  651:        struct virtqueue *vq = &sc->sc_vq;
                    652:        struct virtio_blk_req *vr;
                    653:        int slot;
                    654:        int r;
                    655:
                    656:        if ((features & VIRTIO_BLK_F_FLUSH) == 0)
                    657:                return 0;
                    658:
                    659:        mutex_enter(&sc->sc_sync_wait_lock);
                    660:        while (sc->sc_sync_use != SYNC_FREE) {
                    661:                if (poll) {
                    662:                        mutex_exit(&sc->sc_sync_wait_lock);
                    663:                        ld_virtio_vq_done(vq);
                    664:                        mutex_enter(&sc->sc_sync_wait_lock);
                    665:                        continue;
                    666:                }
                    667:                cv_wait(&sc->sc_sync_wait, &sc->sc_sync_wait_lock);
                    668:        }
                    669:        sc->sc_sync_use = SYNC_BUSY;
                    670:        mutex_exit(&sc->sc_sync_wait_lock);
                    671:
                    672:        r = virtio_enqueue_prep(vsc, vq, &slot);
                    673:        if (r != 0) {
                    674:                return r;
                    675:        }
                    676:
                    677:        vr = &sc->sc_reqs[slot];
                    678:        KASSERT(vr->vr_bp == NULL);
                    679:
                    680:        r = virtio_enqueue_reserve(vsc, vq, slot, VIRTIO_BLK_MIN_SEGMENTS);
                    681:        if (r != 0) {
                    682:                return r;
                    683:        }
                    684:
                    685:        vr->vr_bp = DUMMY_VR_BP;
1.29      reinoud   686:        vr->vr_hdr.type   = virtio_rw32(vsc, VIRTIO_BLK_T_FLUSH);
                    687:        vr->vr_hdr.ioprio = virtio_rw32(vsc, 0);
                    688:        vr->vr_hdr.sector = virtio_rw64(vsc, 0);
1.20      jakllsch  689:
                    690:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
                    691:                        0, sizeof(struct virtio_blk_req_hdr),
                    692:                        BUS_DMASYNC_PREWRITE);
                    693:        bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
                    694:                        offsetof(struct virtio_blk_req, vr_status),
                    695:                        sizeof(uint8_t),
                    696:                        BUS_DMASYNC_PREREAD);
                    697:
                    698:        virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts,
                    699:                         0, sizeof(struct virtio_blk_req_hdr),
                    700:                         true);
                    701:        virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts,
                    702:                         offsetof(struct virtio_blk_req, vr_status),
                    703:                         sizeof(uint8_t),
                    704:                         false);
                    705:        virtio_enqueue_commit(vsc, vq, slot, true);
                    706:
                    707:        mutex_enter(&sc->sc_sync_wait_lock);
                    708:        while (sc->sc_sync_use != SYNC_DONE) {
                    709:                if (poll) {
                    710:                        mutex_exit(&sc->sc_sync_wait_lock);
                    711:                        ld_virtio_vq_done(vq);
                    712:                        mutex_enter(&sc->sc_sync_wait_lock);
                    713:                        continue;
                    714:                }
                    715:                cv_wait(&sc->sc_sync_wait, &sc->sc_sync_wait_lock);
                    716:        }
                    717:
                    718:        if (sc->sc_sync_status == VIRTIO_BLK_S_OK)
                    719:                r = 0;
                    720:        else
                    721:                r = EIO;
                    722:
                    723:        sc->sc_sync_use = SYNC_FREE;
1.27      hannken   724:        cv_broadcast(&sc->sc_sync_wait);
1.20      jakllsch  725:        mutex_exit(&sc->sc_sync_wait_lock);
                    726:
                    727:        return r;
                    728: }
                    729:
                    730: static int
                    731: ld_virtio_getcache(struct ld_softc *ld, int *bitsp)
                    732: {
                    733:        struct ld_virtio_softc * const sc = device_private(ld->sc_dv);
                    734:        struct virtio_softc * const vsc = sc->sc_virtio;
1.29      reinoud   735:        const uint64_t features = virtio_features(vsc);
1.20      jakllsch  736:
                    737:        *bitsp = DKCACHE_READ;
                    738:        if ((features & VIRTIO_BLK_F_CONFIG_WCE) != 0)
                    739:                *bitsp |= DKCACHE_WCHANGE;
                    740:        if (virtio_read_device_config_1(vsc,
                    741:            VIRTIO_BLK_CONFIG_WRITEBACK) != 0x00)
                    742:                *bitsp |= DKCACHE_WRITE;
                    743:
                    744:        return 0;
                    745: }
                    746:
                    747: static int
                    748: ld_virtio_setcache(struct ld_softc *ld, int bits)
                    749: {
                    750:        struct ld_virtio_softc * const sc = device_private(ld->sc_dv);
                    751:        struct virtio_softc * const vsc = sc->sc_virtio;
                    752:        const uint8_t wce = (bits & DKCACHE_WRITE) ? 0x01 : 0x00;
                    753:
                    754:        virtio_write_device_config_1(vsc,
                    755:            VIRTIO_BLK_CONFIG_WRITEBACK, wce);
                    756:        if (virtio_read_device_config_1(vsc,
                    757:            VIRTIO_BLK_CONFIG_WRITEBACK) != wce)
                    758:                return EIO;
                    759:
                    760:        return 0;
                    761: }
                    762:
                    763: static int
                    764: ld_virtio_ioctl(struct ld_softc *ld, u_long cmd, void *addr, int32_t flag, bool poll)
                    765: {
                    766:        int error;
                    767:
                    768:        switch (cmd) {
                    769:        case DIOCCACHESYNC:
                    770:                error = ld_virtio_flush(ld, poll);
                    771:                break;
                    772:
                    773:        case DIOCGCACHE:
                    774:                error = ld_virtio_getcache(ld, (int *)addr);
                    775:                break;
                    776:
                    777:        case DIOCSCACHE:
                    778:                error = ld_virtio_setcache(ld, *(int *)addr);
                    779:                break;
                    780:
                    781:        default:
                    782:                error = EPASSTHROUGH;
                    783:                break;
                    784:        }
                    785:
                    786:        return error;
                    787: }
                    788:
1.12      pgoyette  789: MODULE(MODULE_CLASS_DRIVER, ld_virtio, "ld,virtio");
                    790:
                    791: #ifdef _MODULE
                    792: /*
                    793:  * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd"
                    794:  * XXX it will be defined in the common-code module
                    795:  */
                    796: #undef  CFDRIVER_DECL
                    797: #define CFDRIVER_DECL(name, class, attr)
                    798: #include "ioconf.c"
                    799: #endif
1.17      jakllsch  800:
1.12      pgoyette  801: static int
                    802: ld_virtio_modcmd(modcmd_t cmd, void *opaque)
                    803: {
                    804: #ifdef _MODULE
                    805:        /*
                    806:         * We ignore the cfdriver_vec[] that ioconf provides, since
                    807:         * the cfdrivers are attached already.
                    808:         */
                    809:        static struct cfdriver * const no_cfdriver_vec[] = { NULL };
                    810: #endif
                    811:        int error = 0;
1.17      jakllsch  812:
1.12      pgoyette  813: #ifdef _MODULE
                    814:        switch (cmd) {
                    815:        case MODULE_CMD_INIT:
                    816:                error = config_init_component(no_cfdriver_vec,
                    817:                    cfattach_ioconf_ld_virtio, cfdata_ioconf_ld_virtio);
                    818:                break;
                    819:        case MODULE_CMD_FINI:
                    820:                error = config_fini_component(no_cfdriver_vec,
                    821:                    cfattach_ioconf_ld_virtio, cfdata_ioconf_ld_virtio);
                    822:                break;
                    823:        default:
                    824:                error = ENOTTY;
                    825:                break;
                    826:        }
                    827: #endif
                    828:
                    829:        return error;
                    830: }

CVSweb <webmaster@jp.NetBSD.org>