On Sep 28 11:35, Dmitry Fomichev wrote: > The emulation code has been changed to advertise NVM Command Set when > "zoned" device property is not set (default) and Zoned Namespace > Command Set otherwise. > > Handlers for three new NVMe commands introduced in Zoned Namespace > Command Set specification are added, namely for Zone Management > Receive, Zone Management Send and Zone Append. > > Device initialization code has been extended to create a proper > configuration for zoned operation using device properties. > > Read/Write command handler is modified to only allow writes at the > write pointer if the namespace is zoned. For Zone Append command, > writes implicitly happen at the write pointer and the starting write > pointer value is returned as the result of the command. Write Zeroes > handler is modified to add zoned checks that are identical to those > done as a part of Write flow. > > The code to support for Zone Descriptor Extensions is not included in > this commit and ZDES 0 is always reported. A later commit in this > series will add ZDE support. > > This commit doesn't yet include checks for active and open zone > limits. It is assumed that there are no limits on either active or > open zones. > > Signed-off-by: Niklas Cassel > Signed-off-by: Hans Holmberg > Signed-off-by: Ajay Joshi > Signed-off-by: Chaitanya Kulkarni > Signed-off-by: Matias Bjorling > Signed-off-by: Aravind Ramesh > Signed-off-by: Shin'ichiro Kawasaki > Signed-off-by: Adam Manzanares > Signed-off-by: Dmitry Fomichev > --- > block/nvme.c | 2 +- > hw/block/nvme-ns.c | 185 ++++++++- > hw/block/nvme-ns.h | 6 +- > hw/block/nvme.c | 872 +++++++++++++++++++++++++++++++++++++++++-- > include/block/nvme.h | 6 +- > 5 files changed, 1033 insertions(+), 38 deletions(-) > > diff --git a/block/nvme.c b/block/nvme.c > index 05485fdd11..7a513c9a17 100644 > --- a/block/nvme.c > +++ b/block/nvme.c > +static int nvme_calc_zone_geometry(NvmeNamespace *ns, Error **errp) > +{ > + uint64_t zone_size, zone_cap; > + uint32_t nz, lbasz = ns->blkconf.logical_block_size; > + > + if (ns->params.zone_size_mb) { > + zone_size = ns->params.zone_size_mb; > + } else { > + zone_size = NVME_DEFAULT_ZONE_SIZE; > + } > + if (ns->params.zone_capacity_mb) { > + zone_cap = ns->params.zone_capacity_mb; > + } else { > + zone_cap = zone_size; > + } I think a check that zone_capacity_mb is less than or equal to zone_size_mb is missing earlier? > +static int nvme_zoned_init_ns(NvmeCtrl *n, NvmeNamespace *ns, int lba_index, > + Error **errp) > +{ > + NvmeIdNsZoned *id_ns_z; > + > + if (n->params.fill_pattern == 0) { > + ns->id_ns.dlfeat |= 0x01; > + } else if (n->params.fill_pattern == 0xff) { > + ns->id_ns.dlfeat |= 0x02; > + } > + > + if (nvme_calc_zone_geometry(ns, errp) != 0) { > + return -1; > + } > + > + nvme_init_zone_meta(ns); > + > + id_ns_z = g_malloc0(sizeof(NvmeIdNsZoned)); > + > + /* MAR/MOR are zeroes-based, 0xffffffff means no limit */ > + id_ns_z->mar = 0xffffffff; > + id_ns_z->mor = 0xffffffff; > + id_ns_z->zoc = 0; > + id_ns_z->ozcs = ns->params.cross_zone_read ? 0x01 : 0x00; > + > + id_ns_z->lbafe[lba_index].zsze = cpu_to_le64(ns->zone_size); > + id_ns_z->lbafe[lba_index].zdes = 0; /* FIXME make helper */ > + > + ns->csi = NVME_CSI_ZONED; > + ns->id_ns.ncap = cpu_to_le64(ns->zone_capacity * ns->num_zones); > + ns->id_ns.nuse = ns->id_ns.ncap; > + ns->id_ns.nsze = ns->id_ns.ncap; > + NSZE should be in terms of ZSZE. We *can* report NCAP < NSZE if zcap != zsze, but that requires bit 1 set in NSFEAT and proper reporting of NUSE. > @@ -133,6 +304,14 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp) > static Property nvme_ns_props[] = { > DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf), > DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), > + > + DEFINE_PROP_BOOL("zoned", NvmeNamespace, params.zoned, false), > + DEFINE_PROP_UINT64("zone_size", NvmeNamespace, params.zone_size_mb, > + NVME_DEFAULT_ZONE_SIZE), > + DEFINE_PROP_UINT64("zone_capacity", NvmeNamespace, > + params.zone_capacity_mb, 0), There is a nice DEFINE_PROP_SIZE that handles sizes in a nice way (i.e. 1G, 1M).