]> www.infradead.org Git - users/hch/nvme-cli.git/commitdiff
support for zoned command set
authorKeith Busch <kbusch@kernel.org>
Mon, 8 Jun 2020 23:13:50 +0000 (16:13 -0700)
committerKeith Busch <kbusch@kernel.org>
Tue, 16 Jun 2020 16:29:45 +0000 (09:29 -0700)
Signed-off-by: Keith Busch <kbusch@kernel.org>
Makefile
linux/nvme.h
nvme-ioctl.c
nvme-ioctl.h
nvme-print.c
nvme-print.h
nvme.c
nvme.h
plugins/zns/zns.c [new file with mode: 0644]
plugins/zns/zns.h [new file with mode: 0644]

index 9db121c51266e80f79d2bea272c993f517aa692e..f5e9853e529ebba7d17e81d56bda01a136a74e12 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -77,9 +77,10 @@ PLUGIN_OBJS :=                                       \
        plugins/seagate/seagate-nvme.o          \
        plugins/virtium/virtium-nvme.o          \
        plugins/shannon/shannon-nvme.o          \
-       plugins/dera/dera-nvme.o            \
-       plugins/scaleflux/sfx-nvme.o        \
-    plugins/transcend/transcend-nvme.o
+       plugins/dera/dera-nvme.o                \
+       plugins/scaleflux/sfx-nvme.o            \
+       plugins/transcend/transcend-nvme.o      \
+       plugins/zns/zns.o
 
 nvme: nvme.c nvme.h $(OBJS) $(PLUGIN_OBJS) $(UTIL_OBJS) NVME-VERSION-FILE
        $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) $< -o $(NVME) $(OBJS) $(PLUGIN_OBJS) $(UTIL_OBJS) $(LDFLAGS)
index f2c4fdb1e24b986a95326e94a6f2effaf90bfa8c..98780ce063293e620ff66de859edaffeb404f4d0 100644 (file)
@@ -814,6 +814,9 @@ enum nvme_opcode {
        nvme_cmd_resv_report    = 0x0e,
        nvme_cmd_resv_acquire   = 0x11,
        nvme_cmd_resv_release   = 0x15,
+       nvme_zns_cmd_mgmt_send  = 0x79,
+       nvme_zns_cmd_mgmt_recv  = 0x7a,
+       nvme_zns_cmd_append     = 0x7d,
 };
 
 /*
@@ -1415,4 +1418,139 @@ enum {
 #define NVME_MINOR(ver)                (((ver) >> 8) & 0xff)
 #define NVME_TERTIARY(ver)     ((ver) & 0xff)
 
+
+/**
+ * struct nvme_zns_lbafe -
+ * zsze:
+ * zdes:
+ */
+struct nvme_zns_lbafe {
+       __le64  zsze;
+       __u8    zdes;
+       __u8    rsvd9[7];
+};
+
+/**
+ * struct nvme_zns_id_ns -
+ * @zoc:
+ * @ozcs:
+ * @mar:
+ * @mor:
+ * @rrl:
+ * @frl:
+ * @lbafe:
+ * @vs:
+ */
+struct nvme_zns_id_ns {
+       __le16                  zoc;
+       __le16                  ozcs;
+       __le32                  mar;
+       __le32                  mor;
+       __le32                  rrl;
+       __le32                  frl;
+       __u8                    rsvd20[2796];
+       struct nvme_zns_lbafe   lbafe[16];
+       __u8                    rsvd3072[768];
+       __u8                    vs[256];
+};
+
+/**
+ * struct nvme_zns_id_ctrl -
+ * @zamds:
+ */
+struct nvme_zns_id_ctrl {
+       __u8    zamds;
+       __u8    rsvd1[4095];
+};
+
+#define NVME_ZNS_CHANGED_ZONES_MAX     511
+
+/**
+ * struct nvme_zns_changed_zone_log - ZNS Changed Zone List log
+ * @nrzid:
+ * @zid:
+ */
+struct nvme_zns_changed_zone_log {
+       __le16          nrzid;
+       __u8            rsvd2[6];
+       __le64          zid[NVME_ZNS_CHANGED_ZONES_MAX];
+};
+
+/**
+ * enum nvme_zns_zt -
+ */
+enum nvme_zns_zt {
+       NVME_ZONE_TYPE_SEQWRITE_REQ     = 0x2,
+};
+
+/**
+ * enum nvme_zns_za -
+ */
+enum nvme_zns_za {
+       NVME_ZNS_ZA_ZFC                 = 1 << 0,
+       NVME_ZNS_ZA_FZR                 = 1 << 1,
+       NVME_ZNS_ZA_RZR                 = 1 << 2,
+       NVME_ZNS_ZA_ZDEV                = 1 << 7,
+};
+
+/**
+ * enum nvme_zns_zs -
+ */
+enum nvme_zns_zs {
+       NVME_ZNS_ZS_EMPTY               = 0x1,
+       NVME_ZNS_ZS_IMPL_OPEN           = 0x2,
+       NVME_ZNS_ZS_EXPL_OPEN           = 0x3,
+       NVME_ZNS_ZS_CLOSED              = 0x4,
+       NVME_ZNS_ZS_READ_ONLY           = 0xd,
+       NVME_ZNS_ZS_FULL                = 0xe,
+       NVME_ZNS_ZS_OFFLINE             = 0xf,
+};
+
+/**
+ * struct nvme_zns_desc -
+ */
+struct nvme_zns_desc {
+       __u8    zt;
+       __u8    zs;
+       __u8    za;
+       __u8    rsvd3[5];
+       __le64  zcap;
+       __le64  zslba;
+       __le64  wp;
+       __u8    rsvd32[32];
+};
+
+/**
+ * struct nvme_zone_report -
+ */
+struct nvme_zone_report {
+       __le64                  nr_zones;
+       __u8                    resv8[56];
+       struct nvme_zns_desc    entries[];
+};
+
+enum nvme_zns_send_action {
+       NVME_ZNS_ZSA_CLOSE              = 0x1,
+       NVME_ZNS_ZSA_FINISH             = 0x2,
+       NVME_ZNS_ZSA_OPEN               = 0x3,
+       NVME_ZNS_ZSA_RESET              = 0x4,
+       NVME_ZNS_ZSA_OFFLINE            = 0x5,
+       NVME_ZNS_ZSA_SET_DESC_EXT       = 0x10,
+};
+
+enum nvme_zns_recv_action {
+       NVME_ZNS_ZRA_REPORT_ZONES               = 0x0,
+       NVME_ZNS_ZRA_EXTENDED_REPORT_ZONES      = 0x1,
+};
+
+enum nvme_zns_report_options {
+       NVME_ZNS_ZRAS_REPORT_ALL                = 0x0,
+       NVME_ZNS_ZRAS_REPORT_EMPTY              = 0x1,
+       NVME_ZNS_ZRAS_REPORT_IMPL_OPENED        = 0x2,
+       NVME_ZNS_ZRAS_REPORT_EXPL_OPENED        = 0x3,
+       NVME_ZNS_ZRAS_REPORT_CLOSED             = 0x4,
+       NVME_ZNS_ZRAS_REPORT_FULL               = 0x5,
+       NVME_ZNS_ZRAS_REPORT_READ_ONLY          = 0x6,
+       NVME_ZNS_ZRAS_REPORT_OFFLINE            = 0x7,
+};
 #endif /* _LINUX_NVME_H */
