From: Klaus Jensen <k.jen...@samsung.com> Add the abstract NvmeNamespace object to base proper namespace types on.
Signed-off-by: Klaus Jensen <k.jen...@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