qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Klaus Jensen <its@irrelevant.dk>
To: qemu-devel@nongnu.org
Cc: "Fam Zheng" <fam@euphon.net>, "Kevin Wolf" <kwolf@redhat.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>,
	"Eduardo Habkost" <ehabkost@redhat.com>,
	qemu-block@nongnu.org,
	"Philippe Mathieu-Daudé" <philmd@redhat.com>,
	"Markus Armbruster" <armbru@redhat.com>,
	"Klaus Jensen" <its@irrelevant.dk>,
	"Hanna Reitz" <hreitz@redhat.com>,
	"Hannes Reinecke" <hare@suse.de>,
	"Stefan Hajnoczi" <stefanha@redhat.com>,
	"Klaus Jensen" <k.jensen@samsung.com>,
	"Keith Busch" <kbusch@kernel.org>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Eric Blake" <eblake@redhat.com>
Subject: [PATCH RFC v2 13/16] hw/nvme: add experimental abstract object x-nvme-ns
Date: Mon, 27 Sep 2021 07:17:56 +0200	[thread overview]
Message-ID: <20210927051759.447305-14-its@irrelevant.dk> (raw)
In-Reply-To: <20210927051759.447305-1-its@irrelevant.dk>

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



  parent reply	other threads:[~2021-09-27  5:51 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-27  5:17 [PATCH RFC v2 00/16] hw/nvme: experimental user-creatable objects Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 01/16] hw/nvme: reattach subsystem namespaces on hotplug Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 02/16] hw/nvme: change nvme-ns 'shared' default Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 03/16] hw/nvme: move dif/pi prototypes into dif.h Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 04/16] hw/nvme: move zns helpers and types into zns.h Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 05/16] hw/nvme: move zoned namespace members to separate struct Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 06/16] hw/nvme: move nvm " Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 07/16] hw/nvme: move BlockBackend to NvmeNamespaceNvm Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 08/16] hw/nvme: hoist qdev state from namespace Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 09/16] hw/nvme: hoist qdev state from subsystem Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 10/16] hw/nvme: hoist qdev state from controller Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 11/16] hw/nvme: add experimental object x-nvme-subsystem Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 12/16] nvme: add structured type for nguid Klaus Jensen
2021-09-27  5:17 ` Klaus Jensen [this message]
2021-09-27  5:17 ` [PATCH RFC v2 14/16] hw/nvme: add experimental objects x-nvme-ns-{nvm, zoned} Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 15/16] hw/nvme: add experimental device x-nvme-ctrl Klaus Jensen
2021-09-27  5:17 ` [PATCH RFC v2 16/16] docs: add documentation for experimental nvme emulation Klaus Jensen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210927051759.447305-14-its@irrelevant.dk \
    --to=its@irrelevant.dk \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=eblake@redhat.com \
    --cc=ehabkost@redhat.com \
    --cc=fam@euphon.net \
    --cc=hare@suse.de \
    --cc=hreitz@redhat.com \
    --cc=k.jensen@samsung.com \
    --cc=kbusch@kernel.org \
    --cc=kwolf@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=philmd@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).