index 39685d6bd71bb4fb8005a94f40b8edf1f3b5bb35..403ac5b7e1e708a3227b9aa72c3a3924fef3e25d 100644 (file)
@@ -405,6 +405,16 @@ int nvme_identify_uuid(int fd, void *data)
        return nvme_identify(fd, 0, NVME_ID_CNS_UUID_LIST, data);
 }
 
+int nvme_zns_identify_ns(int fd, __u32 nsid, void *data)
+{
+       return nvme_identify13(fd, nsid, 6, 2 << 24, data);
+}
+
+int nvme_zns_identify_ctrl(int fd, void *data)
+{
+       return nvme_identify13(fd, 0, 6, 2 << 24, data);
+}
+
 int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
                  __u16 lsi, bool rae, __u8 uuid_ix, __u32 data_len, void *data)
 {
@@ -877,3 +887,101 @@ int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result)
 
        return err;
 }
+
+int nvme_zns_mgmt_send(int fd, __u32 nsid, __u64 slba, bool select_all,
+                      enum nvme_zns_send_action zsa, __u32 data_len,
+                      void *data)
+{
+       __u32 cdw10 = slba & 0xffffffff;
+       __u32 cdw11 = slba >> 32;
+       __u32 cdw13 = zsa | (!!select_all) << 8;
+
+       struct nvme_passthru_cmd cmd = {
+               .opcode         = nvme_zns_cmd_mgmt_send,
+               .nsid           = nsid,
+               .cdw10          = cdw10,
+               .cdw11          = cdw11,
+               .cdw13          = cdw13,
+               .addr           = (__u64)(uintptr_t)data,
+               .data_len       = data_len,
+       };
+
+       return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_zns_mgmt_recv(int fd, __u32 nsid, __u64 slba,
+                      enum nvme_zns_recv_action zra, __u16 zrasf,
+                      bool zras_feat, __u32 data_len, void *data)
+{
+       __u32 cdw10 = slba & 0xffffffff;
+       __u32 cdw11 = slba >> 32;
+       __u32 cdw12 = (data_len >> 2) - 1;
+       __u32 cdw13 = zra | zrasf << 8 | zras_feat << 16;
+
+       struct nvme_passthru_cmd cmd = {
+               .opcode         = nvme_zns_cmd_mgmt_recv,
+               .nsid           = nsid,
+               .cdw10          = cdw10,
+               .cdw11          = cdw11,
+               .cdw12          = cdw12,
+               .cdw13          = cdw13,
+               .addr           = (__u64)(uintptr_t)data,
+               .data_len       = data_len,
+       };
+
+       return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_zns_report_zones(int fd, __u32 nsid, __u64 slba, bool extended,
+                         enum nvme_zns_report_options opts, bool partial,
+                         __u32 data_len, void *data)
+{
+       enum nvme_zns_recv_action zra;
+
+       if (extended)
+               zra = NVME_ZNS_ZRA_EXTENDED_REPORT_ZONES;
+       else
+               zra = NVME_ZNS_ZRA_REPORT_ZONES;
+
+       return nvme_zns_mgmt_recv(fd, nsid, slba, zra, opts, partial,
+               data_len, data);
+}
+
+int nvme_zns_append(int fd, __u32 nsid, __u64 zslba, __u16 nlb, __u16 control,
+                   __u32 ilbrt, __u16 lbat, __u16 lbatm, __u32 data_len,
+                   void *data, __u32 metadata_len, void *metadata,
+                   __u64 *result)
+{
+       __u32 cdw10 = zslba & 0xffffffff;
+       __u32 cdw11 = zslba >> 32;
+       __u32 cdw12 = nlb | (control << 16);
+       __u32 cdw14 = ilbrt;
+       __u32 cdw15 = lbat | (lbatm << 16);
+
+       struct nvme_passthru_cmd64 cmd = {
+               .opcode         = nvme_zns_cmd_append,
+               .nsid           = nsid,
+               .cdw10          = cdw10,
+               .cdw11          = cdw11,
+               .cdw12          = cdw12,
+               .cdw14          = cdw14,
+               .cdw15          = cdw15,
+               .metadata       = (__u64)(uintptr_t)metadata,
+               .addr           = (__u64)(uintptr_t)data,
+               .metadata_len   = metadata_len,
+               .data_len       = data_len,
+       };
+
+       int err;
+
+       err = ioctl(fd, NVME_IOCTL_IO64_CMD, cmd);
+       if (!err && result)
+               *result = cmd.result;
+       return err;
+}
+
+int nvme_get_log_zns_changed_zones(int fd, __u32 nsid, bool rae,
+                                  struct nvme_zns_changed_zone_log *log)
+{
+       return 0;
+}
index aae4e494e3d03c176cf0b8108544dd267bf73944..ad8237e8cbd10a8733331e8193fb073a3ff9eb58 100644 (file)
@@ -85,6 +85,8 @@ int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data);
 int nvme_identify_uuid(int fd, void *data);
 int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
 int nvme_identify_ns_granularity(int fd, void *data);
+int nvme_zns_identify_ctrl(int fd, void *data);
+int nvme_zns_identify_ns(int fd, __u32 nsid, void *data);
 int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
                 __u32 data_len, void *data);
 int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
