diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index fa003031e7..121a95b2e3 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -6705,6 +6705,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; @@ -7688,6 +7705,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 6df2e8e7c5..28aacb8db5 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 67ed562e00..7d01080fc1 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)