On Sat, Oct 15, 2022 at 11:41:27PM -0400, Dmitry Fomichev wrote: > This patch adds support for Zoned Block Devices (ZBDs) to the kernel > virtio-blk driver. > > The patch accompanies the virtio-blk ZBD support draft that is now > being proposed for standardization. The latest version of the draft is > linked at > > https://github.com/oasis-tcs/virtio-spec/issues/143 . > > The QEMU zoned device code that implements these protocol extensions > has been developed by Sam Li and it is currently in review at the QEMU > mailing list. > > A number of virtblk request structure changes has been introduced to > accommodate the functionality that is specific to zoned block devices > and, most importantly, make room for carrying the Zoned Append sector > value from the device back to the driver along with the request status. > > The zone-specific code in the patch is heavily influenced by NVMe ZNS > code in drivers/nvme/host/zns.c, but it is simpler because the proposed > virtio ZBD draft only covers the zoned device features that are > relevant to the zoned functionality provided by Linux block layer. > > Co-developed-by: Stefan Hajnoczi <stefanha@xxxxxxxxx> > Signed-off-by: Stefan Hajnoczi <stefanha@xxxxxxxxx> > Signed-off-by: Dmitry Fomichev <dmitry.fomichev@xxxxxxx> > --- > drivers/block/virtio_blk.c | 377 ++++++++++++++++++++++++++++++-- > include/uapi/linux/virtio_blk.h | 105 +++++++++ > 2 files changed, 464 insertions(+), 18 deletions(-) > > diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c > index 3efe3da5f8c2..c9ad590816f8 100644 > --- a/drivers/block/virtio_blk.c > +++ b/drivers/block/virtio_blk.c > @@ -80,22 +80,51 @@ struct virtio_blk { > int num_vqs; > int io_queues[HCTX_MAX_TYPES]; > struct virtio_blk_vq *vqs; > + > + /* For zoned device */ > + unsigned int zone_sectors; > }; > > struct virtblk_req { > + /* Out header */ > struct virtio_blk_outhdr out_hdr; > - u8 status; > + > + /* In header */ > + union { > + u8 status; > + > + /* > + * The zone append command has an extended in header. > + * The status field in zone_append_in_hdr must have > + * the same offset in virtblk_req as the non-zoned > + * status field above. > + */ > + struct { > + u8 status; > + u8 reserved[7]; > + u64 append_sector; > + } zone_append_in_hdr; > + }; This layout is not finalized yet. In the last revision of the spec patch I suggested making the status byte the last byte so that devices that don't know about zone append can still complete the request with status=VIRTIO_BLK_S_UNSUPP at the correct offset. > + > + size_t in_hdr_len; > + > struct sg_table sg_table; > struct scatterlist sg[]; > }; > > -static inline blk_status_t virtblk_result(struct virtblk_req *vbr) > +static inline blk_status_t virtblk_result(u8 status) > { > - switch (vbr->status) { > + switch (status) { > case VIRTIO_BLK_S_OK: > return BLK_STS_OK; > case VIRTIO_BLK_S_UNSUPP: > return BLK_STS_NOTSUPP; > + case VIRTIO_BLK_S_ZONE_OPEN_RESOURCE: > + return BLK_STS_ZONE_OPEN_RESOURCE; > + case VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE: > + return BLK_STS_ZONE_ACTIVE_RESOURCE; > + case VIRTIO_BLK_S_IOERR: > + case VIRTIO_BLK_S_ZONE_UNALIGNED_WP: > default: > return BLK_STS_IOERR; > } > @@ -111,11 +140,11 @@ static inline struct virtio_blk_vq *get_virtio_blk_vq(struct blk_mq_hw_ctx *hctx > > static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr) > { > - struct scatterlist hdr, status, *sgs[3]; > + struct scatterlist out_hdr, in_hdr, *sgs[3]; > unsigned int num_out = 0, num_in = 0; > > - sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr)); > - sgs[num_out++] = &hdr; > + sg_init_one(&out_hdr, &vbr->out_hdr, sizeof(vbr->out_hdr)); > + sgs[num_out++] = &out_hdr; > > if (vbr->sg_table.nents) { > if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT)) > @@ -124,8 +153,8 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr) > sgs[num_out + num_in++] = vbr->sg_table.sgl; > } > > - sg_init_one(&status, &vbr->status, sizeof(vbr->status)); > - sgs[num_out + num_in++] = &status; > + sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len); > + sgs[num_out + num_in++] = &in_hdr; > > return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); > } > @@ -214,21 +243,22 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, > struct request *req, > struct virtblk_req *vbr) > { > + size_t in_hdr_len = sizeof(vbr->status); > bool unmap = false; > u32 type; > + u64 sector = 0; > > - vbr->out_hdr.sector = 0; > + /* Set fields for all request types */ > + vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req)); > > switch (req_op(req)) { > case REQ_OP_READ: > type = VIRTIO_BLK_T_IN; > - vbr->out_hdr.sector = cpu_to_virtio64(vdev, > - blk_rq_pos(req)); > + sector = blk_rq_pos(req); > break; > case REQ_OP_WRITE: > type = VIRTIO_BLK_T_OUT; > - vbr->out_hdr.sector = cpu_to_virtio64(vdev, > - blk_rq_pos(req)); > + sector = blk_rq_pos(req); > break; > case REQ_OP_FLUSH: > type = VIRTIO_BLK_T_FLUSH; > @@ -243,16 +273,42 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, > case REQ_OP_SECURE_ERASE: > type = VIRTIO_BLK_T_SECURE_ERASE; > break; > - case REQ_OP_DRV_IN: > - type = VIRTIO_BLK_T_GET_ID; > + case REQ_OP_ZONE_OPEN: > + type = VIRTIO_BLK_T_ZONE_OPEN; > + sector = blk_rq_pos(req); > break; > + case REQ_OP_ZONE_CLOSE: > + type = VIRTIO_BLK_T_ZONE_CLOSE; > + sector = blk_rq_pos(req); > + break; > + case REQ_OP_ZONE_FINISH: > + type = VIRTIO_BLK_T_ZONE_FINISH; > + sector = blk_rq_pos(req); > + break; > + case REQ_OP_ZONE_APPEND: > + type = VIRTIO_BLK_T_ZONE_APPEND; > + sector = blk_rq_pos(req); > + in_hdr_len = sizeof(vbr->zone_append_in_hdr); > + break; > + case REQ_OP_ZONE_RESET: > + type = VIRTIO_BLK_T_ZONE_RESET; > + sector = blk_rq_pos(req); > + break; > + case REQ_OP_ZONE_RESET_ALL: > + type = VIRTIO_BLK_T_ZONE_RESET_ALL; > + break; > + case REQ_OP_DRV_IN: > + /* Out header already filled in, nothing to do */ > + return 0; > default: > WARN_ON_ONCE(1); > return BLK_STS_IOERR; > } > > + /* Set fields for non-REQ_OP_DRV_IN request types */ > + vbr->in_hdr_len = in_hdr_len; > vbr->out_hdr.type = cpu_to_virtio32(vdev, type); > - vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req)); > + vbr->out_hdr.sector = cpu_to_virtio64(vdev, sector); > > if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES || > type == VIRTIO_BLK_T_SECURE_ERASE) { > @@ -266,10 +322,15 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, > static inline void virtblk_request_done(struct request *req) > { > struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); > + int status = virtblk_result(vbr->status); > > virtblk_unmap_data(req, vbr); > virtblk_cleanup_cmd(req); > - blk_mq_end_request(req, virtblk_result(vbr)); > + > + if (req_op(req) == REQ_OP_ZONE_APPEND) > + req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector); Not sure if it's correct to set __sector upon error, maybe if (... && status == BLK_STS_OK)? A quick look at the nvme driver shows no check was performed there either. > + > + blk_mq_end_request(req, status); > } > > static void virtblk_done(struct virtqueue *vq) > @@ -455,6 +516,266 @@ static void virtio_queue_rqs(struct request **rqlist) > *rqlist = requeue_list; > } > > +#ifdef CONFIG_BLK_DEV_ZONED > +static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk, > + unsigned int nr_zones, > + unsigned int zone_sectors, > + size_t *buflen) > +{ > + struct request_queue *q = vblk->disk->queue; > + size_t bufsize; > + void *buf; > + > + nr_zones = min_t(unsigned int, nr_zones, > + get_capacity(vblk->disk) >> ilog2(zone_sectors)); > + > + bufsize = sizeof(struct virtio_blk_zone_report) + > + nr_zones * sizeof(struct virtio_blk_zone_descriptor); > + bufsize = min_t(size_t, bufsize, > + queue_max_hw_sectors(q) << SECTOR_SHIFT); > + bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT); > + > + while (bufsize >= sizeof(struct virtio_blk_zone_report)) { > + buf = __vmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY); > + if (buf) { > + *buflen = bufsize; > + return buf; > + } > + bufsize >>= 1; > + } > + > + return NULL; > +} > + > +static int virtblk_submit_zone_report(struct virtio_blk *vblk, > + char *report_buf, size_t report_len, > + sector_t sector) > +{ > + struct request_queue *q = vblk->disk->queue; > + struct request *req; > + struct virtblk_req *vbr; > + int err; > + > + req = blk_mq_alloc_request(q, REQ_OP_DRV_IN, 0); > + if (IS_ERR(req)) > + return PTR_ERR(req); > + > + vbr = blk_mq_rq_to_pdu(req); > + vbr->in_hdr_len = sizeof(vbr->status); > + vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT); > + vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector); > + > + err = blk_rq_map_kern(q, req, report_buf, report_len, GFP_KERNEL); > + if (err) > + goto out; > + > + blk_execute_rq(req, false); > + err = blk_status_to_errno(virtblk_result(vbr->status)); > +out: > + blk_mq_free_request(req); > + return err; > +} > + > +static int virtblk_parse_zone(struct virtio_blk *vblk, > + struct virtio_blk_zone_descriptor *entry, > + unsigned int idx, unsigned int zone_sectors, > + report_zones_cb cb, void *data) > +{ > + struct blk_zone zone = { }; > + > + if (entry->z_type != VIRTIO_BLK_ZT_SWR && > + entry->z_type != VIRTIO_BLK_ZT_SWP && > + entry->z_type != VIRTIO_BLK_ZT_CONV) { > + dev_err(&vblk->vdev->dev, "invalid zone type %#x\n", > + entry->z_type); > + return -EINVAL; > + } > + > + zone.type = entry->z_type; > + zone.cond = entry->z_state; > + zone.len = zone_sectors; > + zone.capacity = le64_to_cpu(entry->z_cap); > + zone.start = le64_to_cpu(entry->z_start); > + if (zone.cond == BLK_ZONE_COND_FULL) > + zone.wp = zone.start + zone.len; > + else > + zone.wp = le64_to_cpu(entry->z_wp); > + > + return cb(&zone, idx, data); > +} > + > +static int virtblk_report_zones(struct gendisk *disk, sector_t sector, > + unsigned int nr_zones, report_zones_cb cb, > + void *data) > +{ > + struct virtio_blk *vblk = disk->private_data; > + struct virtio_blk_zone_report *report; > + unsigned int zone_sectors = vblk->zone_sectors; > + unsigned int nz, i; > + int ret, zone_idx = 0; > + size_t buflen; > + > + if (WARN_ON_ONCE(!vblk->zone_sectors)) > + return -EOPNOTSUPP; > + > + report = virtblk_alloc_report_buffer(vblk, nr_zones, > + zone_sectors, &buflen); > + if (!report) > + return -ENOMEM; > + > + while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) { > + memset(report, 0, buflen); > + > + ret = virtblk_submit_zone_report(vblk, (char *)report, > + buflen, sector); > + if (ret) { > + if (ret > 0) > + ret = -EIO; > + goto out_free; > + } > + nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones); > + if (!nz) > + break; > + > + for (i = 0; i < nz && zone_idx < nr_zones; i++) { > + ret = virtblk_parse_zone(vblk, &report->zones[i], > + zone_idx, zone_sectors, cb, data); > + if (ret) > + goto out_free; > + sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors; > + zone_idx++; > + } > + } > + > + if (zone_idx > 0) > + ret = zone_idx; > + else > + ret = -EINVAL; > +out_free: > + kvfree(report); > + return ret; > +} > + > +static void virtblk_revalidate_zones(struct virtio_blk *vblk) > +{ > + u8 model; > + > + if (!vblk->zone_sectors) > + return; > + > + virtio_cread(vblk->vdev, struct virtio_blk_config, > + zoned.model, &model); > + if (!blk_revalidate_disk_zones(vblk->disk, NULL)) > + set_capacity_and_notify(vblk->disk, 0); > +} > + > +static int virtblk_probe_zoned_device(struct virtio_device *vdev, > + struct virtio_blk *vblk, > + struct request_queue *q) > +{ > + u32 v; > + u8 model; > + int ret; > + > + virtio_cread(vdev, struct virtio_blk_config, > + zoned.model, &model); > + > + switch (model) { > + case VIRTIO_BLK_Z_NONE: > + return 0; > + case VIRTIO_BLK_Z_HM: > + break; > + case VIRTIO_BLK_Z_HA: > + /* > + * Present the host-aware device as a regular drive. > + * TODO It is possible to add an option to make it appear > + * in the system as a zoned drive. > + */ > + return 0; > + default: > + dev_err(&vdev->dev, "unsupported zone model %d\n", model); > + return -EINVAL; > + } > + > + dev_dbg(&vdev->dev, "probing host-managed zoned device\n"); > + > + disk_set_zoned(vblk->disk, BLK_ZONED_HM); > + blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q); > + > + virtio_cread(vdev, struct virtio_blk_config, > + zoned.max_open_zones, &v); > + disk_set_max_open_zones(vblk->disk, le32_to_cpu(v)); > + > + dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v)); > + > + virtio_cread(vdev, struct virtio_blk_config, > + zoned.max_active_zones, &v); > + disk_set_max_active_zones(vblk->disk, le32_to_cpu(v)); > + dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v)); > + > + virtio_cread(vdev, struct virtio_blk_config, > + zoned.write_granularity, &v); > + if (!v) { > + dev_warn(&vdev->dev, "zero write granularity reported\n"); > + return -ENODEV; > + } > + blk_queue_physical_block_size(q, le32_to_cpu(v)); > + blk_queue_io_min(q, le32_to_cpu(v)); > + > + dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v)); > + > + /* > + * virtio ZBD specification doesn't require zones to be a power of > + * two sectors in size, but the code in this driver expects that. > + */ > + virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v); > + vblk->zone_sectors = le32_to_cpu(v); > + if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) { > + dev_err(&vdev->dev, > + "zoned device with non power of two zone size %u\n", > + vblk->zone_sectors); > + return -ENODEV; > + } > + dev_dbg(&vdev->dev, "zone sectors = %u\n", vblk->zone_sectors); > + > + if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) { > + dev_warn(&vblk->vdev->dev, > + "ignoring negotiated F_DISCARD for zoned device\n"); > + blk_queue_max_discard_sectors(q, 0); > + } > + > + ret = blk_revalidate_disk_zones(vblk->disk, NULL); > + if (!ret) { > + virtio_cread(vdev, struct virtio_blk_config, > + zoned.max_append_sectors, &v); > + if (!v) { > + dev_warn(&vdev->dev, "zero max_append_sectors reported\n"); > + return -ENODEV; > + } > + blk_queue_max_zone_append_sectors(q, le32_to_cpu(v)); > + dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v)); > + } > + > + return ret; > +} > + > +#else > + > +/* > + * Zoned block device support is not configured in this kernel. > + * We only need to define a few symbols to avoid compilation errors. > + */ > +#define virtblk_report_zones NULL > +static inline void virtblk_revalidate_zones(struct virtio_blk *vblk) > +{ > +} > +static inline int virtblk_probe_zoned_device(struct virtio_device *vdev, > + struct virtio_blk *vblk, struct request_queue *q) > +{ > + return -EOPNOTSUPP; > +} > +#endif /* CONFIG_BLK_DEV_ZONED */ > + > /* return id (s/n) string for *disk to *id_str > */ > static int virtblk_get_id(struct gendisk *disk, char *id_str) > @@ -462,18 +783,24 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) > struct virtio_blk *vblk = disk->private_data; > struct request_queue *q = vblk->disk->queue; > struct request *req; > + struct virtblk_req *vbr; > int err; > > req = blk_mq_alloc_request(q, REQ_OP_DRV_IN, 0); > if (IS_ERR(req)) > return PTR_ERR(req); > > + vbr = blk_mq_rq_to_pdu(req); > + vbr->in_hdr_len = sizeof(vbr->status); > + vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID); > + vbr->out_hdr.sector = 0; > + > err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL); > if (err) > goto out; > > blk_execute_rq(req, false); > - err = blk_status_to_errno(virtblk_result(blk_mq_rq_to_pdu(req))); > + err = blk_status_to_errno(virtblk_result(vbr->status)); > out: > blk_mq_free_request(req); > return err; > @@ -524,6 +851,7 @@ static const struct block_device_operations virtblk_fops = { > .owner = THIS_MODULE, > .getgeo = virtblk_getgeo, > .free_disk = virtblk_free_disk, > + .report_zones = virtblk_report_zones, > }; > > static int index_to_minor(int index) > @@ -594,6 +922,7 @@ static void virtblk_config_changed_work(struct work_struct *work) > struct virtio_blk *vblk = > container_of(work, struct virtio_blk, config_work); > > + virtblk_revalidate_zones(vblk); > virtblk_update_capacity(vblk, true); > } > > @@ -1150,6 +1479,15 @@ static int virtblk_probe(struct virtio_device *vdev) > virtblk_update_capacity(vblk, false); > virtio_device_ready(vdev); > > + if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) { > + err = virtblk_probe_zoned_device(vdev, vblk, q); > + if (err) > + goto out_cleanup_disk; > + } > + > + dev_info(&vdev->dev, "blk config size: %zu\n", > + sizeof(struct virtio_blk_config)); > + > err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); > if (err) > goto out_cleanup_disk; > @@ -1251,6 +1589,9 @@ static unsigned int features[] = { > VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, > VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, > VIRTIO_BLK_F_SECURE_ERASE, > +#ifdef CONFIG_BLK_DEV_ZONED > + VIRTIO_BLK_F_ZONED, > +#endif /* CONFIG_BLK_DEV_ZONED */ > }; > > static struct virtio_driver virtio_blk = { > diff --git a/include/uapi/linux/virtio_blk.h b/include/uapi/linux/virtio_blk.h > index 58e70b24b504..3744e4da1b2a 100644 > --- a/include/uapi/linux/virtio_blk.h > +++ b/include/uapi/linux/virtio_blk.h > @@ -41,6 +41,7 @@ > #define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */ > #define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */ > #define VIRTIO_BLK_F_SECURE_ERASE 16 /* Secure Erase is supported */ > +#define VIRTIO_BLK_F_ZONED 17 /* Zoned block device */ > > /* Legacy feature bits */ > #ifndef VIRTIO_BLK_NO_LEGACY > @@ -137,6 +138,16 @@ struct virtio_blk_config { > /* Secure erase commands must be aligned to this number of sectors. */ > __virtio32 secure_erase_sector_alignment; > > + /* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */ > + struct virtio_blk_zoned_characteristics { > + __virtio32 zone_sectors; > + __virtio32 max_open_zones; > + __virtio32 max_active_zones; > + __virtio32 max_append_sectors; > + __virtio32 write_granularity; > + __u8 model; > + __u8 unused2[3]; > + } zoned; > } __attribute__((packed)); > > /* > @@ -174,6 +185,27 @@ struct virtio_blk_config { > /* Secure erase command */ > #define VIRTIO_BLK_T_SECURE_ERASE 14 > > +/* Zone append command */ > +#define VIRTIO_BLK_T_ZONE_APPEND 15 > + > +/* Report zones command */ > +#define VIRTIO_BLK_T_ZONE_REPORT 16 > + > +/* Open zone command */ > +#define VIRTIO_BLK_T_ZONE_OPEN 18 > + > +/* Close zone command */ > +#define VIRTIO_BLK_T_ZONE_CLOSE 20 > + > +/* Finish zone command */ > +#define VIRTIO_BLK_T_ZONE_FINISH 22 > + > +/* Reset zone command */ > +#define VIRTIO_BLK_T_ZONE_RESET 24 > + > +/* Reset All zones command */ > +#define VIRTIO_BLK_T_ZONE_RESET_ALL 26 > + > #ifndef VIRTIO_BLK_NO_LEGACY > /* Barrier before this op. */ > #define VIRTIO_BLK_T_BARRIER 0x80000000 > @@ -193,6 +225,72 @@ struct virtio_blk_outhdr { > __virtio64 sector; > }; > > +/* > + * Supported zoned device models. > + */ > + > +/* Regular block device */ > +#define VIRTIO_BLK_Z_NONE 0 > +/* Host-managed zoned device */ > +#define VIRTIO_BLK_Z_HM 1 > +/* Host-aware zoned device */ > +#define VIRTIO_BLK_Z_HA 2 > + > +/* > + * Zone descriptor. A part of VIRTIO_BLK_T_ZONE_REPORT command reply. > + */ > +struct virtio_blk_zone_descriptor { > + /* Zone capacity */ > + __virtio64 z_cap; > + /* The starting sector of the zone */ > + __virtio64 z_start; > + /* Zone write pointer position in sectors */ > + __virtio64 z_wp; > + /* Zone type */ > + __u8 z_type; > + /* Zone state */ > + __u8 z_state; > + __u8 reserved[38]; > +}; > + > +struct virtio_blk_zone_report { > + __virtio64 nr_zones; > + __u8 reserved[56]; > + struct virtio_blk_zone_descriptor zones[]; > +}; > + > +/* > + * Supported zone types. > + */ > + > +/* Conventional zone */ > +#define VIRTIO_BLK_ZT_CONV 1 > +/* Sequential Write Required zone */ > +#define VIRTIO_BLK_ZT_SWR 2 > +/* Sequential Write Preferred zone */ > +#define VIRTIO_BLK_ZT_SWP 3 > + > +/* > + * Zone states that are available for zones of all types. > + */ > + > +/* Not a write pointer (conventional zones only) */ > +#define VIRTIO_BLK_ZS_NOT_WP 0 > +/* Empty */ > +#define VIRTIO_BLK_ZS_EMPTY 1 > +/* Implicitly Open */ > +#define VIRTIO_BLK_ZS_IOPEN 2 > +/* Explicitly Open */ > +#define VIRTIO_BLK_ZS_EOPEN 3 > +/* Closed */ > +#define VIRTIO_BLK_ZS_CLOSED 4 > +/* Read-Only */ > +#define VIRTIO_BLK_ZS_RDONLY 13 > +/* Full */ > +#define VIRTIO_BLK_ZS_FULL 14 > +/* Offline */ > +#define VIRTIO_BLK_ZS_OFFLINE 15 > + > /* Unmap this range (only valid for write zeroes command) */ > #define VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP 0x00000001 > > @@ -219,4 +317,11 @@ struct virtio_scsi_inhdr { > #define VIRTIO_BLK_S_OK 0 > #define VIRTIO_BLK_S_IOERR 1 > #define VIRTIO_BLK_S_UNSUPP 2 > + > +/* Error codes that are specific to zoned block devices */ > +#define VIRTIO_BLK_S_ZONE_INVALID_CMD 3 > +#define VIRTIO_BLK_S_ZONE_UNALIGNED_WP 4 > +#define VIRTIO_BLK_S_ZONE_OPEN_RESOURCE 5 > +#define VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE 6 > + > #endif /* _LINUX_VIRTIO_BLK_H */ > -- > 2.34.1 > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: virtio-dev-unsubscribe@xxxxxxxxxxxxxxxxxxxx > For additional commands, e-mail: virtio-dev-help@xxxxxxxxxxxxxxxxxxxx >
Attachment:
signature.asc
Description: PGP signature