@@ -152,4 +154,21 @@ int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
 int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10);
 int nvme_self_test_log(int fd, __u32 nsid, struct nvme_self_test_log *self_test_log);
 int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result);
+
+int nvme_zns_mgmt_send(int fd, __u32 nsid, __u64 slba, bool select_all,
+                      enum nvme_zns_send_action zsa, __u32 data_len,
+                      void *data);
+int nvme_zns_mgmt_recv(int fd, __u32 nsid, __u64 slba,
+                      enum nvme_zns_recv_action zra, __u16 zrasf,
+                      bool zras_feat, __u32 data_len, void *data);
+int nvme_zns_report_zones(int fd, __u32 nsid, __u64 slba, bool extended,
+                         enum nvme_zns_report_options opts, bool partial,
+                         __u32 data_len, void *data);
+int nvme_zns_append(int fd, __u32 nsid, __u64 zslba, __u16 nlb, __u16 control,
+                   __u32 ilbrt, __u16 lbat, __u16 lbatm, __u32 data_len,
+                   void *data, __u32 metadata_len, void *metadata,
+                   __u64 *result);
+int nvme_get_log_zns_changed_zones(int fd, __u32 nsid, bool rae,
+                                  struct nvme_zns_changed_zone_log *log);
+
 #endif                         /* _NVME_LIB_H */
index 30fca29d36e57374ee67ff0f969e07e14387da5b..364bfe2d33683f22be6ddf1419f63ca2ad64019c 100644 (file)
@@ -2858,6 +2858,100 @@ void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode)
        __nvme_show_id_ctrl(ctrl, mode, NULL);
 }
 
+static void json_nvme_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode)
+{
+       struct json_object *root;
+
+       root = json_create_object();
+       json_object_add_value_int(root, "zamds", ctrl->zamds);
+
+       json_print_object(root, NULL);
+       printf("\n");
+       json_free_object(root);
+}
+
+void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode)
+{
+       if (mode & BINARY)
+               return d_raw((unsigned char *)ctrl, sizeof(*ctrl));
+       else if (mode & JSON)
+               return json_nvme_zns_id_ctrl(ctrl, mode);
+
+       printf("NVMe ZNS Identify Controller:\n");
+       printf("zamds: %u\n", ctrl->zamds);
+}
+
+void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns,
+       struct nvme_id_ns *id_ns, unsigned long flags)
+{
+       uint8_t lbaf = id_ns->flbas & NVME_NS_FLBAS_LBA_MASK;
+       int i;
+
+       if (flags & BINARY)
+               return d_raw((unsigned char *)ns, sizeof(*ns));
+
+       printf("NVMe ZNS Identify Namespace:\n");
+       printf("zoc:    %u", le16_to_cpu(ns->zoc));
+       printf("ozcs:   %u", le16_to_cpu(ns->ozcs));
+       printf("mar:    %u", le16_to_cpu(ns->mar));
+       printf("mor:    %u", le16_to_cpu(ns->mor));
+       printf("rrl:    %u", ns->rrl);
+       printf("frl:    %u", ns->frl);
+
+       for (i = 0; i <= id_ns->nlbaf; i++)
+               printf("lbafe %02d: zsze:%"PRIx64" zdes:%u%s\n", i,
+                       (uint64_t)le64_to_cpu(ns->lbafe[i].zsze),
+                       ns->lbafe[i].zdes, i == lbaf ? " in use" : "");
+}
+
+void nvme_show_zns_changed( struct nvme_zns_changed_zone_log *log,
+       unsigned long flags)
+{
+       uint16_t nrzid;
+       int i;
+
+       if (flags & BINARY)
+               return d_raw((unsigned char *)log, sizeof(*log));
+
+       nrzid = le16_to_cpu(log->nrzid);
+       printf("NVMe Changed Zone List:\n");
+       printf("nrzid:  %u\n", nrzid);
+
+       for (i = 0; i < min(nrzid, (uint16_t)NVME_ZNS_CHANGED_ZONES_MAX); i++)
+               printf("zid %03d: %"PRIu64"\n", i, (uint64_t)le64_to_cpu(log->zid[i]));
+}
+
+void nvme_show_zns_report_zones(void *report, __u32 descs,
+       __u8 ext_size, __u32 report_size, unsigned long flags)
+{
+       struct nvme_zone_report *r = report;
+       struct nvme_zns_desc *desc;
+       int i;
+
+       __u64 nr_zones = le64_to_cpu(r->nr_zones);
+
+       if (nr_zones < descs)
+               descs = nr_zones;
+
+       if (flags & BINARY)
+               return d_raw((unsigned char *)report, report_size);
+
+       printf("nr_zones : %"PRIu64"\n", (uint64_t)le64_to_cpu(r->nr_zones));
+       for (i = 0; i < descs; i++) {
+               desc = (struct nvme_zns_desc *)
+                       (report + sizeof(*r) + i * (sizeof(*desc) + ext_size));
+               printf(" desc %02d:\n", i);
+               printf(".................\n");
+               printf("zt      : %x\n", desc->zt);
+               printf("zs      : %x\n", desc->zs);
+               printf("za      : %x\n", desc->za);
+               printf("zcap    : %"PRIx64"\n", le64_to_cpu(desc->zcap));
+               printf("zslba   : %"PRIx64"\n", le64_to_cpu(desc->zslba));
+               printf("wp      : %"PRIx64"\n", le64_to_cpu(desc->wp));
+               printf(".................\n");
+       }
+}
+
 static void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset)
 {
        __u32 nent = nvmset->nid;
index 2a6f5ee51074a308543acfa98fd12e8951d983d2..318f708bdb0b91503b3278c0035b3831999b348f 100644 (file)
@@ -59,6 +59,14 @@ void nvme_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 res
        void *buf, __u32 len, enum nvme_print_flags flags);
 void nvme_show_select_result(__u32 result);
 
