Deleted Added
full compact
virtio_blk.c (228301) virtio_blk.c (234270)
1/*-
2 * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 13 unchanged lines hidden (view full) ---

22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/* Driver for VirtIO block devices. */
28
29#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 13 unchanged lines hidden (view full) ---

22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/* Driver for VirtIO block devices. */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/dev/virtio/block/virtio_blk.c 228301 2011-12-06 06:28:32Z grehan $");
30__FBSDID("$FreeBSD: head/sys/dev/virtio/block/virtio_blk.c 234270 2012-04-14 05:48:04Z grehan $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/bio.h>
36#include <sys/malloc.h>
37#include <sys/module.h>
38#include <sys/sglist.h>

--- 26 unchanged lines hidden (view full) ---

65
66struct vtblk_softc {
67 device_t vtblk_dev;
68 struct mtx vtblk_mtx;
69 uint64_t vtblk_features;
70 uint32_t vtblk_flags;
71#define VTBLK_FLAG_INDIRECT 0x0001
72#define VTBLK_FLAG_READONLY 0x0002
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/bio.h>
36#include <sys/malloc.h>
37#include <sys/module.h>
38#include <sys/sglist.h>

--- 26 unchanged lines hidden (view full) ---

65
66struct vtblk_softc {
67 device_t vtblk_dev;
68 struct mtx vtblk_mtx;
69 uint64_t vtblk_features;
70 uint32_t vtblk_flags;
71#define VTBLK_FLAG_INDIRECT 0x0001
72#define VTBLK_FLAG_READONLY 0x0002
73#define VTBLK_FLAG_DETACHING 0x0004
74#define VTBLK_FLAG_SUSPENDED 0x0008
73#define VTBLK_FLAG_DETACH 0x0004
74#define VTBLK_FLAG_SUSPEND 0x0008
75#define VTBLK_FLAG_DUMPING 0x0010
76
77 struct virtqueue *vtblk_vq;
78 struct sglist *vtblk_sglist;
79 struct disk *vtblk_disk;
80
81 struct bio_queue_head vtblk_bioq;
82 TAILQ_HEAD(, vtblk_request)
83 vtblk_req_free;
84 TAILQ_HEAD(, vtblk_request)
75#define VTBLK_FLAG_DUMPING 0x0010
76
77 struct virtqueue *vtblk_vq;
78 struct sglist *vtblk_sglist;
79 struct disk *vtblk_disk;
80
81 struct bio_queue_head vtblk_bioq;
82 TAILQ_HEAD(, vtblk_request)
83 vtblk_req_free;
84 TAILQ_HEAD(, vtblk_request)
85 vtblk_req_ready;
85 vtblk_req_ready;
86
87 struct taskqueue *vtblk_tq;
88 struct task vtblk_intr_task;
89
90 int vtblk_max_nsegs;
91 int vtblk_request_count;
92
93 struct vtblk_request vtblk_dump_request;

--- 17 unchanged lines hidden (view full) ---

111
112static int vtblk_probe(device_t);
113static int vtblk_attach(device_t);
114static int vtblk_detach(device_t);
115static int vtblk_suspend(device_t);
116static int vtblk_resume(device_t);
117static int vtblk_shutdown(device_t);
118
86
87 struct taskqueue *vtblk_tq;
88 struct task vtblk_intr_task;
89
90 int vtblk_max_nsegs;
91 int vtblk_request_count;
92
93 struct vtblk_request vtblk_dump_request;

--- 17 unchanged lines hidden (view full) ---

111
112static int vtblk_probe(device_t);
113static int vtblk_attach(device_t);
114static int vtblk_detach(device_t);
115static int vtblk_suspend(device_t);
116static int vtblk_resume(device_t);
117static int vtblk_shutdown(device_t);
118
119static int vtblk_open(struct disk *);
120static int vtblk_close(struct disk *);
121static int vtblk_ioctl(struct disk *, u_long, void *, int,
122 struct thread *);
123static int vtblk_dump(void *, void *, vm_offset_t, off_t, size_t);
124static void vtblk_strategy(struct bio *);
125
119static void vtblk_negotiate_features(struct vtblk_softc *);
120static int vtblk_maximum_segments(struct vtblk_softc *,
121 struct virtio_blk_config *);
122static int vtblk_alloc_virtqueue(struct vtblk_softc *);
123static void vtblk_alloc_disk(struct vtblk_softc *,
124 struct virtio_blk_config *);
125static void vtblk_create_disk(struct vtblk_softc *);
126
126static void vtblk_negotiate_features(struct vtblk_softc *);
127static int vtblk_maximum_segments(struct vtblk_softc *,
128 struct virtio_blk_config *);
129static int vtblk_alloc_virtqueue(struct vtblk_softc *);
130static void vtblk_alloc_disk(struct vtblk_softc *,
131 struct virtio_blk_config *);
132static void vtblk_create_disk(struct vtblk_softc *);
133
127static int vtblk_open(struct disk *);
128static int vtblk_close(struct disk *);
129static int vtblk_ioctl(struct disk *, u_long, void *, int,
130 struct thread *);
131static int vtblk_dump(void *, void *, vm_offset_t, off_t, size_t);
132static void vtblk_strategy(struct bio *);
133
134static int vtblk_quiesce(struct vtblk_softc *);
134static void vtblk_startio(struct vtblk_softc *);
135static struct vtblk_request * vtblk_bio_request(struct vtblk_softc *);
136static int vtblk_execute_request(struct vtblk_softc *,
137 struct vtblk_request *);
138
139static int vtblk_vq_intr(void *);
140static void vtblk_intr_task(void *, int);
141
142static void vtblk_stop(struct vtblk_softc *);
143
144static void vtblk_get_ident(struct vtblk_softc *);
145static void vtblk_prepare_dump(struct vtblk_softc *);
146static int vtblk_write_dump(struct vtblk_softc *, void *, off_t, size_t);
147static int vtblk_flush_dump(struct vtblk_softc *);
148static int vtblk_poll_request(struct vtblk_softc *,
149 struct vtblk_request *);
150
135static void vtblk_startio(struct vtblk_softc *);
136static struct vtblk_request * vtblk_bio_request(struct vtblk_softc *);
137static int vtblk_execute_request(struct vtblk_softc *,
138 struct vtblk_request *);
139
140static int vtblk_vq_intr(void *);
141static void vtblk_intr_task(void *, int);
142
143static void vtblk_stop(struct vtblk_softc *);
144
145static void vtblk_get_ident(struct vtblk_softc *);
146static void vtblk_prepare_dump(struct vtblk_softc *);
147static int vtblk_write_dump(struct vtblk_softc *, void *, off_t, size_t);
148static int vtblk_flush_dump(struct vtblk_softc *);
149static int vtblk_poll_request(struct vtblk_softc *,
150 struct vtblk_request *);
151
152static void vtblk_finish_completed(struct vtblk_softc *);
151static void vtblk_drain_vq(struct vtblk_softc *, int);
152static void vtblk_drain(struct vtblk_softc *);
153
154static int vtblk_alloc_requests(struct vtblk_softc *);
155static void vtblk_free_requests(struct vtblk_softc *);
156static struct vtblk_request * vtblk_dequeue_request(struct vtblk_softc *);
157static void vtblk_enqueue_request(struct vtblk_softc *,
158 struct vtblk_request *);
159
160static struct vtblk_request * vtblk_dequeue_ready(struct vtblk_softc *);
161static void vtblk_enqueue_ready(struct vtblk_softc *,
162 struct vtblk_request *);
163
153static void vtblk_drain_vq(struct vtblk_softc *, int);
154static void vtblk_drain(struct vtblk_softc *);
155
156static int vtblk_alloc_requests(struct vtblk_softc *);
157static void vtblk_free_requests(struct vtblk_softc *);
158static struct vtblk_request * vtblk_dequeue_request(struct vtblk_softc *);
159static void vtblk_enqueue_request(struct vtblk_softc *,
160 struct vtblk_request *);
161
162static struct vtblk_request * vtblk_dequeue_ready(struct vtblk_softc *);
163static void vtblk_enqueue_ready(struct vtblk_softc *,
164 struct vtblk_request *);
165
164static void vtblk_bio_error(struct bio *, int);
166static int vtblk_request_error(struct vtblk_request *);
167static void vtblk_finish_bio(struct bio *, int);
165
166/* Tunables. */
167static int vtblk_no_ident = 0;
168TUNABLE_INT("hw.vtblk.no_ident", &vtblk_no_ident);
169
170/* Features desired/implemented by this driver. */
171#define VTBLK_FEATURES \
172 (VIRTIO_BLK_F_BARRIER | \

--- 11 unchanged lines hidden (view full) ---

184 "VTBLK Lock", MTX_DEF)
185#define VTBLK_LOCK(_sc) mtx_lock(VTBLK_MTX((_sc)))
186#define VTBLK_UNLOCK(_sc) mtx_unlock(VTBLK_MTX((_sc)))
187#define VTBLK_LOCK_DESTROY(_sc) mtx_destroy(VTBLK_MTX((_sc)))
188#define VTBLK_LOCK_ASSERT(_sc) mtx_assert(VTBLK_MTX((_sc)), MA_OWNED)
189#define VTBLK_LOCK_ASSERT_NOTOWNED(_sc) \
190 mtx_assert(VTBLK_MTX((_sc)), MA_NOTOWNED)
191
168
169/* Tunables. */
170static int vtblk_no_ident = 0;
171TUNABLE_INT("hw.vtblk.no_ident", &vtblk_no_ident);
172
173/* Features desired/implemented by this driver. */
174#define VTBLK_FEATURES \
175 (VIRTIO_BLK_F_BARRIER | \

--- 11 unchanged lines hidden (view full) ---

187 "VTBLK Lock", MTX_DEF)
188#define VTBLK_LOCK(_sc) mtx_lock(VTBLK_MTX((_sc)))
189#define VTBLK_UNLOCK(_sc) mtx_unlock(VTBLK_MTX((_sc)))
190#define VTBLK_LOCK_DESTROY(_sc) mtx_destroy(VTBLK_MTX((_sc)))
191#define VTBLK_LOCK_ASSERT(_sc) mtx_assert(VTBLK_MTX((_sc)), MA_OWNED)
192#define VTBLK_LOCK_ASSERT_NOTOWNED(_sc) \
193 mtx_assert(VTBLK_MTX((_sc)), MA_NOTOWNED)
194
192#define VTBLK_BIO_SEGMENTS(_bp) sglist_count((_bp)->bio_data, (_bp)->bio_bcount)
193
194#define VTBLK_DISK_NAME "vtbd"
195#define VTBLK_DISK_NAME "vtbd"
196#define VTBLK_QUIESCE_TIMEOUT (30 * hz)
195
196/*
197 * Each block request uses at least two segments - one for the header
198 * and one for the status.
199 */
200#define VTBLK_MIN_SEGMENTS 2
201
202static uma_zone_t vtblk_req_zone;
203
204static device_method_t vtblk_methods[] = {
205 /* Device methods. */
206 DEVMETHOD(device_probe, vtblk_probe),
207 DEVMETHOD(device_attach, vtblk_attach),
208 DEVMETHOD(device_detach, vtblk_detach),
209 DEVMETHOD(device_suspend, vtblk_suspend),
210 DEVMETHOD(device_resume, vtblk_resume),
211 DEVMETHOD(device_shutdown, vtblk_shutdown),
212
197
198/*
199 * Each block request uses at least two segments - one for the header
200 * and one for the status.
201 */
202#define VTBLK_MIN_SEGMENTS 2
203
204static uma_zone_t vtblk_req_zone;
205
206static device_method_t vtblk_methods[] = {
207 /* Device methods. */
208 DEVMETHOD(device_probe, vtblk_probe),
209 DEVMETHOD(device_attach, vtblk_attach),
210 DEVMETHOD(device_detach, vtblk_detach),
211 DEVMETHOD(device_suspend, vtblk_suspend),
212 DEVMETHOD(device_resume, vtblk_resume),
213 DEVMETHOD(device_shutdown, vtblk_shutdown),
214
213 { 0, 0 }
215 DEVMETHOD_END
214};
215
216static driver_t vtblk_driver = {
217 "vtblk",
218 vtblk_methods,
219 sizeof(struct vtblk_softc)
220};
221static devclass_t vtblk_devclass;

--- 87 unchanged lines hidden (view full) ---

309 error = ENOTSUP;
310 device_printf(dev, "host requires unsupported "
311 "maximum segment size feature\n");
312 goto fail;
313 }
314 }
315
316 sc->vtblk_max_nsegs = vtblk_maximum_segments(sc, &blkcfg);
216};
217
218static driver_t vtblk_driver = {
219 "vtblk",
220 vtblk_methods,
221 sizeof(struct vtblk_softc)
222};
223static devclass_t vtblk_devclass;

--- 87 unchanged lines hidden (view full) ---

311 error = ENOTSUP;
312 device_printf(dev, "host requires unsupported "
313 "maximum segment size feature\n");
314 goto fail;
315 }
316 }
317
318 sc->vtblk_max_nsegs = vtblk_maximum_segments(sc, &blkcfg);
319 if (sc->vtblk_max_nsegs <= VTBLK_MIN_SEGMENTS) {
320 error = EINVAL;
321 device_printf(dev, "fewer than minimum number of segments "
322 "allowed: %d\n", sc->vtblk_max_nsegs);
323 goto fail;
324 }
317
325
318 /*
319 * Allocate working sglist. The number of segments may be too
320 * large to safely store on the stack.
321 */
322 sc->vtblk_sglist = sglist_alloc(sc->vtblk_max_nsegs, M_NOWAIT);
323 if (sc->vtblk_sglist == NULL) {
324 error = ENOMEM;
325 device_printf(dev, "cannot allocate sglist\n");
326 goto fail;
327 }
328
329 error = vtblk_alloc_virtqueue(sc);

