Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/virtio/block/virtio_blk.c
Show First 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | struct vtblk_softc { | ||||
struct mtx vtblk_mtx; | struct mtx vtblk_mtx; | ||||
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_WCE_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 12 Lines | |||||
static struct virtio_feature_desc vtblk_feature_desc[] = { | static struct virtio_feature_desc vtblk_feature_desc[] = { | ||||
{ VIRTIO_BLK_F_BARRIER, "HostBarrier" }, | { VIRTIO_BLK_F_BARRIER, "HostBarrier" }, | ||||
{ VIRTIO_BLK_F_SIZE_MAX, "MaxSegSize" }, | { VIRTIO_BLK_F_SIZE_MAX, "MaxSegSize" }, | ||||
{ 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_FLUSH, "FlushCmd" }, | ||||
{ 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_MQ, "Multiqueue" }, | |||||
{ VIRTIO_BLK_F_DISCARD, "Discard" }, | { VIRTIO_BLK_F_DISCARD, "Discard" }, | ||||
{ VIRTIO_BLK_F_WRITE_ZEROES, "WriteZeros" }, | |||||
{ 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); | ||||
static int vtblk_detach(device_t); | static int vtblk_detach(device_t); | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
static void vtblk_set_write_cache(struct vtblk_softc *, int); | static void vtblk_set_write_cache(struct vtblk_softc *, int); | ||||
static int vtblk_write_cache_enabled(struct vtblk_softc *sc, | static int vtblk_write_cache_enabled(struct vtblk_softc *sc, | ||||
struct virtio_blk_config *); | struct virtio_blk_config *); | ||||
static int vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS); | static int vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static void vtblk_setup_sysctl(struct vtblk_softc *); | static void vtblk_setup_sysctl(struct vtblk_softc *); | ||||
static int vtblk_tunable_int(struct vtblk_softc *, const char *, int); | static int vtblk_tunable_int(struct vtblk_softc *, const char *, int); | ||||
#define vtblk_modern(_sc) (((_sc)->vtblk_features & VIRTIO_F_VERSION_1) != 0) | |||||
#define vtblk_htog16(_sc, _val) virtio_htog16(vtblk_modern(_sc), _val) | |||||
#define vtblk_htog32(_sc, _val) virtio_htog32(vtblk_modern(_sc), _val) | |||||
#define vtblk_htog64(_sc, _val) virtio_htog64(vtblk_modern(_sc), _val) | |||||
#define vtblk_gtoh16(_sc, _val) virtio_gtoh16(vtblk_modern(_sc), _val) | |||||
#define vtblk_gtoh32(_sc, _val) virtio_gtoh32(vtblk_modern(_sc), _val) | |||||
#define vtblk_gtoh64(_sc, _val) virtio_gtoh64(vtblk_modern(_sc), _val) | |||||
/* Tunables. */ | /* Tunables. */ | ||||
static int vtblk_no_ident = 0; | static int vtblk_no_ident = 0; | ||||
TUNABLE_INT("hw.vtblk.no_ident", &vtblk_no_ident); | TUNABLE_INT("hw.vtblk.no_ident", &vtblk_no_ident); | ||||
static int vtblk_writecache_mode = -1; | static int vtblk_writecache_mode = -1; | ||||
TUNABLE_INT("hw.vtblk.writecache_mode", &vtblk_writecache_mode); | TUNABLE_INT("hw.vtblk.writecache_mode", &vtblk_writecache_mode); | ||||
/* Features desired/implemented by this driver. */ | #define VTBLK_COMMON_FEATURES \ | ||||
#define VTBLK_FEATURES \ | (VIRTIO_BLK_F_SIZE_MAX | \ | ||||
(VIRTIO_BLK_F_BARRIER | \ | |||||
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_FLUSH | \ | ||||
VIRTIO_BLK_F_TOPOLOGY | \ | VIRTIO_BLK_F_TOPOLOGY | \ | ||||
VIRTIO_BLK_F_CONFIG_WCE | \ | VIRTIO_BLK_F_CONFIG_WCE | \ | ||||
VIRTIO_BLK_F_DISCARD | \ | VIRTIO_BLK_F_DISCARD | \ | ||||
VIRTIO_RING_F_INDIRECT_DESC) | VIRTIO_RING_F_INDIRECT_DESC) | ||||
#define VTBLK_MODERN_FEATURES (VTBLK_COMMON_FEATURES) | |||||
#define VTBLK_LEGACY_FEATURES (VIRTIO_BLK_F_BARRIER | VTBLK_COMMON_FEATURES) | |||||
#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))) | ||||
#define VTBLK_LOCK_DESTROY(_sc) mtx_destroy(VTBLK_MTX((_sc))) | #define VTBLK_LOCK_DESTROY(_sc) mtx_destroy(VTBLK_MTX((_sc))) | ||||
#define VTBLK_LOCK_ASSERT(_sc) mtx_assert(VTBLK_MTX((_sc)), MA_OWNED) | #define VTBLK_LOCK_ASSERT(_sc) mtx_assert(VTBLK_MTX((_sc)), MA_OWNED) | ||||
#define VTBLK_LOCK_ASSERT_NOTOWNED(_sc) \ | #define VTBLK_LOCK_ASSERT_NOTOWNED(_sc) \ | ||||
mtx_assert(VTBLK_MTX((_sc)), MA_NOTOWNED) | mtx_assert(VTBLK_MTX((_sc)), MA_NOTOWNED) | ||||
#define VTBLK_DISK_NAME "vtbd" | #define VTBLK_DISK_NAME "vtbd" | ||||
#define VTBLK_QUIESCE_TIMEOUT (30 * hz) | #define VTBLK_QUIESCE_TIMEOUT (30 * hz) | ||||
#define VTBLK_BSIZE 512 | |||||
/* | /* | ||||
* Each block request uses at least two segments - one for the header | * Each block request uses at least two segments - one for the header | ||||
* and one for the status. | * and one for the status. | ||||
*/ | */ | ||||
#define VTBLK_MIN_SEGMENTS 2 | #define VTBLK_MIN_SEGMENTS 2 | ||||
static device_method_t vtblk_methods[] = { | static device_method_t vtblk_methods[] = { | ||||
▲ Show 20 Lines • Show All 322 Lines • ▼ Show 20 Lines | vtblk_strategy(struct bio *bp) | ||||
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); | ||||
grehan: Was the deleted code block a no-op ? (guessing there won't be DELETE bio's if the… | |||||
Done Inline ActionsYes. geom_disk already checks for DISKFLAG_CANDELETE before send down the BIO bryanv: Yes. geom_disk already checks for DISKFLAG_CANDELETE before send down the BIO | |||||
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) | ||||
{ | { | ||||
device_t dev; | device_t dev; | ||||
uint64_t features; | uint64_t features; | ||||
dev = sc->vtblk_dev; | dev = sc->vtblk_dev; | ||||
features = VTBLK_FEATURES; | features = virtio_bus_is_modern(dev) ? VTBLK_MODERN_FEATURES : | ||||
VTBLK_LEGACY_FEATURES; | |||||
sc->vtblk_features = virtio_negotiate_features(dev, features); | sc->vtblk_features = virtio_negotiate_features(dev, features); | ||||
virtio_finalize_features(dev); | |||||
} | } | ||||
static void | static void | ||||
vtblk_setup_features(struct vtblk_softc *sc) | vtblk_setup_features(struct vtblk_softc *sc) | ||||
{ | { | ||||
device_t dev; | device_t dev; | ||||
dev = sc->vtblk_dev; | dev = sc->vtblk_dev; | ||||
vtblk_negotiate_features(sc); | vtblk_negotiate_features(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_CONFIG_WCE)) | |||||
sc->vtblk_flags |= VTBLK_FLAG_WCE_CONFIG; | |||||
/* Legacy. */ | |||||
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)) | |||||
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 62 Lines • ▼ Show 20 Lines | vtblk_alloc_disk(struct vtblk_softc *sc, struct virtio_blk_config *blkcfg) | ||||
sc->vtblk_disk = dp = disk_alloc(); | sc->vtblk_disk = dp = disk_alloc(); | ||||
dp->d_open = vtblk_open; | dp->d_open = vtblk_open; | ||||
dp->d_close = vtblk_close; | dp->d_close = vtblk_close; | ||||
dp->d_ioctl = vtblk_ioctl; | dp->d_ioctl = vtblk_ioctl; | ||||
dp->d_strategy = vtblk_strategy; | dp->d_strategy = vtblk_strategy; | ||||
dp->d_name = VTBLK_DISK_NAME; | dp->d_name = VTBLK_DISK_NAME; | ||||
dp->d_unit = device_get_unit(dev); | dp->d_unit = device_get_unit(dev); | ||||
dp->d_drv1 = sc; | dp->d_drv1 = sc; | ||||
dp->d_flags = DISKFLAG_CANFLUSHCACHE | DISKFLAG_UNMAPPED_BIO | | dp->d_flags = DISKFLAG_UNMAPPED_BIO | DISKFLAG_DIRECT_COMPLETION; | ||||
DISKFLAG_DIRECT_COMPLETION; | |||||
dp->d_hba_vendor = virtio_get_vendor(dev); | dp->d_hba_vendor = virtio_get_vendor(dev); | ||||
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 (virtio_with_feature(dev, VIRTIO_BLK_F_FLUSH)) | |||||
dp->d_flags |= DISKFLAG_CANFLUSHCACHE; | |||||
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 * VTBLK_BSIZE; | 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; | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | vtblk_request_bio(struct vtblk_softc *sc) | ||||
req = vtblk_request_dequeue(sc); | req = vtblk_request_dequeue(sc); | ||||
if (req == NULL) | if (req == NULL) | ||||
return (NULL); | return (NULL); | ||||
bp = bioq_takefirst(bioq); | bp = bioq_takefirst(bioq); | ||||
req->vbr_bp = bp; | req->vbr_bp = bp; | ||||
req->vbr_ack = -1; | req->vbr_ack = -1; | ||||
req->vbr_hdr.ioprio = 1; | req->vbr_hdr.ioprio = vtblk_gtoh32(sc, 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 = vtblk_gtoh32(sc, VIRTIO_BLK_T_FLUSH); | ||||
req->vbr_hdr.sector = 0; | |||||
break; | break; | ||||
case BIO_READ: | case BIO_READ: | ||||
req->vbr_hdr.type = VIRTIO_BLK_T_IN; | req->vbr_hdr.type = vtblk_gtoh32(sc, VIRTIO_BLK_T_IN); | ||||
req->vbr_hdr.sector = bp->bio_offset / VTBLK_BSIZE; | req->vbr_hdr.sector = vtblk_gtoh64(sc, 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 = vtblk_gtoh32(sc, VIRTIO_BLK_T_OUT); | ||||
req->vbr_hdr.sector = bp->bio_offset / VTBLK_BSIZE; | req->vbr_hdr.sector = vtblk_gtoh64(sc, bp->bio_offset / VTBLK_BSIZE); | ||||
break; | break; | ||||
case BIO_DELETE: | case BIO_DELETE: | ||||
req->vbr_hdr.type = VIRTIO_BLK_T_DISCARD; | req->vbr_hdr.type = vtblk_gtoh32(sc, VIRTIO_BLK_T_DISCARD); | ||||
req->vbr_hdr.sector = bp->bio_offset / VTBLK_BSIZE; | req->vbr_hdr.sector = vtblk_gtoh64(sc, bp->bio_offset / VTBLK_BSIZE); | ||||
break; | 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 |= vtblk_gtoh32(sc, VIRTIO_BLK_T_BARRIER); | ||||
return (req); | return (req); | ||||
} | } | ||||
static int | static int | ||||
vtblk_request_execute(struct vtblk_softc *sc, struct vtblk_request *req) | vtblk_request_execute(struct vtblk_softc *sc, struct vtblk_request *req) | ||||
{ | { | ||||
struct virtqueue *vq; | struct virtqueue *vq; | ||||
Show All 14 Lines | vtblk_request_execute(struct vtblk_softc *sc, struct vtblk_request *req) | ||||
*/ | */ | ||||
if ((sc->vtblk_flags & VTBLK_FLAG_BARRIER) == 0) { | if ((sc->vtblk_flags & VTBLK_FLAG_BARRIER) == 0) { | ||||
if (sc->vtblk_req_ordered != NULL) | if (sc->vtblk_req_ordered != NULL) | ||||
return (EBUSY); | return (EBUSY); | ||||
if (bp->bio_flags & BIO_ORDERED) { | if (bp->bio_flags & BIO_ORDERED) { | ||||
if (!virtqueue_empty(vq)) | if (!virtqueue_empty(vq)) | ||||
return (EBUSY); | return (EBUSY); | ||||
ordered = 1; | ordered = 1; | ||||
req->vbr_hdr.type &= ~VIRTIO_BLK_T_BARRIER; | req->vbr_hdr.type &= vtblk_gtoh32(sc, | ||||
~VIRTIO_BLK_T_BARRIER); | |||||
} | } | ||||
} | } | ||||
sglist_reset(sg); | sglist_reset(sg); | ||||
sglist_append(sg, &req->vbr_hdr, sizeof(struct virtio_blk_outhdr)); | sglist_append(sg, &req->vbr_hdr, sizeof(struct virtio_blk_outhdr)); | ||||
if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { | if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { | ||||
error = sglist_append_bio(sg, bp); | error = sglist_append_bio(sg, bp); | ||||
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) { | } else if (bp->bio_cmd == BIO_DELETE) { | ||||
struct virtio_blk_discard_write_zeroes *discard; | struct virtio_blk_discard_write_zeroes *discard; | ||||
discard = malloc(sizeof(*discard), M_DEVBUF, M_NOWAIT | M_ZERO); | discard = malloc(sizeof(*discard), M_DEVBUF, M_NOWAIT | M_ZERO); | ||||
if (discard == NULL) | if (discard == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
discard->sector = bp->bio_offset / VTBLK_BSIZE; | |||||
discard->num_sectors = bp->bio_bcount / VTBLK_BSIZE; | |||||
bp->bio_driver1 = discard; | bp->bio_driver1 = discard; | ||||
discard->sector = vtblk_gtoh64(sc, bp->bio_offset / VTBLK_BSIZE); | |||||
discard->num_sectors = vtblk_gtoh32(sc, bp->bio_bcount / VTBLK_BSIZE); | |||||
error = sglist_append(sg, discard, sizeof(*discard)); | error = sglist_append(sg, discard, sizeof(*discard)); | ||||
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); | ||||
} | } | ||||
} | } | ||||
writable++; | writable++; | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | vtblk_drain_vq(struct vtblk_softc *sc) | ||||
sc->vtblk_req_ordered = NULL; | sc->vtblk_req_ordered = NULL; | ||||
KASSERT(virtqueue_empty(vq), ("virtqueue not empty")); | KASSERT(virtqueue_empty(vq), ("virtqueue not empty")); | ||||
} | } | ||||
static void | static void | ||||
vtblk_drain(struct vtblk_softc *sc) | vtblk_drain(struct vtblk_softc *sc) | ||||
{ | { | ||||
struct bio_queue queue; | |||||
struct bio_queue_head *bioq; | struct bio_queue_head *bioq; | ||||
struct vtblk_request *req; | struct vtblk_request *req; | ||||
struct bio *bp; | struct bio *bp; | ||||
bioq = &sc->vtblk_bioq; | bioq = &sc->vtblk_bioq; | ||||
TAILQ_INIT(&queue); | |||||
if (sc->vtblk_vq != NULL) { | if (sc->vtblk_vq != NULL) { | ||||
struct bio_queue queue; | |||||
TAILQ_INIT(&queue); | |||||
vtblk_queue_completed(sc, &queue); | vtblk_queue_completed(sc, &queue); | ||||
vtblk_done_completed(sc, &queue); | vtblk_done_completed(sc, &queue); | ||||
vtblk_drain_vq(sc); | vtblk_drain_vq(sc); | ||||
} | } | ||||
while ((req = vtblk_request_next_ready(sc)) != NULL) { | while ((req = vtblk_request_next_ready(sc)) != NULL) { | ||||
vtblk_bio_done(sc, req->vbr_bp, ENXIO); | vtblk_bio_done(sc, req->vbr_bp, ENXIO); | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | vtblk_read_config(struct vtblk_softc *sc, struct virtio_blk_config *blkcfg) | ||||
/* The capacity is always available. */ | /* The capacity is always available. */ | ||||
virtio_read_device_config(dev, offsetof(struct virtio_blk_config, | 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.cylinders, blkcfg); | |||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_GEOMETRY, | |||||
geometry.heads, blkcfg); | |||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_GEOMETRY, | |||||
geometry.sectors, 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.physical_block_exp, blkcfg); | |||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_TOPOLOGY, | |||||
topology.alignment_offset, blkcfg); | |||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_TOPOLOGY, | |||||
topology.min_io_size, blkcfg); | |||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_TOPOLOGY, | |||||
topology.opt_io_size, blkcfg); | |||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_CONFIG_WCE, wce, blkcfg); | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_CONFIG_WCE, wce, blkcfg); | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, max_discard_sectors, | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, max_discard_sectors, | ||||
blkcfg); | blkcfg); | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, max_discard_seg, blkcfg); | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, max_discard_seg, blkcfg); | ||||
VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, discard_sector_alignment, | VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, discard_sector_alignment, | ||||
blkcfg); | blkcfg); | ||||
} | } | ||||
Show All 13 Lines | vtblk_ident(struct vtblk_softc *sc) | ||||
if (vtblk_tunable_int(sc, "no_ident", vtblk_no_ident) != 0) | if (vtblk_tunable_int(sc, "no_ident", vtblk_no_ident) != 0) | ||||
return; | return; | ||||
req = vtblk_request_dequeue(sc); | req = vtblk_request_dequeue(sc); | ||||
if (req == NULL) | if (req == NULL) | ||||
return; | return; | ||||
req->vbr_ack = -1; | req->vbr_ack = -1; | ||||
req->vbr_hdr.type = VIRTIO_BLK_T_GET_ID; | req->vbr_hdr.type = vtblk_gtoh32(sc, VIRTIO_BLK_T_GET_ID); | ||||
req->vbr_hdr.ioprio = 1; | req->vbr_hdr.ioprio = vtblk_gtoh32(sc, 1); | ||||
req->vbr_hdr.sector = 0; | req->vbr_hdr.sector = 0; | ||||
req->vbr_bp = &buf; | req->vbr_bp = &buf; | ||||
g_reset_bio(&buf); | g_reset_bio(&buf); | ||||
buf.bio_cmd = BIO_READ; | buf.bio_cmd = BIO_READ; | ||||
buf.bio_data = dp->d_ident; | buf.bio_data = dp->d_ident; | ||||
buf.bio_bcount = len; | buf.bio_bcount = len; | ||||
▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | |||||
vtblk_dump_write(struct vtblk_softc *sc, void *virtual, off_t offset, | vtblk_dump_write(struct vtblk_softc *sc, void *virtual, off_t offset, | ||||
size_t length) | size_t length) | ||||
{ | { | ||||
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 = vtblk_gtoh32(sc, VIRTIO_BLK_T_OUT); | ||||
req->vbr_hdr.ioprio = 1; | req->vbr_hdr.ioprio = vtblk_gtoh32(sc, 1); | ||||
req->vbr_hdr.sector = offset / VTBLK_BSIZE; | req->vbr_hdr.sector = vtblk_gtoh64(sc, 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; | ||||
return (vtblk_poll_request(sc, req)); | return (vtblk_poll_request(sc, req)); | ||||
} | } | ||||
static int | static int | ||||
vtblk_dump_flush(struct vtblk_softc *sc) | vtblk_dump_flush(struct vtblk_softc *sc) | ||||
{ | { | ||||
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_FLUSH; | req->vbr_hdr.type = vtblk_gtoh32(sc, VIRTIO_BLK_T_FLUSH); | ||||
req->vbr_hdr.ioprio = 1; | req->vbr_hdr.ioprio = vtblk_gtoh32(sc, 1); | ||||
req->vbr_hdr.sector = 0; | req->vbr_hdr.sector = 0; | ||||
req->vbr_bp = &buf; | req->vbr_bp = &buf; | ||||
g_reset_bio(&buf); | g_reset_bio(&buf); | ||||
buf.bio_cmd = BIO_FLUSH; | buf.bio_cmd = BIO_FLUSH; | ||||
return (vtblk_poll_request(sc, req)); | return (vtblk_poll_request(sc, req)); | ||||
Show All 20 Lines | |||||
} | } | ||||
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_WCE_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->wce; | 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_FLUSH); | ||||
return (wc); | return (wc); | ||||
} | } | ||||
static int | static int | ||||
vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS) | vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct vtblk_softc *sc; | struct vtblk_softc *sc; | ||||
int wc, error; | int wc, error; | ||||
sc = oidp->oid_arg1; | sc = oidp->oid_arg1; | ||||
wc = sc->vtblk_write_cache; | wc = sc->vtblk_write_cache; | ||||
error = sysctl_handle_int(oidp, &wc, 0, req); | error = sysctl_handle_int(oidp, &wc, 0, req); | ||||
if (error || req->newptr == NULL) | if (error || req->newptr == NULL) | ||||
return (error); | return (error); | ||||
if ((sc->vtblk_flags & VTBLK_FLAG_WC_CONFIG) == 0) | if ((sc->vtblk_flags & VTBLK_FLAG_WCE_CONFIG) == 0) | ||||
return (EPERM); | return (EPERM); | ||||
if (wc < 0 || wc >= VTBLK_CACHE_MAX) | if (wc < 0 || wc >= VTBLK_CACHE_MAX) | ||||
return (EINVAL); | return (EINVAL); | ||||
VTBLK_LOCK(sc); | VTBLK_LOCK(sc); | ||||
sc->vtblk_write_cache = wc; | sc->vtblk_write_cache = wc; | ||||
vtblk_set_write_cache(sc, sc->vtblk_write_cache); | vtblk_set_write_cache(sc, sc->vtblk_write_cache); | ||||
VTBLK_UNLOCK(sc); | VTBLK_UNLOCK(sc); | ||||
Show All 34 Lines |
Was the deleted code block a no-op ? (guessing there won't be DELETE bio's if the DISKFLAG_CANDELETE wasn't set)