+void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode);
+void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns,
+       struct nvme_id_ns *id_ns, unsigned long flags);
+void nvme_show_zns_changed( struct nvme_zns_changed_zone_log *log,
+       unsigned long flags);
+void nvme_show_zns_report_zones(void *report, __u32 descs,
+       __u8 ext_size, __u32 report_size, unsigned long flags);
+
 const char *nvme_status_to_string(__u32 status);
 const char *nvme_select_to_string(int sel);
 const char *nvme_feature_to_string(int feature);
diff --git a/nvme.c b/nvme.c
index 107f01267569ce9cdc978d13a0a5989a74924b45..f4b228931fae5971efb52c9c5665f2c06b9009e8 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -85,7 +85,7 @@ static struct program nvme = {
        .extensions = &builtin,
 };
 
-static const char *output_format = "Output format: normal|json|binary";
+const char *output_format = "Output format: normal|json|binary";
 static const char *output_format_no_binary = "Output format: normal|json";
 
 static void *__nvme_alloc(size_t len, bool *huge)
@@ -103,7 +103,7 @@ static void *__nvme_alloc(size_t len, bool *huge)
 #ifdef LIBHUGETLBFS
 #define HUGE_MIN 0x80000
 
-static void nvme_free(void *p, bool huge)
+void nvme_free(void *p, bool huge)
 {
        if (huge)
                free_hugepage_region(p);
@@ -111,7 +111,7 @@ static void nvme_free(void *p, bool huge)
                free(p);
 }
 
-static void *nvme_alloc(size_t len, bool *huge)
+void *nvme_alloc(size_t len, bool *huge)
 {
        void *p;
 
@@ -126,12 +126,12 @@ static void *nvme_alloc(size_t len, bool *huge)
        return p;
 }
 #else
-static void nvme_free(void *p, bool huge)
+void nvme_free(void *p, bool huge)
 {
        free(p);
 }
 
-static void *nvme_alloc(size_t len, bool *huge)
+void *nvme_alloc(size_t len, bool *huge)
 {
        return __nvme_alloc(len, huge);
 }
diff --git a/nvme.h b/nvme.h
index 017148ae5fb0322bb3b00566fa8e43721d8910e5..361191b94ad611a90c6be6ce0454e4ed1fa852ac 100644 (file)
--- a/nvme.h
+++ b/nvme.h
@@ -87,6 +87,7 @@ int parse_and_open(int argc, char **argv, const char *desc,
        const struct argconfig_commandline_options *clo);
 
 extern const char *devicename;
