Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/virtio/block/virtio_blk.c
Show First 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | struct vtblk_softc { | ||||
uint64_t vtblk_features; | uint64_t vtblk_features; | ||||
uint32_t vtblk_flags; | uint32_t vtblk_flags; | ||||
#define VTBLK_FLAG_INDIRECT 0x0001 | #define VTBLK_FLAG_INDIRECT 0x0001 | ||||
#define VTBLK_FLAG_READONLY 0x0002 | #define VTBLK_FLAG_READONLY 0x0002 | ||||
#define VTBLK_FLAG_DETACH 0x0004 | #define VTBLK_FLAG_DETACH 0x0004 | ||||
#define VTBLK_FLAG_SUSPEND 0x0008 | #define VTBLK_FLAG_SUSPEND 0x0008 | ||||
#define VTBLK_FLAG_BARRIER 0x0010 | #define VTBLK_FLAG_BARRIER 0x0010 | ||||
#define VTBLK_FLAG_WC_CONFIG 0x0020 | #define VTBLK_FLAG_WC_CONFIG 0x0020 | ||||
#define VTBLK_FLAG_DISCARD 0x0040 | |||||
struct virtqueue *vtblk_vq; | struct virtqueue *vtblk_vq; | ||||
struct sglist *vtblk_sglist; | struct sglist *vtblk_sglist; | ||||
struct disk *vtblk_disk; | struct disk *vtblk_disk; | ||||
struct bio_queue_head vtblk_bioq; | struct bio_queue_head vtblk_bioq; | ||||
TAILQ_HEAD(, vtblk_request) | TAILQ_HEAD(, vtblk_request) | ||||
vtblk_req_free; | vtblk_req_free; | ||||
Show All 15 Lines | static struct virtio_feature_desc vtblk_feature_desc[] = { | ||||
{ VIRTIO_BLK_F_SEG_MAX, "MaxNumSegs" }, | { VIRTIO_BLK_F_SEG_MAX, "MaxNumSegs" }, | ||||
{ VIRTIO_BLK_F_GEOMETRY, "DiskGeometry" }, | { VIRTIO_BLK_F_GEOMETRY, "DiskGeometry" }, | ||||
{ VIRTIO_BLK_F_RO, "ReadOnly" }, | { VIRTIO_BLK_F_RO, "ReadOnly" }, | ||||
{ VIRTIO_BLK_F_BLK_SIZE, "BlockSize" }, | { VIRTIO_BLK_F_BLK_SIZE, "BlockSize" }, | ||||
{ VIRTIO_BLK_F_SCSI, "SCSICmds" }, | { VIRTIO_BLK_F_SCSI, "SCSICmds" }, | ||||
{ VIRTIO_BLK_F_WCE, "WriteCache" }, | { VIRTIO_BLK_F_WCE, "WriteCache" }, | ||||
{ VIRTIO_BLK_F_TOPOLOGY, "Topology" }, | { VIRTIO_BLK_F_TOPOLOGY, "Topology" }, | ||||
{ VIRTIO_BLK_F_CONFIG_WCE, "ConfigWCE" }, | { VIRTIO_BLK_F_CONFIG_WCE, "ConfigWCE" }, | ||||
{ VIRTIO_BLK_F_DISCARD, "Discard" }, | |||||
{ 0, NULL } | { 0, NULL } | ||||
}; | }; | ||||
static int vtblk_modevent(module_t, int, void *); | static int vtblk_modevent(module_t, int, void *); | ||||
static int vtblk_probe(device_t); | static int vtblk_probe(device_t); | ||||
static int vtblk_attach(device_t); | static int vtblk_attach(device_t); | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | #define VTBLK_FEATURES \ | ||||
VIRTIO_BLK_F_SIZE_MAX | \ | VIRTIO_BLK_F_SIZE_MAX | \ | ||||
VIRTIO_BLK_F_SEG_MAX | \ | VIRTIO_BLK_F_SEG_MAX | \ | ||||
VIRTIO_BLK_F_GEOMETRY | \ | VIRTIO_BLK_F_GEOMETRY | \ | ||||
VIRTIO_BLK_F_RO | \ | VIRTIO_BLK_F_RO | \ | ||||
VIRTIO_BLK_F_BLK_SIZE | \ | VIRTIO_BLK_F_BLK_SIZE | \ | ||||
VIRTIO_BLK_F_WCE | \ | VIRTIO_BLK_F_WCE | \ | ||||
VIRTIO_BLK_F_TOPOLOGY | \ | VIRTIO_BLK_F_TOPOLOGY | \ | ||||
VIRTIO_BLK_F_CONFIG_WCE | \ | VIRTIO_BLK_F_CONFIG_WCE | \ | ||||
VIRTIO_BLK_F_DISCARD | \ | |||||
VIRTIO_RING_F_INDIRECT_DESC) | VIRTIO_RING_F_INDIRECT_DESC) | ||||
#define VTBLK_MTX(_sc) &(_sc)->vtblk_mtx | #define VTBLK_MTX(_sc) &(_sc)->vtblk_mtx | ||||
#define VTBLK_LOCK_INIT(_sc, _name) \ | #define VTBLK_LOCK_INIT(_sc, _name) \ | ||||
mtx_init(VTBLK_MTX((_sc)), (_name), \ | mtx_init(VTBLK_MTX((_sc)), (_name), \ | ||||
"VirtIO Block Lock", MTX_DEF) | "VirtIO Block Lock", MTX_DEF) | ||||
#define VTBLK_LOCK(_sc) mtx_lock(VTBLK_MTX((_sc))) | #define VTBLK_LOCK(_sc) mtx_lock(VTBLK_MTX((_sc))) | ||||
#define VTBLK_UNLOCK(_sc) mtx_unlock(VTBLK_MTX((_sc))) | #define VTBLK_UNLOCK(_sc) mtx_unlock(VTBLK_MTX((_sc))) | ||||
▲ Show 20 Lines • Show All 233 Lines • ▼ Show 20 Lines | vtblk_config_change(device_t dev) | ||||
struct virtio_blk_config blkcfg; | struct virtio_blk_config blkcfg; | ||||
uint64_t capacity; | uint64_t capacity; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
vtblk_read_config(sc, &blkcfg); | vtblk_read_config(sc, &blkcfg); | ||||
/* Capacity is always in 512-byte units. */ | /* Capacity is always in 512-byte units. */ | ||||
capacity = blkcfg.capacity * 512; | capacity = blkcfg.capacity * VTBLK_BSIZE; | ||||
if (sc->vtblk_disk->d_mediasize != capacity) | if (sc->vtblk_disk->d_mediasize != capacity) | ||||
vtblk_resize_disk(sc, capacity); | vtblk_resize_disk(sc, capacity); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | if ((sc = bp->bio_disk->d_drv1) == NULL) { | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Fail any write if RO. Unfortunately, there does not seem to | * Fail any write if RO. Unfortunately, there does not seem to | ||||
* be a better way to report our readonly'ness to GEOM above. | * be a better way to report our readonly'ness to GEOM above. | ||||
*/ | */ | ||||
if (sc->vtblk_flags & VTBLK_FLAG_READONLY && | if (sc->vtblk_flags & VTBLK_FLAG_READONLY && | ||||
(bp->bio_cmd == BIO_WRITE || bp->bio_cmd == BIO_FLUSH)) { | (bp->bio_cmd == BIO_WRITE || bp->bio_cmd == BIO_FLUSH || | ||||
bp->bio_cmd == BIO_DELETE)) { | |||||
vtblk_bio_done(sc, bp, EROFS); | vtblk_bio_done(sc, bp, EROFS); | ||||
return; | return; | ||||
} | } | ||||
if ((bp->bio_cmd != BIO_READ) && (bp->bio_cmd != BIO_WRITE) && | if ((bp->bio_cmd != BIO_READ) && (bp->bio_cmd != BIO_WRITE) && | ||||
(bp->bio_cmd != BIO_FLUSH)) { | (bp->bio_cmd != BIO_FLUSH) && (bp->bio_cmd != BIO_DELETE)) { | ||||
vtblk_bio_done(sc, bp, EOPNOTSUPP); | vtblk_bio_done(sc, bp, EOPNOTSUPP); | ||||
return; | return; | ||||
} | } | ||||
VTBLK_LOCK(sc); | VTBLK_LOCK(sc); | ||||
if (sc->vtblk_flags & VTBLK_FLAG_DETACH) { | if (sc->vtblk_flags & VTBLK_FLAG_DETACH) { | ||||
VTBLK_UNLOCK(sc); | VTBLK_UNLOCK(sc); | ||||
vtblk_bio_done(sc, bp, ENXIO); | vtblk_bio_done(sc, bp, ENXIO); | ||||
return; | return; | ||||
} | } | ||||
if ((bp->bio_cmd == BIO_DELETE) && | |||||
!(sc->vtblk_flags & VTBLK_FLAG_DISCARD)) { | |||||
VTBLK_UNLOCK(sc); | |||||
vtblk_bio_done(sc, bp, EOPNOTSUPP); | |||||
return; | |||||
} | |||||
bioq_insert_tail(&sc->vtblk_bioq, bp); | bioq_insert_tail(&sc->vtblk_bioq, bp); | ||||
vtblk_startio(sc); | vtblk_startio(sc); | ||||
VTBLK_UNLOCK(sc); | VTBLK_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
vtblk_negotiate_features(struct vtblk_softc *sc) | vtblk_negotiate_features(struct vtblk_softc *sc) | ||||
Show All 19 Lines | vtblk_setup_features(struct vtblk_softc *sc) | ||||
if (virtio_with_feature(dev, VIRTIO_RING_F_INDIRECT_DESC)) | if (virtio_with_feature(dev, VIRTIO_RING_F_INDIRECT_DESC)) | ||||
sc->vtblk_flags |= VTBLK_FLAG_INDIRECT; | sc->vtblk_flags |= VTBLK_FLAG_INDIRECT; | ||||
if (virtio_with_feature(dev, VIRTIO_BLK_F_RO)) | if (virtio_with_feature(dev, VIRTIO_BLK_F_RO)) | ||||
sc->vtblk_flags |= VTBLK_FLAG_READONLY; | sc->vtblk_flags |= VTBLK_FLAG_READONLY; | ||||
if (virtio_with_feature(dev, VIRTIO_BLK_F_BARRIER)) | if (virtio_with_feature(dev, VIRTIO_BLK_F_BARRIER)) | ||||
sc->vtblk_flags |= VTBLK_FLAG_BARRIER; | sc->vtblk_flags |= VTBLK_FLAG_BARRIER; | ||||
if (virtio_with_feature(dev, VIRTIO_BLK_F_CONFIG_WCE)) | if (virtio_with_feature(dev, VIRTIO_BLK_F_CONFIG_WCE)) | ||||
sc->vtblk_flags |= VTBLK_FLAG_WC_CONFIG; | sc->vtblk_flags |= VTBLK_FLAG_WC_CONFIG; | ||||
if (virtio_with_feature(dev, VIRTIO_BLK_F_DISCARD)) | |||||
sc->vtblk_flags |= VTBLK_FLAG_DISCARD; | |||||
} | } | ||||
static int | static int | ||||
vtblk_maximum_segments(struct vtblk_softc *sc, | vtblk_maximum_segments(struct vtblk_softc *sc, | ||||
struct virtio_blk_config *blkcfg) | struct virtio_blk_config *blkcfg) | ||||
{ | { | ||||
device_t dev; | device_t dev; | ||||
int nsegs; | int nsegs; | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | vtblk_alloc_disk(struct vtblk_softc *sc, struct virtio_blk_config *blkcfg) | ||||
dp->d_hba_device = virtio_get_device(dev); | dp->d_hba_device = virtio_get_device(dev); | ||||
dp->d_hba_subvendor = virtio_get_subvendor(dev); | dp->d_hba_subvendor = virtio_get_subvendor(dev); | ||||
dp->d_hba_subdevice = virtio_get_subdevice(dev); | dp->d_hba_subdevice = virtio_get_subdevice(dev); | ||||
if ((sc->vtblk_flags & VTBLK_FLAG_READONLY) == 0) | if ((sc->vtblk_flags & VTBLK_FLAG_READONLY) == 0) | ||||
dp->d_dump = vtblk_dump; | dp->d_dump = vtblk_dump; | ||||
/* Capacity is always in 512-byte units. */ | /* Capacity is always in 512-byte units. */ | ||||
dp->d_mediasize = blkcfg->capacity * 512; | dp->d_mediasize = blkcfg->capacity * VTBLK_BSIZE; | ||||
if (virtio_with_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) | if (virtio_with_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) | ||||
dp->d_sectorsize = blkcfg->blk_size; | dp->d_sectorsize = blkcfg->blk_size; | ||||
else | else | ||||
dp->d_sectorsize = 512; | dp->d_sectorsize = VTBLK_BSIZE; | ||||
/* | /* | ||||
* The VirtIO maximum I/O size is given in terms of segments. | * The VirtIO maximum I/O size is given in terms of segments. | ||||
* However, FreeBSD limits I/O size by logical buffer size, not | * However, FreeBSD limits I/O size by logical buffer size, not | ||||
* by physically contiguous pages. Therefore, we have to assume | * by physically contiguous pages. Therefore, we have to assume | ||||
* no pages are contiguous. This may impose an artificially low | * no pages are contiguous. This may impose an artificially low | ||||
* maximum I/O size. But in practice, since QEMU advertises 128 | * maximum I/O size. But in practice, since QEMU advertises 128 | ||||
* segments, this gives us a maximum IO size of 125 * PAGE_SIZE, | * segments, this gives us a maximum IO size of 125 * PAGE_SIZE, | ||||
Show All 17 Lines | if (virtio_with_feature(dev, VIRTIO_BLK_F_TOPOLOGY) && | ||||
blkcfg->topology.physical_block_exp > 0) { | blkcfg->topology.physical_block_exp > 0) { | ||||
dp->d_stripesize = dp->d_sectorsize * | dp->d_stripesize = dp->d_sectorsize * | ||||
(1 << blkcfg->topology.physical_block_exp); | (1 << blkcfg->topology.physical_block_exp); | ||||
dp->d_stripeoffset = (dp->d_stripesize - | dp->d_stripeoffset = (dp->d_stripesize - | ||||
blkcfg->topology.alignment_offset * dp->d_sectorsize) % | blkcfg->topology.alignment_offset * dp->d_sectorsize) % | ||||
dp->d_stripesize; | dp->d_stripesize; | ||||
} | } | ||||
if (virtio_with_feature(dev, VIRTIO_BLK_F_DISCARD)) { | |||||
dp->d_flags |= DISKFLAG_CANDELETE; | |||||
dp->d_delmaxsize = blkcfg->max_discard_sectors * VTBLK_BSIZE; | |||||
} | |||||
if (vtblk_write_cache_enabled(sc, blkcfg) != 0) | if (vtblk_write_cache_enabled(sc, blkcfg) != 0) | ||||
sc->vtblk_write_cache = VTBLK_CACHE_WRITEBACK; | sc->vtblk_write_cache = VTBLK_CACHE_WRITEBACK; | ||||
else | else | ||||
sc->vtblk_write_cache = VTBLK_CACHE_WRITETHROUGH; | sc->vtblk_write_cache = VTBLK_CACHE_WRITETHROUGH; | ||||
} | } | ||||
static void | static void | ||||
vtblk_create_disk(struct vtblk_softc *sc) | vtblk_create_disk(struct vtblk_softc *sc) | ||||
▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | vtblk_request_bio(struct vtblk_softc *sc) | ||||
req->vbr_hdr.ioprio = 1; | req->vbr_hdr.ioprio = 1; | ||||
switch (bp->bio_cmd) { | switch (bp->bio_cmd) { | ||||
case BIO_FLUSH: | case BIO_FLUSH: | ||||
req->vbr_hdr.type = VIRTIO_BLK_T_FLUSH; | req->vbr_hdr.type = VIRTIO_BLK_T_FLUSH; | ||||
break; | break; | ||||
case BIO_READ: | case BIO_READ: | ||||
req->vbr_hdr.type = VIRTIO_BLK_T_IN; | req->vbr_hdr.type = VIRTIO_BLK_T_IN; | ||||
req->vbr_hdr.sector = bp->bio_offset / 512; | req->vbr_hdr.sector = bp->bio_offset / VTBLK_BSIZE; | ||||
break; | break; | ||||
case BIO_WRITE: | case BIO_WRITE: | ||||
req->vbr_hdr.type = VIRTIO_BLK_T_OUT; | req->vbr_hdr.type = VIRTIO_BLK_T_OUT; | ||||
req->vbr_hdr.sector = bp->bio_offset / 512; | req->vbr_hdr.sector = bp->bio_offset / VTBLK_BSIZE; | ||||
break; | break; | ||||
case BIO_DELETE: | |||||
req->vbr_hdr.type = VIRTIO_BLK_T_DISCARD; | |||||
req->vbr_hdr.sector = bp->bio_offset / VTBLK_BSIZE; | |||||
break; | |||||
default: | default: | ||||
panic("%s: bio with unhandled cmd: %d", __func__, bp->bio_cmd); | panic("%s: bio with unhandled cmd: %d", __func__, bp->bio_cmd); | ||||
} | } | ||||
if (bp->bio_flags & BIO_ORDERED) | if (bp->bio_flags & BIO_ORDERED) | ||||
req->vbr_hdr.type |= VIRTIO_BLK_T_BARRIER; | req->vbr_hdr.type |= VIRTIO_BLK_T_BARRIER; | ||||
return (req); | return (req); | ||||
Show All 37 Lines | if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { | ||||
if (error || sg->sg_nseg == sg->sg_maxseg) { | if (error || sg->sg_nseg == sg->sg_maxseg) { | ||||
panic("%s: bio %p data buffer too big %d", | panic("%s: bio %p data buffer too big %d", | ||||
__func__, bp, error); | __func__, bp, error); | ||||
} | } | ||||
/* BIO_READ means the host writes into our buffer. */ | /* BIO_READ means the host writes into our buffer. */ | ||||
if (bp->bio_cmd == BIO_READ) | if (bp->bio_cmd == BIO_READ) | ||||
writable = sg->sg_nseg - 1; | writable = sg->sg_nseg - 1; | ||||
} else if (bp->bio_cmd == BIO_DELETE) { | |||||
struct virtio_blk_discard_write_zeroes *discard; | |||||
discard = malloc(sizeof(*discard), M_DEVBUF, M_NOWAIT | M_ZERO); | |||||
if (discard == NULL) | |||||
return (ENOMEM); | |||||
discard->sector = bp->bio_offset / VTBLK_BSIZE; | |||||
discard->num_sectors = bp->bio_bcount / VTBLK_BSIZE; | |||||
bp->bio_driver1 = discard; | |||||
error = sglist_append(sg, discard, sizeof(*discard)); | |||||
if (error || sg->sg_nseg == sg->sg_maxseg) { | |||||
panic("%s: bio %p data buffer too big %d", | |||||
__func__, bp, error); | |||||
} | } | ||||
} | |||||
writable++; | writable++; | ||||
sglist_append(sg, &req->vbr_ack, sizeof(uint8_t)); | sglist_append(sg, &req->vbr_ack, sizeof(uint8_t)); | ||||
readable = sg->sg_nseg - writable; | readable = sg->sg_nseg - writable; | ||||
error = virtqueue_enqueue(vq, req, sg, readable, writable); | error = virtqueue_enqueue(vq, req, sg, readable, writable); | ||||
if (error == 0 && ordered) | if (error == 0 && ordered) | ||||
sc->vtblk_req_ordered = req; | sc->vtblk_req_ordered = req; | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | if (sc != NULL) | ||||
VTBLK_LOCK_ASSERT_NOTOWNED(sc); | VTBLK_LOCK_ASSERT_NOTOWNED(sc); | ||||
if (error) { | if (error) { | ||||
bp->bio_resid = bp->bio_bcount; | bp->bio_resid = bp->bio_bcount; | ||||
bp->bio_error = error; | bp->bio_error = error; | ||||
bp->bio_flags |= BIO_ERROR; | bp->bio_flags |= BIO_ERROR; | ||||
} | } | ||||
if (bp->bio_driver1 != NULL) { | |||||
free(bp->bio_driver1, M_DEVBUF); | |||||
bp->bio_driver1 = NULL; | |||||
} | |||||
biodone(bp); | biodone(bp); | ||||
} | } | ||||
#define VTBLK_GET_CONFIG(_dev, _feature, _field, _cfg) \ | #define VTBLK_GET_CONFIG(_dev, _feature, _field, _cfg) \ | ||||
if (virtio_with_feature(_dev, _feature)) { \ | if (virtio_with_feature(_dev, _feature)) { \ | ||||
virtio_read_device_config(_dev, \ | virtio_read_device_config(_dev, \ | ||||
offsetof(struct virtio_blk_config, _field), \ | offsetof(struct virtio_blk_config, _field), \ | ||||
&(_cfg)->_field, sizeof((_cfg)->_field)); \ | &(_cfg)->_field, sizeof((_cfg)->_field)); \ | ||||
Show All 13 Lines | virtio_read_device_config(dev, offsetof(struct virtio_blk_config, | ||||
capacity), &blkcfg->capacity, sizeof(blkcfg->capacity)); | capacity), &blkcfg->capacity, sizeof(blkcfg->capacity)); | ||||
/* Read the configuration if the feature was negotiated. */ | /* Read the configuration if the feature was negotiated. */ | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_SIZE_MAX, size_max, blkcfg); | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_SIZE_MAX, size_max, blkcfg); | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_SEG_MAX, seg_max, blkcfg); | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_SEG_MAX, seg_max, blkcfg); | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_GEOMETRY, geometry, blkcfg); | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_GEOMETRY, geometry, blkcfg); | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_BLK_SIZE, blk_size, blkcfg); | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_BLK_SIZE, blk_size, blkcfg); | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_TOPOLOGY, topology, blkcfg); | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_TOPOLOGY, topology, blkcfg); | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_CONFIG_WCE, writeback, blkcfg); | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_CONFIG_WCE, wce, blkcfg); | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, max_discard_sectors, | |||||
blkcfg); | |||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, max_discard_seg, blkcfg); | |||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, discard_sector_alignment, | |||||
blkcfg); | |||||
} | } | ||||
#undef VTBLK_GET_CONFIG | #undef VTBLK_GET_CONFIG | ||||
static void | static void | ||||
vtblk_ident(struct vtblk_softc *sc) | vtblk_ident(struct vtblk_softc *sc) | ||||
{ | { | ||||
struct bio buf; | struct bio buf; | ||||
▲ Show 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct bio buf; | struct bio buf; | ||||
struct vtblk_request *req; | struct vtblk_request *req; | ||||
req = &sc->vtblk_dump_request; | req = &sc->vtblk_dump_request; | ||||
req->vbr_ack = -1; | req->vbr_ack = -1; | ||||
req->vbr_hdr.type = VIRTIO_BLK_T_OUT; | req->vbr_hdr.type = VIRTIO_BLK_T_OUT; | ||||
req->vbr_hdr.ioprio = 1; | req->vbr_hdr.ioprio = 1; | ||||
req->vbr_hdr.sector = offset / 512; | req->vbr_hdr.sector = offset / VTBLK_BSIZE; | ||||
req->vbr_bp = &buf; | req->vbr_bp = &buf; | ||||
g_reset_bio(&buf); | g_reset_bio(&buf); | ||||
buf.bio_cmd = BIO_WRITE; | buf.bio_cmd = BIO_WRITE; | ||||
buf.bio_data = virtual; | buf.bio_data = virtual; | ||||
buf.bio_bcount = length; | buf.bio_bcount = length; | ||||
Show All 32 Lines | |||||
} | } | ||||
static void | static void | ||||
vtblk_set_write_cache(struct vtblk_softc *sc, int wc) | vtblk_set_write_cache(struct vtblk_softc *sc, int wc) | ||||
{ | { | ||||
/* Set either writeback (1) or writethrough (0) mode. */ | /* Set either writeback (1) or writethrough (0) mode. */ | ||||
virtio_write_dev_config_1(sc->vtblk_dev, | virtio_write_dev_config_1(sc->vtblk_dev, | ||||
offsetof(struct virtio_blk_config, writeback), wc); | offsetof(struct virtio_blk_config, wce), wc); | ||||
} | } | ||||
static int | static int | ||||
vtblk_write_cache_enabled(struct vtblk_softc *sc, | vtblk_write_cache_enabled(struct vtblk_softc *sc, | ||||
struct virtio_blk_config *blkcfg) | struct virtio_blk_config *blkcfg) | ||||
{ | { | ||||
int wc; | int wc; | ||||
if (sc->vtblk_flags & VTBLK_FLAG_WC_CONFIG) { | if (sc->vtblk_flags & VTBLK_FLAG_WC_CONFIG) { | ||||
wc = vtblk_tunable_int(sc, "writecache_mode", | wc = vtblk_tunable_int(sc, "writecache_mode", | ||||
vtblk_writecache_mode); | vtblk_writecache_mode); | ||||
if (wc >= 0 && wc < VTBLK_CACHE_MAX) | if (wc >= 0 && wc < VTBLK_CACHE_MAX) | ||||
vtblk_set_write_cache(sc, wc); | vtblk_set_write_cache(sc, wc); | ||||
else | else | ||||
wc = blkcfg->writeback; | wc = blkcfg->wce; | ||||
} else | } else | ||||
wc = virtio_with_feature(sc->vtblk_dev, VIRTIO_BLK_F_WCE); | wc = virtio_with_feature(sc->vtblk_dev, VIRTIO_BLK_F_WCE); | ||||
return (wc); | return (wc); | ||||
} | } | ||||
static int | static int | ||||
vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS) | vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS) | ||||
▲ Show 20 Lines • Show All 53 Lines • Show Last 20 Lines |