Add support for the namespace atomic paramters: NAWUN and NAWUN. Namespace Atomic Compare and Write Unit (NACWU) is not currently supported.
Writes that adhere to the NACWU and NAWUPF parameters are guaranteed to be atomic. New NVMe QEMU Paramters (See NVMe Specification for details): atomic.nawun=UINT16 (default: 0) atomic.nawupf=UINT16 (default: 0) atomic.nsfeat (default off) - Set Namespace Supported Atomic Boundary & Power (NSABP) bit in Namespace Features (NSFEAT) in the Identify Namespace Data Structure See the NVMe Specification for more information. Signed-off-by: Alan Adamson <alan.adam...@oracle.com> --- hw/nvme/ctrl.c | 23 +++++++++++++++++++++++ hw/nvme/ns.c | 38 ++++++++++++++++++++++++++++++++++++++ hw/nvme/nvme.h | 6 ++++++ 3 files changed, 67 insertions(+) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index fd935507bc02..a2dd50f3af43 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -6703,6 +6703,23 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) } else { atomic->atomic_writes = 1; } + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { + ns = nvme_ns(n, i); + if (ns && ns->atomic.atomic_writes) { + if (n->dn) { + ns->atomic.atomic_max_write_size = + le16_to_cpu(ns->id_ns.nawupf) + 1; + } else { + ns->atomic.atomic_max_write_size = + le16_to_cpu(ns->id_ns.nawun) + 1; + } + if (ns->atomic.atomic_max_write_size == 1) { + ns->atomic.atomic_writes = 0; + } else { + ns->atomic.atomic_writes = 1; + } + } + } break; default: return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR; @@ -7477,6 +7494,12 @@ static int nvme_atomic_write_check(NvmeCtrl *n, NvmeCmd *cmd, static NvmeAtomic *nvme_get_atomic(NvmeCtrl *n, NvmeCmd *cmd) { + NvmeNamespace *ns = nvme_ns(n, cmd->nsid); + + if (ns && ns->atomic.atomic_writes) { + return &ns->atomic; + } + if (n->atomic.atomic_writes) { return &n->atomic; } diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index 6df2e8e7c5ac..28aacb8db59a 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -724,11 +724,46 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp) BusState *s = qdev_get_parent_bus(dev); NvmeCtrl *n = NVME(s->parent); NvmeSubsystem *subsys = n->subsys; + NvmeIdCtrl *id = &n->id_ctrl; + NvmeIdNs *id_ns = &ns->id_ns; uint32_t nsid = ns->params.nsid; int i; assert(subsys); + /* Set atomic write parameters */ + if (ns->params.atomic_nsfeat) { + id_ns->nsfeat |= NVME_ID_NS_NSFEAT_NSABPNS; + id_ns->nawun = cpu_to_le16(ns->params.atomic_nawun); + if (!id->awupf || (id_ns->nawun && (id_ns->nawun < id->awun))) { + error_report("Invalid NAWUN: %x AWUN=%x", id_ns->nawun, id->awun); + } + id_ns->nawupf = cpu_to_le16(ns->params.atomic_nawupf); + if (!id->awupf || (id_ns->nawupf && (id_ns->nawupf < id->awupf))) { + error_report("Invalid NAWUPF: %x AWUPF=%x", + id_ns->nawupf, id->awupf); + } + if (id_ns->nawupf > id_ns->nawun) { + error_report("Invalid: NAWUN=%x NAWUPF=%x", + id_ns->nawun, id_ns->nawupf); + } + } + + if (id_ns->nawun || id_ns->nawupf) { + NvmeAtomic *atomic = &ns->atomic; + + if (n->dn) { + atomic->atomic_max_write_size = cpu_to_le16(id_ns->nawupf) + 1; + } else { + atomic->atomic_max_write_size = cpu_to_le16(id_ns->nawun) + 1; + } + if (atomic->atomic_max_write_size == 1) { + atomic->atomic_writes = 0; + } else { + atomic->atomic_writes = 1; + } + } + /* reparent to subsystem bus */ if (!qdev_set_parent_bus(dev, &subsys->bus.parent_bus, errp)) { return; @@ -804,6 +839,9 @@ static const Property nvme_ns_props[] = { DEFINE_PROP_BOOL("eui64-default", NvmeNamespace, params.eui64_default, false), DEFINE_PROP_STRING("fdp.ruhs", NvmeNamespace, params.fdp.ruhs), + DEFINE_PROP_UINT16("atomic.nawun", NvmeNamespace, params.atomic_nawun, 0), + DEFINE_PROP_UINT16("atomic.nawupf", NvmeNamespace, params.atomic_nawupf, 0), + DEFINE_PROP_BOOL("atomic.nsfeat", NvmeNamespace, params.atomic_nsfeat, 0), }; static void nvme_ns_class_init(ObjectClass *oc, const void *data) diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index b5c9378ea4e5..4ac9bd7e6a25 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -218,6 +218,9 @@ typedef struct NvmeNamespaceParams { struct { char *ruhs; } fdp; + uint16_t atomic_nawun; + uint16_t atomic_nawupf; + bool atomic_nsfeat; } NvmeNamespaceParams; typedef struct NvmeAtomic { @@ -280,6 +283,9 @@ typedef struct NvmeNamespace { /* reclaim unit handle identifiers indexed by placement handle */ uint16_t *phs; } fdp; + uint16_t atomic_nawun; + uint16_t atomic_nawupf; + NvmeAtomic atomic; } NvmeNamespace; static inline uint32_t nvme_nsid(NvmeNamespace *ns) -- 2.43.5