[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH RFC v2 13/16] hw/nvme: add experimental abstract object x-nvme-ns
From: |
Klaus Jensen |
Subject: |
[PATCH RFC v2 13/16] hw/nvme: add experimental abstract object x-nvme-ns |
Date: |
Mon, 27 Sep 2021 07:17:56 +0200 |
From: Klaus Jensen <k.jensen@samsung.com>
Add the abstract NvmeNamespace object to base proper namespace types on.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
hw/nvme/ns.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++
hw/nvme/nvme.h | 22 +++++
hw/nvme/subsys.c | 31 +++++++
qapi/qom.json | 17 ++++
4 files changed, 286 insertions(+)
diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c
index 09556f0ec7c9..d75ff4f1cb74 100644
--- a/hw/nvme/ns.c
+++ b/hw/nvme/ns.c
@@ -13,9 +13,13 @@
*/
#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "qemu/ctype.h"
#include "qemu/units.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
+#include "qapi/qapi-builtin-visit.h"
+#include "qom/object_interfaces.h"
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
@@ -632,8 +636,220 @@ static const TypeInfo nvme_nsdev_info = {
.instance_init = nvme_nsdev_instance_init,
};
+bool nvme_ns_prop_writable(Object *obj, const char *name, Error **errp)
+{
+ NvmeNamespace *ns = NVME_NAMESPACE(obj);
+
+ if (ns->realized) {
+ error_setg(errp, "attempt to set immutable property '%s' on "
+ "active namespace", name);
+ return false;
+ }
+
+ return true;
+}
+
+static char *nvme_ns_get_nsid(Object *obj, Error **errp)
+{
+ NvmeNamespace *ns = NVME_NAMESPACE(obj);
+
+ return g_strdup_printf("%d\n", ns->nsid);
+}
+
+static void nvme_ns_set_nsid(Object *obj, const char *v, Error **errp)
+{
+ NvmeNamespace *ns = NVME_NAMESPACE(obj);
+ unsigned long nsid;
+
+ if (!nvme_ns_prop_writable(obj, "nsid", errp)) {
+ return;
+ }
+
+ if (!strcmp(v, "auto")) {
+ ns->nsid = 0;
+ return;
+ }
+
+ if (qemu_strtoul(v, NULL, 0, &nsid) < 0 || nsid > NVME_MAX_NAMESPACES) {
+ error_setg(errp, "invalid namespace identifier");
+ return;
+ }
+
+ ns->nsid = nsid;
+}
+
+static char *nvme_ns_get_uuid(Object *obj, Error **errp)
+{
+ NvmeNamespace *ns = NVME_NAMESPACE(obj);
+
+ char *str = g_malloc(UUID_FMT_LEN + 1);
+
+ qemu_uuid_unparse(&ns->uuid, str);
+
+ return str;
+}
+
+static void nvme_ns_set_uuid(Object *obj, const char *v, Error **errp)
+{
+ NvmeNamespace *ns = NVME_NAMESPACE(obj);
+
+ if (!nvme_ns_prop_writable(obj, "uuid", errp)) {
+ return;
+ }
+
+ if (!strcmp(v, "auto")) {
+ qemu_uuid_generate(&ns->uuid);
+ } else if (qemu_uuid_parse(v, &ns->uuid) < 0) {
+ error_setg(errp, "invalid uuid");
+ }
+}
+
+static char *nvme_ns_get_eui64(Object *obj, Error **errp)
+{
+ NvmeNamespace *ns = NVME_NAMESPACE(obj);
+
+ const int len = 2 * 8 + 7 + 1; /* "aa:bb:cc:dd:ee:ff:gg:hh\0" */
+ char *str = g_malloc(len);
+
+ snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ ns->eui64.a[0], ns->eui64.a[1], ns->eui64.a[2], ns->eui64.a[3],
+ ns->eui64.a[4], ns->eui64.a[5], ns->eui64.a[6], ns->eui64.a[7]);
+
+ return str;
+}
+
+static void nvme_ns_set_eui64(Object *obj, const char *v, Error **errp)
+{
+ NvmeNamespace *ns = NVME_NAMESPACE(obj);
+
+ int i, pos;
+
+ if (!nvme_ns_prop_writable(obj, "eui64", errp)) {
+ return;
+ }
+
+ if (!strcmp(v, "auto")) {
+ ns->eui64.a[0] = 0x52;
+ ns->eui64.a[1] = 0x54;
+ ns->eui64.a[2] = 0x00;
+
+ for (i = 0; i < 5; ++i) {
+ ns->eui64.a[3 + i] = g_random_int();
+ }
+
+ return;
+ }
+
+ for (i = 0, pos = 0; i < 8; i++, pos += 3) {
+ long octet;
+
+ if (!(qemu_isxdigit(v[pos]) && qemu_isxdigit(v[pos + 1]))) {
+ goto invalid;
+ }
+
+ if (i == 7) {
+ if (v[pos + 2] != '\0') {
+ goto invalid;
+ }
+ } else {
+ if (!(v[pos + 2] == ':' || v[pos + 2] == '-')) {
+ goto invalid;
+ }
+ }
+
+ if (qemu_strtol(v + pos, NULL, 16, &octet) < 0 || octet > 0xff) {
+ goto invalid;
+ }
+
+ ns->eui64.a[i] = octet;
+ }
+
+ return;
+
+invalid:
+ error_setg(errp, "invalid ieee extended unique identifier");
+}
+
+static void nvme_ns_set_identifiers_if_unset(NvmeNamespace *ns)
+{
+ ns->nguid.eui = ns->eui64.v;
+}
+
+static void nvme_ns_complete(UserCreatable *uc, Error **errp)
+{
+ NvmeNamespace *ns = NVME_NAMESPACE(uc);
+ NvmeNamespaceClass *nc = NVME_NAMESPACE_GET_CLASS(ns);
+
+ nvme_ns_set_identifiers_if_unset(ns);
+
+ ns->flags |= NVME_NS_SHARED;
+
+ if (nc->check_params && nc->check_params(ns, errp)) {
+ return;
+ }
+
+ if (nvme_subsys_register_ns(ns->subsys, ns, errp)) {
+ return;
+ }
+
+ if (nc->configure && nc->configure(ns, errp)) {
+ return;
+ }
+
+ ns->realized = true;
+}
+
+static void nvme_ns_class_init(ObjectClass *oc, void *data)
+{
+ ObjectProperty *op;
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+
+ ucc->complete = nvme_ns_complete;
+
+ op = object_class_property_add_str(oc, "nsid", nvme_ns_get_nsid,
+ nvme_ns_set_nsid);
+ object_property_set_default_str(op, "auto");
+ object_class_property_set_description(oc, "nsid", "namespace identifier "
+ "(\"auto\": assigned by controller "
+ "or subsystem; default: \"auto\")");
+
+ object_class_property_add_link(oc, "subsys", TYPE_NVME_SUBSYSTEM,
+ offsetof(NvmeNamespace, subsys),
+ object_property_allow_set_link, 0);
+ object_class_property_set_description(oc, "subsys", "link to "
+ "x-nvme-subsystem object");
+
+ op = object_class_property_add_str(oc, "uuid", nvme_ns_get_uuid,
+ nvme_ns_set_uuid);
+ object_property_set_default_str(op, "auto");
+ object_class_property_set_description(oc, "uuid", "namespace uuid "
+ "(\"auto\" for random value; "
+ "default: \"auto\")");
+
+ op = object_class_property_add_str(oc, "eui64", nvme_ns_get_eui64,
+ nvme_ns_set_eui64);
+ object_property_set_default_str(op, "auto");
+ object_class_property_set_description(oc, "eui64", "IEEE Extended Unique "
+ "Identifier (\"auto\" for random "
+ "value; default: \"auto\")");
+}
+
+static const TypeInfo nvme_ns_info = {
+ .name = TYPE_NVME_NAMESPACE,
+ .parent = TYPE_OBJECT,
+ .abstract = true,
+ .class_size = sizeof(NvmeNamespaceClass),
+ .class_init = nvme_ns_class_init,
+ .instance_size = sizeof(NvmeNamespace),
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_USER_CREATABLE },
+ { },
+ },
+};
+
static void register_types(void)
{
+ type_register_static(&nvme_ns_info);
type_register_static(&nvme_nsdev_info);
}
diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h
index b67e5900a01d..627b28649892 100644
--- a/hw/nvme/nvme.h
+++ b/hw/nvme/nvme.h
@@ -19,6 +19,8 @@
#define HW_NVME_INTERNAL_H
#include "qemu/uuid.h"
+#include "qemu/notify.h"
+#include "qapi/qapi-builtin-visit.h"
#include "hw/pci/pci.h"
#include "hw/block/block.h"
@@ -45,6 +47,16 @@ typedef struct NvmeBus {
BusState parent_bus;
} NvmeBus;
+#define TYPE_NVME_NAMESPACE "x-nvme-ns"
+OBJECT_DECLARE_TYPE(NvmeNamespace, NvmeNamespaceClass, NVME_NAMESPACE)
+
+struct NvmeNamespaceClass {
+ ObjectClass parent_class;
+
+ int (*check_params)(NvmeNamespace *ns, Error **errp);
+ int (*configure)(NvmeNamespace *ns, Error **errp);
+};
+
#define TYPE_NVME_SUBSYSTEM "x-nvme-subsystem"
OBJECT_DECLARE_SIMPLE_TYPE(NvmeSubsystem, NVME_SUBSYSTEM)
@@ -75,6 +87,8 @@ typedef struct NvmeSubsystemDevice {
int nvme_subsys_register_ctrl(NvmeSubsystem *subsys, NvmeState *n,
Error **errp);
void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeState *n);
+int nvme_subsys_register_ns(NvmeSubsystem *subsys, NvmeNamespace *ns,
+ Error **errp);
static inline NvmeState *nvme_subsys_ctrl(NvmeSubsystem *subsys,
uint32_t cntlid)
@@ -190,6 +204,11 @@ enum NvmeNamespaceFlags {
};
typedef struct NvmeNamespace {
+ Object parent_obj;
+ bool realized;
+
+ NvmeSubsystem *subsys;
+
uint32_t nsid;
uint8_t csi;
QemuUUID uuid;
@@ -197,6 +216,7 @@ typedef struct NvmeNamespace {
uint64_t v;
uint8_t a[8];
} eui64;
+ NvmeNGUID nguid;
unsigned long flags;
@@ -212,6 +232,8 @@ typedef struct NvmeNamespace {
NvmeNamespaceZoned zoned;
} NvmeNamespace;
+bool nvme_ns_prop_writable(Object *obj, const char *name, Error **errp);
+
#define NVME_NAMESPACE_NVM(ns) (&(ns)->nvm)
#define NVME_NAMESPACE_ZONED(ns) (&(ns)->zoned)
diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c
index 2599b83c348e..e4dcd8fd20a5 100644
--- a/hw/nvme/subsys.c
+++ b/hw/nvme/subsys.c
@@ -47,6 +47,37 @@ void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys,
NvmeState *n)
n->cntlid = -1;
}
+int nvme_subsys_register_ns(NvmeSubsystem *subsys, NvmeNamespace *ns,
+ Error **errp)
+{
+ int i;
+
+ if (!ns->nsid) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
+ if (!subsys->namespaces[i]) {
+ ns->nsid = i;
+ break;
+ }
+ }
+
+ if (!ns->nsid) {
+ error_setg(errp, "no free namespace identifiers");
+ return -1;
+ }
+ } else if (ns->nsid > NVME_MAX_NAMESPACES) {
+ error_setg(errp, "invalid namespace identifier '%d'", ns->nsid);
+ return -1;
+ } else if (subsys->namespaces[ns->nsid]) {
+ error_setg(errp, "namespace identifier '%d' already allocated",
+ ns->nsid);
+ return -1;
+ }
+
+ subsys->namespaces[ns->nsid] = ns;
+
+ return 0;
+}
+
static void get_controllers(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
diff --git a/qapi/qom.json b/qapi/qom.json
index d4c211fc38b1..6d5cef6b92ad 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -662,6 +662,23 @@
'data': { '*subnqn': 'str',
'*uuid': 'str' } }
+##
+# @NvmeNamespaceProperties:
+#
+# Properties for x-nvme-ns objects.
+#
+# @subsys: nvme controller to attach to
+#
+# @nsid: namespace identifier to assign
+#
+# Since: 6.1
+##
+{ 'struct': 'NvmeNamespaceProperties',
+ 'data': { 'subsys': 'str',
+ '*nsid': 'str',
+ '*eui64': 'str',
+ '*uuid': 'str' } }
+
##
# @PrManagerHelperProperties:
#
--
2.33.0
- [PATCH RFC v2 03/16] hw/nvme: move dif/pi prototypes into dif.h, (continued)
- [PATCH RFC v2 03/16] hw/nvme: move dif/pi prototypes into dif.h, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 04/16] hw/nvme: move zns helpers and types into zns.h, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 05/16] hw/nvme: move zoned namespace members to separate struct, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 06/16] hw/nvme: move nvm namespace members to separate struct, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 07/16] hw/nvme: move BlockBackend to NvmeNamespaceNvm, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 08/16] hw/nvme: hoist qdev state from namespace, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 09/16] hw/nvme: hoist qdev state from subsystem, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 10/16] hw/nvme: hoist qdev state from controller, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 11/16] hw/nvme: add experimental object x-nvme-subsystem, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 12/16] nvme: add structured type for nguid, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 13/16] hw/nvme: add experimental abstract object x-nvme-ns,
Klaus Jensen <=
- [PATCH RFC v2 14/16] hw/nvme: add experimental objects x-nvme-ns-{nvm, zoned}, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 15/16] hw/nvme: add experimental device x-nvme-ctrl, Klaus Jensen, 2021/09/27
- [PATCH RFC v2 16/16] docs: add documentation for experimental nvme emulation, Klaus Jensen, 2021/09/27