+extern const char *output_format;
 
 enum nvme_print_flags validate_output_format(char *format);
 int __id_ctrl(int argc, char **argv, struct command *cmd,
@@ -107,4 +108,6 @@ void free_topology(struct nvme_topology *t);
 char *get_nvme_subsnqn(char *path);
 char *nvme_get_ctrl_attr(char *path, const char *attr);
 
+void *nvme_alloc(size_t len, bool *huge);
+void nvme_free(void *p, bool huge);
 #endif /* _NVME_H */
diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c
new file mode 100644 (file)
index 0000000..8218a91
--- /dev/null
@@ -0,0 +1,814 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <linux/fs.h>
+#include <sys/stat.h>
+
+#include "nvme.h"
+#include "nvme-ioctl.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "zns.h"
+
+static const char *namespace_id = "Namespace identify to use";
+
+static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Send ZNS specific Identify Controller command to "\
+               "the given device and report information about the specified "\
+               "controller in varios formats.";
+
+       enum nvme_print_flags flags;
+       struct nvme_zns_id_ctrl ctrl;
+       int fd, err = -1;
+
+       struct config {
+               char *output_format;
+       };
+
+       struct config cfg = {
+               .output_format = "normal",
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return errno;
+
+       err = flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto close_fd;
+
+       err = nvme_zns_identify_ctrl(fd, &ctrl);
+       if (!err)
+               nvme_show_zns_id_ctrl(&ctrl, flags);
+       else
+               nvme_show_status(err);
+close_fd:
+       close(fd);
+       return err;
+}
+
+static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Send ZNS specific Identify Namespace command to "\
+               "the given device and report information about the specified "\
+               "namespace in varios formats.";
+       const char *verbose = "verbosely decode fields";
+
+       enum nvme_print_flags flags;
+       struct nvme_zns_id_ns ns;
+       struct nvme_id_ns id_ns;
+       int fd, err = -1;
+
+       struct config {
+               char *output_format;
+               __u32 namespace_id;
+               int verbose;
+       };
+
+       struct config cfg = {
+               .output_format = "normal",
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id", 'n', &cfg.namespace_id,  namespace_id),
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_FLAG("verbose",      'v', &cfg.verbose,       verbose),
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return errno;
+
+       flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto close_fd;
+       if (cfg.verbose)
+               flags |= VERBOSE;
+
+       if (!cfg.namespace_id) {
+               err = cfg.namespace_id = nvme_get_nsid(fd);
+               if (err < 0) {
+                       perror("get-namespace-id");
+                       goto close_fd;
+               }
+       }
+
+       err = nvme_identify_ns(fd, cfg.namespace_id, false, &id_ns);
+       if (err) {
+               nvme_show_status(err);
+               goto close_fd;
+       }
+
+       err = nvme_zns_identify_ns(fd, cfg.namespace_id, &ns);
+       if (!err)
+               nvme_show_zns_id_ns(&ns, &id_ns, flags);
+       else
+               nvme_show_status(err);
+close_fd:
+       close(fd);
+       return err;
+}
+
+static int __zns_mgmt_send(int fd, __u32 namespace_id, __u64 zslba,
+       bool select_all, enum nvme_zns_send_action zsa, __u32 data_len, void *buf)
+{
+       int err;
+
+       if (!namespace_id) {
+               err = namespace_id = nvme_get_nsid(fd);
+               if (err < 0) {
+                       perror("get-namespace-id");
+                       goto close_fd;
+               }
+       }
+
+       err = nvme_zns_mgmt_send(fd, namespace_id, zslba, select_all, zsa,
+                       data_len, buf);
+close_fd:
+       close(fd);
+       return err;
+}
+
+static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin,
+       const char *desc, enum nvme_zns_send_action zsa)
+{
+       const char *zslba = "starting lba of the zone for this command";
+       const char *select_all = "send command to all zones";
+
+       int err, fd;
+       char *command;
+
+       struct config {
+               __u64   zslba;
+               int     namespace_id;
+               bool    select_all;
+       };
+
+       struct config cfg = {
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id", 'n', &cfg.namespace_id,  namespace_id),
+               OPT_SUFFIX("start-lba",  's', &cfg.zslba,         zslba),
+               OPT_FLAG("select-all",   'a', &cfg.select_all,    select_all),
+               OPT_END()
+       };
+
+       err = asprintf(&command, "%s-%s", plugin->name, cmd->name);
+       if (err < 0)
+               return errno;
+
+       err = fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               goto free;
+
+       err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba,
+               cfg.select_all, zsa, 0, NULL);
+       if (!err)
+               printf("%s: Success, action:%d zone:%"PRIx64" nsid:%d\n", command,
+                       zsa, (uint64_t)zslba, cfg.namespace_id);
+       else
+               nvme_show_status(err);
+free:
+       free(command);
+       return err;
+}
+
+static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Zone Management Send";
+       const char *zslba = "starting lba of the zone for this command";
+       const char *select_all = "send command to all zones";
+       const char *zsa = "zone send action";
+       const char *data_len = "buffer length if data required";
+       const char *data = "optional file for data (default stdin)";
+
+       int fd, ffd = STDIN_FILENO, err = -1;
+       void *buf = NULL;
+
+       struct config {
+               __u64   zslba;
+               int     namespace_id;
+               bool    select_all;
+               __u8    zsa;
+               __u32   data_len;
+               char   *file;
+       };
+
+       struct config cfg = {
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id", 'n', &cfg.namespace_id,  namespace_id),
+               OPT_SUFFIX("start-lba",  's', &cfg.zslba,         zslba),
+               OPT_FLAG("select-all",   'a', &cfg.select_all,    select_all),
+               OPT_BYTE("zsa",          'z', &cfg.zsa,           zsa),
+               OPT_UINT("data-len",     'l', &cfg.data_len,     data_len),
+               OPT_FILE("data",         'd', &cfg.file,         data),
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return errno;
+
+       if (cfg.data_len) {
+               if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
+                       fprintf(stderr, "can not allocate feature payload\n");
+                       goto close_fd;
+               }
+               memset(buf, 0, cfg.data_len);
+
+               if (cfg.file) {
+                       ffd = open(cfg.file, O_RDONLY);
+                       if (ffd < 0) {
+                               perror(cfg.file);
+                               goto free;
+                       }
+               }
+
+               err = read(ffd, (void *)buf, cfg.data_len);
+               if (err < 0) {
+                       perror("read");
+                       goto close_ffd;
+               }
+       }
+
+       err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, cfg.select_all,
+                       cfg.zsa, cfg.data_len, buf);
+       if (!err)
+               printf("zone-mgmt-send: Success, action:%d zone:%"PRIx64" nsid:%d\n",
+                       cfg.zsa, (uint64_t)cfg.zslba, cfg.namespace_id);
+       else
+               nvme_show_status(err);
+
+close_ffd:
+       if (cfg.file)
+               close(ffd);
+free:
+       if (buf)
+               free(buf);
+close_fd:
+       close(fd);
+       return err;
+}
+
+static int close_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Close zones\n";
+
+       return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_CLOSE);
+}
+
+static int finish_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Finish zones\n";
+
+       return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_FINISH);
+}
+
+static int open_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Open zones\n";
+
+       return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_OPEN);
+}
+
+static int reset_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Reset zones\n";
+
+       return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_RESET);
+}
+
+static int offline_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Offline zones\n";
+
+       return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_OFFLINE);
+}
+
+static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Set Zone Descriptor Extension\n";
+       const char *zslba = "starting lba of the zone for this command";
+       const char *data = "optional file for zone extention data (default stdin)";
+
+       int fd, ffd = STDIN_FILENO, err;
+       struct nvme_zns_id_ns ns;
+       struct nvme_id_ns id_ns;
+       void *buf = NULL;
+       __u32 data_len;
+       uint8_t lbaf;
+
+       struct config {
+               __u64   zslba;
+               int     namespace_id;
+               char   *file;
+       };
+
+       struct config cfg = {
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id", 'n', &cfg.namespace_id,  namespace_id),
+               OPT_SUFFIX("start-lba",  's', &cfg.zslba,         zslba),
+               OPT_FILE("data",         'd', &cfg.file,         data),
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return errno;
+
+       err = nvme_identify_ns(fd, cfg.namespace_id, false, &id_ns);
+       if (err) {
+               nvme_show_status(err);
+               goto close_fd;
+       }
+
+       err = nvme_zns_identify_ns(fd, cfg.namespace_id, &ns);
+       if (err) {
+               nvme_show_status(err);
+               goto close_fd;
+       }
+
+       lbaf = id_ns.flbas & NVME_NS_FLBAS_LBA_MASK;
+       data_len = ns.lbafe[lbaf].zdes;
+
+       if (!data_len) {
+               fprintf(stderr,
+                       "zone format does not provide descriptor extention\n");
+               errno = EINVAL;
+               err = -1;
+               goto close_fd;
+       }
+
+       buf = calloc(1, data_len);
+       if (!buf) {
+               err = -1;
+               goto close_fd;
+       }
+
+       if (cfg.file) {
+               ffd = open(cfg.file, O_RDONLY);
+               if (ffd < 0) {
+                       perror(cfg.file);
+                       err = -1;
+                       goto free;
+               }
+       }
+
+       err = read(ffd, (void *)buf, data_len);
+       if (err < 0) {
+               perror("read");
+               goto close_ffd;
+       }
+
+       err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, 0,
+               NVME_ZNS_ZSA_SET_DESC_EXT, data_len, buf);
+       if (!err)
+               printf("set-zone-desc: Success, zone:%"PRIx64" nsid:%d\n",
+                       (uint64_t)cfg.zslba, cfg.namespace_id);
+       else
+               nvme_show_status(err);
+close_ffd:
+       if (cfg.file)
+               close(ffd);
+free:
+       free(buf);
+close_fd:
+       close(fd);
+       return err;
+}
+
+static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Zone Management Receive";
+
+       enum nvme_print_flags flags;
+       int fd, err = -1;
+       void *data = NULL;
+
+       struct config {
+               char *output_format;
+               __u64  zslba;
+               __u32  namespace_id;
+               __u16  zra;
+               __u16  zrasf;
+               bool   zrass;
+               __u32  data_len;
+       };
+
+       struct config cfg = {
+               .output_format = "normal",
+       };
+
+
+       OPT_ARGS(opts) = {
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return errno;
+
+       flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto close_fd;
+
+       if (!cfg.namespace_id) {
+               err = cfg.namespace_id = nvme_get_nsid(fd);
+               if (err < 0) {
+                       perror("get-namespace-id");
+                       goto close_fd;
+               }
+       }
+
+       if (cfg.data_len) {
+               data = calloc(1, cfg.data_len);
+               if (!data) {
+                       err = -1;
+                       goto close_fd;
+               }
+       }
+
+       err = nvme_zns_mgmt_recv(fd, cfg.namespace_id, cfg.zslba, cfg.zra,
+               cfg.zrasf, cfg.zrass, cfg.data_len, data);
+       if (!err)
+               printf("zone-mgmt-recv: Success, action:%d zone:%"PRIx64" nsid:%d\n",
+                       cfg.zra, (uint64_t)cfg.zslba, cfg.namespace_id);
+       else
+               nvme_show_status(err);
+
+       if (data)
+               free(data);
+close_fd:
+       close(fd);
+       return err;
+}
+
+static int get_zdes(int fd, __u32 nsid)
+{
+       struct nvme_zns_id_ns ns;
+       struct nvme_id_ns id_ns;
+       __u8 lbaf;
+       int err;
+
+       err = nvme_identify_ns(fd, nsid,  false, &id_ns);
+       if (err) {
+               nvme_show_status(err);
+               return err;
+       }
+
+       err = nvme_zns_identify_ns(fd, nsid,  &ns);
+       if (err) {
+               nvme_show_status(err);
+               return err;
+       }
+
+       lbaf = id_ns.flbas & NVME_NS_FLBAS_LBA_MASK;
+       return ns.lbafe[lbaf].zdes;
+}
+
+static int report_zones(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Retrieve the Report Zones data structure";
+       const char *zslba = "starting lba of the zone";
+       const char *num_descs = "number of descriptors to retrieve";
+       const char *state = "state of zones to list";
+       const char *ext = "set to use the extended report zones";
+       const char *part = "set to use the partial report";
+       const char *verbose = "verbosely decode fields";
+
+       enum nvme_print_flags flags;
+       int fd, zdes = 0, err = -1;
+       __u32 report_size;
+       void *report;
+       bool huge = false;
+
+       struct config {
+               char *output_format;
+               __u64 zslba;
+               __u32 namespace_id;
+               int   num_descs;
+               int   state;
+               bool  verbose;
+               bool  extended;
+               bool  partial;
+       };
+
+       struct config cfg = {
+               .output_format = "normal",
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id", 'n', &cfg.namespace_id,  namespace_id),
+               OPT_SUFFIX("start-lba",  's', &cfg.zslba,         zslba),
+               OPT_UINT("descs",        'd', &cfg.num_descs,     num_descs),
+               OPT_UINT("state",        'S', &cfg.state,         state),
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_FLAG("verbose",      'v', &cfg.verbose,       verbose),
+               OPT_FLAG("extended",     'e', &cfg.extended,      ext),
+               OPT_FLAG("partial",      'p', &cfg.partial,       part),
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return errno;
+
+       flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto close_fd;
+       if (cfg.verbose)
+               flags |= VERBOSE;
+
+       if (!cfg.namespace_id) {
+               err = cfg.namespace_id = nvme_get_nsid(fd);
+               if (err < 0) {
+                       perror("get-namespace-id");
+                       goto close_fd;
+               }
+       }
+
+       if (cfg.extended) {
+               zdes = get_zdes(fd, cfg.namespace_id);
+               if (zdes < 0) {
+                       err = zdes;
+                       goto close_fd;
+               }
+       }
+
+       report_size = sizeof(struct nvme_zone_report) + cfg.num_descs *
+               (sizeof(struct nvme_zns_desc) + zdes);
+
+       report = nvme_alloc(report_size, &huge);
+       if (!report) {
+               perror("alloc");
+               err = -1;
+               goto close_fd;
+       }
+
+       err = nvme_zns_report_zones(fd, cfg.namespace_id, cfg.zslba,
+               cfg.extended, cfg.state, cfg.partial, report_size, report);
+       if (!err)
+               nvme_show_zns_report_zones(report, cfg.num_descs, zdes,
+                       report_size, flags);
+       else
+               nvme_show_status(err);
+
+       nvme_free(report, huge);
+close_fd:
+       close(fd);
+       return err;
+}
+
+static int zone_append(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "The zone append command is used to write to a zone "\
+                 "using the slba of the zone, and the write will be appended from the "\
+                 "write pointer of the zone";
+       const char *zslba = "starting lba of the zone";
+       const char *data = "file containing data to write";
+       const char *metadata = "file with metadata to be written";
+       const char *limited_retry = "limit media access attempts";
+       const char *fua = "force unit access";
+       const char *prinfo = "protection information action and checks field";
+       const char *ref_tag = "reference tag (for end to end PI)";
+       const char *lbat = "logical block application tag (for end to end PI)";
+       const char *lbatm = "logical block application tag mask (for end to end PI)";
+       const char *metadata_size = "size of metadata in bytes";
+       const char *data_size = "size of data in bytes";
+
+       int err = -1, fd, dfd = STDIN_FILENO, mfd = STDIN_FILENO;
+       unsigned int lba_size, meta_size;
+       void *buf = NULL, *mbuf = NULL;
+       __u16 nblocks, control = 0;
+       __u64 result;
+
+       struct nvme_id_ns ns;
+
+       struct config {
+               char  *data;
+               char  *metadata;
+               __u64  zslba;
+               __u64  data_size;
+               __u64  metadata_size;
+               int    limited_retry;
+               int    fua;
+               int    namespace_id;
+               __u32  ref_tag;
+               __u16  lbat;
+               __u16  lbatm;
+               __u8   prinfo;
+       };
+
+       struct config cfg = {
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id", 'n', &cfg.namespace_id,  namespace_id),
+               OPT_SUFFIX("zslba",           's', &cfg.zslba,         zslba),
+               OPT_SUFFIX("data-size",       'z', &cfg.data_size,     data_size),
+               OPT_SUFFIX("metadata-size",   'y', &cfg.metadata_size, metadata_size),
+               OPT_FILE("data",              'd', &cfg.data,          data),
+               OPT_FILE("metadata",          'M', &cfg.metadata,      metadata),
+               OPT_FLAG("limited-retry",     'l', &cfg.limited_retry, limited_retry),
+               OPT_FLAG("force-unit-access", 'f', &cfg.fua,           fua),
+               OPT_UINT("ref-tag",           'r', &cfg.ref_tag,       ref_tag),
+               OPT_SHRT("app-tag-mask",      'm', &cfg.lbatm,         lbatm),
+               OPT_SHRT("app-tag",           'a', &cfg.lbat,          lbat),
+               OPT_BYTE("prinfo",            'p', &cfg.prinfo,        prinfo),
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return errno;
+
+       if (!cfg.data_size) {
+               fprintf(stderr, "Append size not provided\n");
+               errno = EINVAL;
+               goto close_fd;
+       }
+
+       if (!cfg.namespace_id) {
+               err = cfg.namespace_id = nvme_get_nsid(fd);
+               if (err < 0) {
+                       perror("get-namespace-id");
+                       goto close_fd;
+               }
+       }
+
+       err = nvme_identify_ns(fd, cfg.namespace_id, false, &ns);
+       if (err) {
+               nvme_show_status(err);
+               goto close_fd;
+       }
+
+       lba_size = 1 << ns.lbaf[(ns.flbas & 0x0f)].ds;
+       if (cfg.data_size & (lba_size - 1)) {
+               fprintf(stderr,
+                       "Data size:%#"PRIx64" not aligned to lba size:%#x\n",
+                       (uint64_t)cfg.data_size, lba_size);
+               errno = EINVAL;
+               goto close_ns;
+       }
+
+       meta_size = ns.lbaf[(ns.flbas & 0x0f)].ms;
+       if (meta_size && (!cfg.metadata_size || cfg.metadata_size % meta_size)) {
+               fprintf(stderr,
+                       "Metadata size:%#"PRIx64" not aligned to metadata size:%#x\n",
+                       (uint64_t)cfg.metadata_size, meta_size);
+               errno = EINVAL;
+               goto close_ns;
+       }
+
+       if (cfg.prinfo > 0xf) {
+               fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo);
+               errno = EINVAL;
+               goto close_ns;
+       }
+
+       if (cfg.data) {
+               dfd = open(cfg.data, O_RDONLY);
+               if (dfd < 0) {
+                       perror(cfg.data);
+                       goto close_ns;
+               }
+       }
+
+       if (posix_memalign(&buf, getpagesize(), cfg.data_size)) {
+               fprintf(stderr, "No memory for data size:%"PRIx64"\n",
+                       (uint64_t)cfg.data_size);
+               goto close_dfd;
+       }
+
+       memset(buf, 0, cfg.data_size);
+       err = read(dfd, buf, cfg.data_size);
+       if (err < 0) {
+               perror("read-data");
+               goto free_data;
+       }
+
+       if (cfg.metadata) {
+               mfd = open(cfg.metadata, O_RDONLY);
+               if (mfd < 0) {
+                       perror(cfg.metadata);
+                       err = -1;
+                       goto close_dfd;
+               }
+       }
+
+       if (cfg.metadata_size) {
+               if (posix_memalign(&mbuf, getpagesize(), meta_size)) {
+                       fprintf(stderr, "No memory for metadata size:%d\n",
+                               meta_size);
+                       err = -1;
+                       goto close_mfd;
+               }
+
+               memset(mbuf, 0, cfg.metadata_size);
+               err = read(mfd, mbuf, cfg.metadata_size);
+               if (err < 0) {
+                       perror("read-metadata");
+                       goto free_meta;
+               }
+       }
+
+       nblocks = (cfg.data_size / lba_size) - 1;
+       control |= (cfg.prinfo << 10);
+       if (cfg.limited_retry)
+               control |= NVME_RW_LR;
+       if (cfg.fua)
+               control |= NVME_RW_FUA;
+
+       err = nvme_zns_append(fd, cfg.namespace_id, cfg.zslba, nblocks,
+                             control, cfg.ref_tag, cfg.lbat, cfg.lbatm,
+                             cfg.data_size, buf, cfg.metadata_size, mbuf,
+                             &result);
+       if (!err)
+               printf("Success appended data to LBA %"PRIx64"\n", (uint64_t)result);
+       else
+               nvme_show_status(err);
+
+free_meta:
+       free(mbuf);
+close_mfd:
+       if (cfg.metadata)
+               close(mfd);
+free_data:
+       free(buf);
+close_dfd:
+       if (cfg.data)
+               close(dfd);
+close_ns:
+close_fd:
+       close(fd);
+       return err;
+}
+
+static int change_zone_list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Retrieve Changed Zone log for the given device";
+       const char *rae = "retain an asynchronous event";
+
+       struct nvme_zns_changed_zone_log log;
+       enum nvme_print_flags flags;
+       int fd, err = -1;
+
+       struct config {
+               char *output_format;
+               __u32 namespace_id;
+               bool  rae;
+       };
+
+       struct config cfg = {
+               .output_format = "normal",
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id", 'n', &cfg.namespace_id,  namespace_id),
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_FLAG("rae",          'r', &cfg.rae,           rae),
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return errno;
+
+       flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto close_fd;
+
+       if (!cfg.namespace_id) {
+               err = cfg.namespace_id = nvme_get_nsid(fd);
+               if (err < 0) {
+                       perror("get-namespace-id");
+                       goto close_fd;
+               }
+       }
+
+       err = nvme_get_log_zns_changed_zones(fd, cfg.namespace_id, cfg.rae, &log);
+       if (!err)
+               nvme_show_zns_changed(&log, flags);
+       else
+               nvme_show_status(err);
+
+close_fd:
+       close(fd);
+       return err;
+}
diff --git a/plugins/zns/zns.h b/plugins/zns/zns.h
new file mode 100644 (file)
index 0000000..4e9d363
--- /dev/null
@@ -0,0 +1,30 @@
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/zns/zns
+
+#if !defined(ZNS_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define ZNS_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("zns", "Zoned Namespace Command Set"),
+       COMMAND_LIST(
+               ENTRY("id-ctrl", "Retrieve ZNS controller identification", id_ctrl)
+               ENTRY("id-ns", "Retrieve ZNS namespace identification", id_ns)
+               ENTRY("zone-mgmt-recv", "Sends the zone management receive command", zone_mgmt_recv)
+               ENTRY("zone-mgmt-send", "Sends the zone management send command", zone_mgmt_send)
+               ENTRY("report-zones", "Retrieve the Report Zones report", report_zones)
+               ENTRY("close-zone", "Closes one or more zones", close_zone)
+               ENTRY("finish-zone", "Finishes one or more zones", finish_zone)
+               ENTRY("open-zone", "Opens one or more zones", open_zone)
+               ENTRY("reset-zone", "Resets one or more zones", reset_zone)
+               ENTRY("offline-zone", "Offlines one or more zones", offline_zone)
+               ENTRY("set-zone-desc", "Attaches zone descriptor extension data", set_zone_desc)
+               ENTRY("zone-append", "Writes data and metadata (if applicable), appended to the end of the requested zone", zone_append)
+               ENTRY("changed-zone-list", "Retrieves the changed zone list log", change_zone_list)
+       )
+);
+
+#endif
+
+#include "define_cmd.h"
+