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>