--- 41 unchanged lines hidden (view full) ---

371static int
372vtblk_detach(device_t dev)
373{
374 struct vtblk_softc *sc;
375
376 sc = device_get_softc(dev);
377
378 VTBLK_LOCK(sc);
326 sc->vtblk_sglist = sglist_alloc(sc->vtblk_max_nsegs, M_NOWAIT);
327 if (sc->vtblk_sglist == NULL) {
328 error = ENOMEM;
329 device_printf(dev, "cannot allocate sglist\n");
330 goto fail;
331 }
332
333 error = vtblk_alloc_virtqueue(sc);

--- 41 unchanged lines hidden (view full) ---

375static int
376vtblk_detach(device_t dev)
377{
378 struct vtblk_softc *sc;
379
380 sc = device_get_softc(dev);
381
382 VTBLK_LOCK(sc);
379 sc->vtblk_flags |= VTBLK_FLAG_DETACHING;
383 sc->vtblk_flags |= VTBLK_FLAG_DETACH;
380 if (device_is_attached(dev))
381 vtblk_stop(sc);
382 VTBLK_UNLOCK(sc);
383
384 if (sc->vtblk_tq != NULL) {
385 taskqueue_drain(sc->vtblk_tq, &sc->vtblk_intr_task);
386 taskqueue_free(sc->vtblk_tq);
387 sc->vtblk_tq = NULL;

--- 15 unchanged lines hidden (view full) ---

403
404 return (0);
405}
406
407static int
408vtblk_suspend(device_t dev)
409{
410 struct vtblk_softc *sc;
384 if (device_is_attached(dev))
385 vtblk_stop(sc);
386 VTBLK_UNLOCK(sc);
387
388 if (sc->vtblk_tq != NULL) {
389 taskqueue_drain(sc->vtblk_tq, &sc->vtblk_intr_task);
390 taskqueue_free(sc->vtblk_tq);
391 sc->vtblk_tq = NULL;

--- 15 unchanged lines hidden (view full) ---

407
408 return (0);
409}
410
411static int
412vtblk_suspend(device_t dev)
413{
414 struct vtblk_softc *sc;
415 int error;
411
412 sc = device_get_softc(dev);
413
414 VTBLK_LOCK(sc);
416
417 sc = device_get_softc(dev);
418
419 VTBLK_LOCK(sc);
415 sc->vtblk_flags |= VTBLK_FLAG_SUSPENDED;
416 /* TODO Wait for any inflight IO to complete? */
420 sc->vtblk_flags |= VTBLK_FLAG_SUSPEND;
421 /* XXX BMV: virtio_stop(), etc needed here? */
422 error = vtblk_quiesce(sc);
423 if (error)
424 sc->vtblk_flags &= ~VTBLK_FLAG_SUSPEND;
417 VTBLK_UNLOCK(sc);
418
425 VTBLK_UNLOCK(sc);
426
419 return (0);
427 return (error);
420}
421
422static int
423vtblk_resume(device_t dev)
424{
425 struct vtblk_softc *sc;
426
427 sc = device_get_softc(dev);
428
429 VTBLK_LOCK(sc);
428}
429
430static int
431vtblk_resume(device_t dev)
432{
433 struct vtblk_softc *sc;
434
435 sc = device_get_softc(dev);
436
437 VTBLK_LOCK(sc);
430 sc->vtblk_flags &= ~VTBLK_FLAG_SUSPENDED;
431 /* TODO Resume IO? */
438 /* XXX BMV: virtio_reinit(), etc needed here? */
439 sc->vtblk_flags &= ~VTBLK_FLAG_SUSPEND;
440 vtblk_startio(sc);
432 VTBLK_UNLOCK(sc);
433
434 return (0);
435}
436
437static int
438vtblk_shutdown(device_t dev)
439{

--- 4 unchanged lines hidden (view full) ---

444static int
445vtblk_open(struct disk *dp)
446{
447 struct vtblk_softc *sc;
448
449 if ((sc = dp->d_drv1) == NULL)
450 return (ENXIO);
451
441 VTBLK_UNLOCK(sc);
442
443 return (0);
444}
445
446static int
447vtblk_shutdown(device_t dev)
448{

--- 4 unchanged lines hidden (view full) ---

453static int
454vtblk_open(struct disk *dp)
455{
456 struct vtblk_softc *sc;
457
458 if ((sc = dp->d_drv1) == NULL)
459 return (ENXIO);
460
452 return (sc->vtblk_flags & VTBLK_FLAG_DETACHING ? ENXIO : 0);
461 return (sc->vtblk_flags & VTBLK_FLAG_DETACH ? ENXIO : 0);
453}
454
455static int
456vtblk_close(struct disk *dp)
457{
458 struct vtblk_softc *sc;
459
460 if ((sc = dp->d_drv1) == NULL)

--- 23 unchanged lines hidden (view full) ---

484 int error;
485
486 dp = arg;
487 error = 0;
488
489 if ((sc = dp->d_drv1) == NULL)
490 return (ENXIO);
491
462}
463
464static int
465vtblk_close(struct disk *dp)
466{
467 struct vtblk_softc *sc;
468
469 if ((sc = dp->d_drv1) == NULL)

--- 23 unchanged lines hidden (view full) ---

493 int error;
494
495 dp = arg;
496 error = 0;
497
498 if ((sc = dp->d_drv1) == NULL)
499 return (ENXIO);
500
501 VTBLK_LOCK(sc);
502
492 if ((sc->vtblk_flags & VTBLK_FLAG_DUMPING) == 0) {
493 vtblk_prepare_dump(sc);
494 sc->vtblk_flags |= VTBLK_FLAG_DUMPING;
495 }
496
497 if (length > 0)
498 error = vtblk_write_dump(sc, virtual, offset, length);
499 else if (virtual == NULL && offset == 0)
500 error = vtblk_flush_dump(sc);
503 if ((sc->vtblk_flags & VTBLK_FLAG_DUMPING) == 0) {
504 vtblk_prepare_dump(sc);
505 sc->vtblk_flags |= VTBLK_FLAG_DUMPING;
506 }
507
508 if (length > 0)
509 error = vtblk_write_dump(sc, virtual, offset, length);
510 else if (virtual == NULL && offset == 0)
511 error = vtblk_flush_dump(sc);
512 else {
513 error = EINVAL;
514 sc->vtblk_flags &= ~VTBLK_FLAG_DUMPING;
515 }
501
502 VTBLK_UNLOCK(sc);
503
504 return (error);
505}
506
507static void
508vtblk_strategy(struct bio *bp)
509{
510 struct vtblk_softc *sc;
511
512 if ((sc = bp->bio_disk->d_drv1) == NULL) {
516
517 VTBLK_UNLOCK(sc);
518
519 return (error);
520}
521
522static void
523vtblk_strategy(struct bio *bp)
524{
525 struct vtblk_softc *sc;
526
527 if ((sc = bp->bio_disk->d_drv1) == NULL) {
513 vtblk_bio_error(bp, EINVAL);
528 vtblk_finish_bio(bp, EINVAL);
514 return;
515 }
516
517 /*
518 * Fail any write if RO. Unfortunately, there does not seem to
519 * be a better way to report our readonly'ness to GEOM above.
520 */
521 if (sc->vtblk_flags & VTBLK_FLAG_READONLY &&
522 (bp->bio_cmd == BIO_WRITE || bp->bio_cmd == BIO_FLUSH)) {
529 return;
530 }
531
532 /*
533 * Fail any write if RO. Unfortunately, there does not seem to
534 * be a better way to report our readonly'ness to GEOM above.
535 */
536 if (sc->vtblk_flags & VTBLK_FLAG_READONLY &&
537 (bp->bio_cmd == BIO_WRITE || bp->bio_cmd == BIO_FLUSH)) {
523 vtblk_bio_error(bp, EROFS);
538 vtblk_finish_bio(bp, EROFS);
524 return;
525 }
526
539 return;
540 }
541
542#ifdef INVARIANTS
527 /*
528 * Prevent read/write buffers spanning too many segments from
529 * getting into the queue. This should only trip if d_maxsize
530 * was incorrectly set.
531 */
532 if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
543 /*
544 * Prevent read/write buffers spanning too many segments from
545 * getting into the queue. This should only trip if d_maxsize
546 * was incorrectly set.
547 */
548 if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
533 KASSERT(VTBLK_BIO_SEGMENTS(bp) <= sc->vtblk_max_nsegs -
534 VTBLK_MIN_SEGMENTS,
549 int nsegs, max_nsegs;
550
551 nsegs = sglist_count(bp->bio_data, bp->bio_bcount);
552 max_nsegs = sc->vtblk_max_nsegs - VTBLK_MIN_SEGMENTS;
553
554 KASSERT(nsegs <= max_nsegs,
535 ("bio spanned too many segments: %d, max: %d",
555 ("bio spanned too many segments: %d, max: %d",
536 VTBLK_BIO_SEGMENTS(bp),
537 sc->vtblk_max_nsegs - VTBLK_MIN_SEGMENTS));
556 nsegs, max_nsegs));
538 }
557 }
558#endif
539
540 VTBLK_LOCK(sc);
559
560 VTBLK_LOCK(sc);
541 if ((sc->vtblk_flags & VTBLK_FLAG_DETACHING) == 0) {
561 if (sc->vtblk_flags & VTBLK_FLAG_DETACH)
562 vtblk_finish_bio(bp, ENXIO);
563 else {
542 bioq_disksort(&sc->vtblk_bioq, bp);
564 bioq_disksort(&sc->vtblk_bioq, bp);
543 vtblk_startio(sc);
544 } else
545 vtblk_bio_error(bp, ENXIO);
565
566 if ((sc->vtblk_flags & VTBLK_FLAG_SUSPEND) == 0)
567 vtblk_startio(sc);
568 }
546 VTBLK_UNLOCK(sc);
547}
548
549static void
550vtblk_negotiate_features(struct vtblk_softc *sc)
551{
552 device_t dev;
553 uint64_t features;

--- 110 unchanged lines hidden (view full) ---

664 device_printf(sc->vtblk_dev, "%juMB (%ju %u byte sectors)\n",
665 (uintmax_t) dp->d_mediasize >> 20,
666 (uintmax_t) dp->d_mediasize / dp->d_sectorsize,
667 dp->d_sectorsize);
668
669 disk_create(dp, DISK_VERSION);
670}
671
569 VTBLK_UNLOCK(sc);
570}
571
572static void
573vtblk_negotiate_features(struct vtblk_softc *sc)
574{
575 device_t dev;
576 uint64_t features;

--- 110 unchanged lines hidden (view full) ---

687 device_printf(sc->vtblk_dev, "%juMB (%ju %u byte sectors)\n",
688 (uintmax_t) dp->d_mediasize >> 20,
689 (uintmax_t) dp->d_mediasize / dp->d_sectorsize,
690 dp->d_sectorsize);
691
692 disk_create(dp, DISK_VERSION);
693}
694
695static int
696vtblk_quiesce(struct vtblk_softc *sc)
697{
698 int error;
699
700 error = 0;
701
702 VTBLK_LOCK_ASSERT(sc);
703
704 while (!virtqueue_empty(sc->vtblk_vq)) {
705 if (mtx_sleep(&sc->vtblk_vq, VTBLK_MTX(sc), PRIBIO, "vtblkq",
706 VTBLK_QUIESCE_TIMEOUT) == EWOULDBLOCK) {
707 error = EBUSY;
708 break;
709 }
710 }
711
712 return (error);
713}
714
672static void
673vtblk_startio(struct vtblk_softc *sc)
674{
675 struct virtqueue *vq;
676 struct vtblk_request *req;
677 int enq;
678
679 vq = sc->vtblk_vq;
680 enq = 0;
681
682 VTBLK_LOCK_ASSERT(sc);
683
715static void
716vtblk_startio(struct vtblk_softc *sc)
717{
718 struct virtqueue *vq;
719 struct vtblk_request *req;
720 int enq;
721
722 vq = sc->vtblk_vq;
723 enq = 0;
724
725 VTBLK_LOCK_ASSERT(sc);
726
684 if (sc->vtblk_flags & VTBLK_FLAG_SUSPENDED)
685 return;
686
687 while (!virtqueue_full(vq)) {
688 if ((req = vtblk_dequeue_ready(sc)) == NULL)
689 req = vtblk_bio_request(sc);
690 if (req == NULL)
691 break;
692
693 if (vtblk_execute_request(sc, req) != 0) {
694 vtblk_enqueue_ready(sc, req);

--- 36 unchanged lines hidden (view full) ---

731 req->vbr_hdr.type = VIRTIO_BLK_T_IN;
732 req->vbr_hdr.sector = bp->bio_offset / 512;
733 break;
734 case BIO_WRITE:
735 req->vbr_hdr.type = VIRTIO_BLK_T_OUT;
736 req->vbr_hdr.sector = bp->bio_offset / 512;
737 break;
738 default:
727 while (!virtqueue_full(vq)) {
728 if ((req = vtblk_dequeue_ready(sc)) == NULL)
729 req = vtblk_bio_request(sc);
730 if (req == NULL)
731 break;
732
733 if (vtblk_execute_request(sc, req) != 0) {
734 vtblk_enqueue_ready(sc, req);

--- 36 unchanged lines hidden (view full) ---

771 req->vbr_hdr.type = VIRTIO_BLK_T_IN;
772 req->vbr_hdr.sector = bp->bio_offset / 512;
773 break;
774 case BIO_WRITE:
775 req->vbr_hdr.type = VIRTIO_BLK_T_OUT;
776 req->vbr_hdr.sector = bp->bio_offset / 512;
777 break;
778 default:
739 KASSERT(0, ("bio with unhandled cmd: %d", bp->bio_cmd));
740 req->vbr_hdr.type = -1;
741 break;
779 panic("%s: bio with unhandled cmd: %d", __FUNCTION__,
780 bp->bio_cmd);
742 }
743
744 if (bp->bio_flags & BIO_ORDERED)
745 req->vbr_hdr.type |= VIRTIO_BLK_T_BARRIER;
746
747 return (req);
748}
749
750static int
751vtblk_execute_request(struct vtblk_softc *sc, struct vtblk_request *req)
752{
753 struct sglist *sg;
754 struct bio *bp;
781 }
782
783 if (bp->bio_flags & BIO_ORDERED)
784 req->vbr_hdr.type |= VIRTIO_BLK_T_BARRIER;
785
786 return (req);
787}
788
789static int
790vtblk_execute_request(struct vtblk_softc *sc, struct vtblk_request *req)
791{
792 struct sglist *sg;
793 struct bio *bp;
755 int writable, error;
794 int readable, writable, error;
756
757 sg = sc->vtblk_sglist;
758 bp = req->vbr_bp;
759 writable = 0;
760
761 VTBLK_LOCK_ASSERT(sc);
762
763 sglist_reset(sg);

--- 14 unchanged lines hidden (view full) ---

778
779 error = sglist_append(sg, &req->vbr_ack, sizeof(uint8_t));
780 KASSERT(error == 0, ("error adding ack to sglist"));
781 writable++;
782
783 KASSERT(sg->sg_nseg >= VTBLK_MIN_SEGMENTS,
784 ("fewer than min segments: %d", sg->sg_nseg));
785
795
796 sg = sc->vtblk_sglist;
797 bp = req->vbr_bp;
798 writable = 0;
799
800 VTBLK_LOCK_ASSERT(sc);
801
802 sglist_reset(sg);

--- 14 unchanged lines hidden (view full) ---

817
818 error = sglist_append(sg, &req->vbr_ack, sizeof(uint8_t));
819 KASSERT(error == 0, ("error adding ack to sglist"));
820 writable++;
821
822 KASSERT(sg->sg_nseg >= VTBLK_MIN_SEGMENTS,
823 ("fewer than min segments: %d", sg->sg_nseg));
824
786 error = virtqueue_enqueue(sc->vtblk_vq, req, sg,
787 sg->sg_nseg - writable, writable);
825 readable = sg->sg_nseg - writable;
788
826
789 return (error);
827 return (virtqueue_enqueue(sc->vtblk_vq, req, sg, readable, writable));
790}
791
792static int
793vtblk_vq_intr(void *xsc)
794{
795 struct vtblk_softc *sc;
796
797 sc = xsc;
798
799 virtqueue_disable_intr(sc->vtblk_vq);
800 taskqueue_enqueue_fast(sc->vtblk_tq, &sc->vtblk_intr_task);
801
802 return (1);
803}
804
805static void
806vtblk_intr_task(void *arg, int pending)
807{
808 struct vtblk_softc *sc;
828}
829
830static int
831vtblk_vq_intr(void *xsc)
832{
833 struct vtblk_softc *sc;
834
835 sc = xsc;
836
837 virtqueue_disable_intr(sc->vtblk_vq);
838 taskqueue_enqueue_fast(sc->vtblk_tq, &sc->vtblk_intr_task);
839
840 return (1);
841}
842
843static void
844vtblk_intr_task(void *arg, int pending)
845{
846 struct vtblk_softc *sc;
809 struct vtblk_request *req;
810 struct virtqueue *vq;
847 struct virtqueue *vq;
811 struct bio *bp;
812
813 sc = arg;
814 vq = sc->vtblk_vq;
815
816 VTBLK_LOCK(sc);
848
849 sc = arg;
850 vq = sc->vtblk_vq;
851
852 VTBLK_LOCK(sc);
817 if (sc->vtblk_flags & VTBLK_FLAG_DETACHING) {
853 if (sc->vtblk_flags & VTBLK_FLAG_DETACH) {
818 VTBLK_UNLOCK(sc);
819 return;
820 }
821
854 VTBLK_UNLOCK(sc);
855 return;
856 }
857
822 while ((req = virtqueue_dequeue(vq, NULL)) != NULL) {
823 bp = req->vbr_bp;
858 vtblk_finish_completed(sc);
824
859
825 if (req->vbr_ack == VIRTIO_BLK_S_OK)
826 bp->bio_resid = 0;
827 else {
828 bp->bio_flags |= BIO_ERROR;
829 if (req->vbr_ack == VIRTIO_BLK_S_UNSUPP)
830 bp->bio_error = ENOTSUP;
831 else
832 bp->bio_error = EIO;
833 }
860 if ((sc->vtblk_flags & VTBLK_FLAG_SUSPEND) == 0)
861 vtblk_startio(sc);
862 else
863 wakeup(&sc->vtblk_vq);
834
864
835 biodone(bp);
836 vtblk_enqueue_request(sc, req);
837 }
838
839 vtblk_startio(sc);
840
841 if (virtqueue_enable_intr(vq) != 0) {
842 virtqueue_disable_intr(vq);
843 VTBLK_UNLOCK(sc);
844 taskqueue_enqueue_fast(sc->vtblk_tq,
845 &sc->vtblk_intr_task);
846 return;
847 }
848

--- 119 unchanged lines hidden (view full) ---

968 return (vtblk_poll_request(sc, req));
969}
970
971static int
972vtblk_poll_request(struct vtblk_softc *sc, struct vtblk_request *req)
973{
974 device_t dev;
975 struct virtqueue *vq;
865 if (virtqueue_enable_intr(vq) != 0) {
866 virtqueue_disable_intr(vq);
867 VTBLK_UNLOCK(sc);
868 taskqueue_enqueue_fast(sc->vtblk_tq,
869 &sc->vtblk_intr_task);
870 return;
871 }
872

--- 119 unchanged lines hidden (view full) ---

992 return (vtblk_poll_request(sc, req));
993}
994
995static int
996vtblk_poll_request(struct vtblk_softc *sc, struct vtblk_request *req)
997{
998 device_t dev;
999 struct virtqueue *vq;
976 struct vtblk_request *r;
977 int error;
978
979 dev = sc->vtblk_dev;
980 vq = sc->vtblk_vq;
981
982 if (!virtqueue_empty(vq))
983 return (EBUSY);
984
985 error = vtblk_execute_request(sc, req);
986 if (error)
987 return (error);
988
989 virtqueue_notify(vq);
990
1000 int error;
1001
1002 dev = sc->vtblk_dev;
1003 vq = sc->vtblk_vq;
1004
1005 if (!virtqueue_empty(vq))
1006 return (EBUSY);
1007
1008 error = vtblk_execute_request(sc, req);
1009 if (error)
1010 return (error);
1011
1012 virtqueue_notify(vq);
1013
991 r = virtqueue_poll(vq, NULL);
992 KASSERT(r == req, ("unexpected request response"));
1014 req = virtqueue_poll(vq, NULL);
993
1015
994 if (req->vbr_ack != VIRTIO_BLK_S_OK) {
995 error = req->vbr_ack == VIRTIO_BLK_S_UNSUPP ? ENOTSUP : EIO;
996 if (bootverbose)
997 device_printf(dev,
998 "vtblk_poll_request: IO error: %d\n", error);
1016 error = vtblk_request_error(req);
1017 if (error && bootverbose) {
1018 device_printf(dev, "vtblk_poll_request: IO error: %d\n",
1019 error);
999 }
1000
1001 return (error);
1002}
1003
1004static void
1020 }
1021
1022 return (error);
1023}
1024
1025static void
1026vtblk_finish_completed(struct vtblk_softc *sc)
1027{
1028 struct vtblk_request *req;
1029 struct bio *bp;
1030 int error;
1031
1032 while ((req = virtqueue_dequeue(sc->vtblk_vq, NULL)) != NULL) {
1033 bp = req->vbr_bp;
1034
1035 error = vtblk_request_error(req);
1036 if (error)
1037 disk_err(bp, "hard error", -1, 1);
1038
1039 vtblk_finish_bio(bp, error);
1040 vtblk_enqueue_request(sc, req);
1041 }
1042}
1043
1044static void
1005vtblk_drain_vq(struct vtblk_softc *sc, int skip_done)
1006{
1007 struct virtqueue *vq;
1008 struct vtblk_request *req;
1009 int last;
1010
1011 vq = sc->vtblk_vq;
1012 last = 0;
1013
1014 while ((req = virtqueue_drain(vq, &last)) != NULL) {
1015 if (!skip_done)
1045vtblk_drain_vq(struct vtblk_softc *sc, int skip_done)
1046{
1047 struct virtqueue *vq;
1048 struct vtblk_request *req;
1049 int last;
1050
1051 vq = sc->vtblk_vq;
1052 last = 0;
1053
1054 while ((req = virtqueue_drain(vq, &last)) != NULL) {
1055 if (!skip_done)
1016 vtblk_bio_error(req->vbr_bp, ENXIO);
1056 vtblk_finish_bio(req->vbr_bp, ENXIO);
1017
1018 vtblk_enqueue_request(sc, req);
1019 }
1020
1021 KASSERT(virtqueue_empty(vq), ("virtqueue not empty"));
1022}
1023
1024static void
1025vtblk_drain(struct vtblk_softc *sc)
1026{
1027 struct bio_queue_head *bioq;
1028 struct vtblk_request *req;
1029 struct bio *bp;
1030
1031 bioq = &sc->vtblk_bioq;
1032
1057
1058 vtblk_enqueue_request(sc, req);
1059 }
1060
1061 KASSERT(virtqueue_empty(vq), ("virtqueue not empty"));
1062}
1063
1064static void
1065vtblk_drain(struct vtblk_softc *sc)
1066{
1067 struct bio_queue_head *bioq;
1068 struct vtblk_request *req;
1069 struct bio *bp;
1070
1071 bioq = &sc->vtblk_bioq;
1072
1033 if (sc->vtblk_vq != NULL)
1073 if (sc->vtblk_vq != NULL) {
1074 vtblk_finish_completed(sc);
1034 vtblk_drain_vq(sc, 0);
1075 vtblk_drain_vq(sc, 0);
1076 }
1035
1036 while ((req = vtblk_dequeue_ready(sc)) != NULL) {
1077
1078 while ((req = vtblk_dequeue_ready(sc)) != NULL) {
1037 vtblk_bio_error(req->vbr_bp, ENXIO);
1079 vtblk_finish_bio(req->vbr_bp, ENXIO);
1038 vtblk_enqueue_request(sc, req);
1039 }
1040
1041 while (bioq_first(bioq) != NULL) {
1042 bp = bioq_takefirst(bioq);
1080 vtblk_enqueue_request(sc, req);
1081 }
1082
1083 while (bioq_first(bioq) != NULL) {
1084 bp = bioq_takefirst(bioq);
1043 vtblk_bio_error(bp, ENXIO);
1085 vtblk_finish_bio(bp, ENXIO);
1044 }
1045
1046 vtblk_free_requests(sc);
1047}
1048
1049static int
1050vtblk_alloc_requests(struct vtblk_softc *sc)
1051{
1052 struct vtblk_request *req;
1086 }
1087
1088 vtblk_free_requests(sc);
1089}
1090
1091static int
1092vtblk_alloc_requests(struct vtblk_softc *sc)
1093{
1094 struct vtblk_request *req;
1053 int i, size;
1095 int i, nreqs;
1054
1096
1055 size = virtqueue_size(sc->vtblk_vq);
1097 nreqs = virtqueue_size(sc->vtblk_vq);
1056
1057 /*
1058 * Preallocate sufficient requests to keep the virtqueue full. Each
1059 * request consumes VTBLK_MIN_SEGMENTS or more descriptors so reduce
1060 * the number allocated when indirect descriptors are not available.
1061 */
1062 if ((sc->vtblk_flags & VTBLK_FLAG_INDIRECT) == 0)
1098
1099 /*
1100 * Preallocate sufficient requests to keep the virtqueue full. Each
1101 * request consumes VTBLK_MIN_SEGMENTS or more descriptors so reduce
1102 * the number allocated when indirect descriptors are not available.
1103 */
1104 if ((sc->vtblk_flags & VTBLK_FLAG_INDIRECT) == 0)
1063 size /= VTBLK_MIN_SEGMENTS;
1105 nreqs /= VTBLK_MIN_SEGMENTS;
1064
1106
1065 for (i = 0; i < size; i++) {
1107 for (i = 0; i < nreqs; i++) {
1066 req = uma_zalloc(vtblk_req_zone, M_NOWAIT);
1067 if (req == NULL)
1068 return (ENOMEM);
1069
1070 sc->vtblk_request_count++;
1071 vtblk_enqueue_request(sc, req);
1072 }
1073
1074 return (0);
1075}
1076
1077static void
1078vtblk_free_requests(struct vtblk_softc *sc)
1079{
1080 struct vtblk_request *req;
1081
1108 req = uma_zalloc(vtblk_req_zone, M_NOWAIT);
1109 if (req == NULL)
1110 return (ENOMEM);
1111
1112 sc->vtblk_request_count++;
1113 vtblk_enqueue_request(sc, req);
1114 }
1115
1116 return (0);
1117}
1118
1119static void
1120vtblk_free_requests(struct vtblk_softc *sc)
1121{
1122 struct vtblk_request *req;
1123
1124 KASSERT(TAILQ_EMPTY(&sc->vtblk_req_ready),
1125 ("ready requests left on queue"));
1126
1082 while ((req = vtblk_dequeue_request(sc)) != NULL) {
1083 sc->vtblk_request_count--;
1084 uma_zfree(vtblk_req_zone, req);
1085 }
1086
1087 KASSERT(sc->vtblk_request_count == 0, ("leaked requests"));
1088}
1089

--- 31 unchanged lines hidden (view full) ---

1121
1122static void
1123vtblk_enqueue_ready(struct vtblk_softc *sc, struct vtblk_request *req)
1124{
1125
1126 TAILQ_INSERT_HEAD(&sc->vtblk_req_ready, req, vbr_link);
1127}
1128
1127 while ((req = vtblk_dequeue_request(sc)) != NULL) {
1128 sc->vtblk_request_count--;
1129 uma_zfree(vtblk_req_zone, req);
1130 }
1131
1132 KASSERT(sc->vtblk_request_count == 0, ("leaked requests"));
1133}
1134

--- 31 unchanged lines hidden (view full) ---

1166
1167static void
1168vtblk_enqueue_ready(struct vtblk_softc *sc, struct vtblk_request *req)
1169{
1170
1171 TAILQ_INSERT_HEAD(&sc->vtblk_req_ready, req, vbr_link);
1172}
1173
1174static int
1175vtblk_request_error(struct vtblk_request *req)
1176{
1177 int error;
1178
1179 switch (req->vbr_ack) {
1180 case VIRTIO_BLK_S_OK:
1181 error = 0;
1182 break;
1183 case VIRTIO_BLK_S_UNSUPP:
1184 error = ENOTSUP;
1185 break;
1186 default:
1187 error = EIO;
1188 break;
1189 }
1190
1191 return (error);
1192}
1193
1129static void
1194static void
1130vtblk_bio_error(struct bio *bp, int error)
1195vtblk_finish_bio(struct bio *bp, int error)
1131{
1132
1196{
1197
1133 biofinish(bp, NULL, error);
1198 if (error) {
1199 bp->bio_resid = bp->bio_bcount;
1200 bp->bio_error = error;
1201 bp->bio_flags |= BIO_ERROR;
1202 }
1203
1204 biodone(bp);
1134}
1205}