]> www.infradead.org Git - users/hch/nvme-cli.git/commitdiff
zns
authorKeith Busch <kbusch@kernel.org>
Thu, 4 Jun 2020 20:22:47 +0000 (13:22 -0700)
committerKeith Busch <kbusch@kernel.org>
Thu, 4 Jun 2020 20:22:47 +0000 (13:22 -0700)
Signed-off-by: Keith Busch <kbusch@kernel.org>
libnvme
nvme.c
plugins/zns/zns.c [new file with mode: 0644]
plugins/zns/zns.h [new file with mode: 0644]
util/user-types.c
util/user-types.h

diff --git a/libnvme b/libnvme
index 5a0b27adc70c92ee2c37b09b006d1e4098278e59..a4c001a47663d0392d2cedfe33a8dec5654fc527 160000 (submodule)
--- a/libnvme
+++ b/libnvme
@@ -1 +1 @@
-Subproject commit 5a0b27adc70c92ee2c37b09b006d1e4098278e59
+Subproject commit a4c001a47663d0392d2cedfe33a8dec5654fc527
diff --git a/nvme.c b/nvme.c
index 2eba49445fd8204a6a087645df0f297126560ad1..a2893fb6758f94b4580d5f85f7ecf89531bb84a9 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -1614,7 +1614,7 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
        int err, fd;
 
        struct config {
-               __u32 namespace_id;
+               int   namespace_id;
                int   vendor_specific;
                int   raw_binary;
                int   human_readable;
@@ -1653,13 +1653,12 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
        if (!cfg.namespace_id) {
                cfg.namespace_id = nvme_get_nsid(fd);
                if (cfg.namespace_id < 0) {
-                       err = cfg.namespace_id;
-                       goto close_fd;
-               }
-               else if (!cfg.namespace_id) {
                        fprintf(stderr,
                                "Error: requesting namespace-id from non-block device\n");
-                       err = -ENOTBLK;
+                       err = cfg.namespace_id;
+                       goto close_fd;
+               } else if (!cfg.namespace_id) {
+                       err = -EINVAL;
                        goto close_fd;
                }
        }
@@ -2968,9 +2967,7 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
                        goto close_fd;
                }
                memset(buf, 0, cfg.data_len);
-       }
 
-       if (buf) {
                if (cfg.file) {
                        ffd = open(cfg.file, O_RDONLY);
                        if (ffd <= 0) {
@@ -3784,6 +3781,7 @@ static int submit_io(int opcode, char *command, const char *desc,
        const char *dtype = "directive type (for write-only)";
        const char *dspec = "directive specific (for write-only)";
        const char *dsm = "dataset management attributes (lower 16 bits)";
+       const char *namespace_id = "desired namespace";
 
        struct config {
                __u64 start_block;
@@ -3799,6 +3797,7 @@ static int submit_io(int opcode, char *command, const char *desc,
                __u16 dsmgmt;
                __u16 app_tag_mask;
                __u16 app_tag;
+               int   namespace_id;
                int   limited_retry;
                int   force_unit_access;
                int   show;
@@ -3809,6 +3808,7 @@ static int submit_io(int opcode, char *command, const char *desc,
        struct config cfg = { 0 };
 
        OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id",      'n', &cfg.namespace_id,      namespace_id),
                OPT_SUFFIX("start-block",     's', &cfg.start_block,       start_block),
                OPT_SHRT("block-count",       'c', &cfg.block_count,       block_count),
                OPT_SUFFIX("data-size",       'z', &cfg.data_size,         data_size),
@@ -3834,6 +3834,14 @@ static int submit_io(int opcode, char *command, const char *desc,
        if (fd < 0)
                goto ret;
 
+       if (!cfg.namespace_id) {
+               cfg.namespace_id = nvme_get_nsid(fd);
+               if (cfg.namespace_id <= 0) {
+                       err = cfg.namespace_id;
+                       goto close_fd;
+               }
+       }
+
        dfd = mfd = opcode & 1 ? STDIN_FILENO : STDOUT_FILENO;
        if (cfg.prinfo > 0xf) {
                err = -EINVAL;
@@ -3857,7 +3865,7 @@ static int submit_io(int opcode, char *command, const char *desc,
                dsmgmt |= ((__u32)cfg.dspec) << 16;
        }
 
-       if (cfg.data && strlen(cfg.data)) {
+       if (cfg.data) {
                dfd = open(cfg.data, flags, mode);
                if (dfd < 0) {
                        perror(cfg.data);
@@ -3866,7 +3874,8 @@ static int submit_io(int opcode, char *command, const char *desc,
                }
                mfd = dfd;
        }
-       if (cfg.metadata && strlen(cfg.metadata)) {
+
+       if (cfg.metadata) {
                mfd = open(cfg.metadata, flags, mode);
                if (mfd < 0) {
                        perror(cfg.metadata);
@@ -3886,8 +3895,9 @@ static int submit_io(int opcode, char *command, const char *desc,
 
        buffer_size = (cfg.block_count + 1) * phys_sector_size;
        if (cfg.data_size < buffer_size)
-               fprintf(stderr, "Rounding data size to fit block count (%u bytes)\n",
-                               buffer_size);
+               fprintf(stderr,
+                       "Rounding data size to fit block count (%u bytes)\n",
+                       buffer_size);
        else
                buffer_size = cfg.data_size;
 
@@ -3897,6 +3907,7 @@ static int submit_io(int opcode, char *command, const char *desc,
                err = -1;
                goto close_mfd;
        }
+       memset(buffer, 0, buffer_size);
 
        if (cfg.metadata_size) {
                mbuffer = malloc(cfg.metadata_size);
@@ -3949,14 +3960,14 @@ static int submit_io(int opcode, char *command, const char *desc,
 
        gettimeofday(&start_time, NULL);
        if (opcode & 1)
-               err = nvme_write(fd, 0, cfg.start_block, cfg.block_count,
-                       control, dsmgmt, 0, cfg.ref_tag, cfg.app_tag,
-                       cfg.app_tag_mask, buffer_size, buffer,
+               err = nvme_write(fd, cfg.namespace_id, cfg.start_block,
+                       cfg.block_count, control, dsmgmt, 0, cfg.ref_tag,
+                       cfg.app_tag, cfg.app_tag_mask, buffer_size, buffer,
                        cfg.metadata_size, mbuffer);
        else
-               err = nvme_read(fd, 0, cfg.start_block, cfg.block_count,
-                       control, dsmgmt, cfg.ref_tag, cfg.app_tag,
-                       cfg.app_tag_mask, buffer_size, buffer,
+               err = nvme_read(fd, cfg.namespace_id, cfg.start_block,
+                       cfg.block_count, control, dsmgmt, cfg.ref_tag,
+                       cfg.app_tag, cfg.app_tag_mask, buffer_size, buffer,
                        cfg.metadata_size, mbuffer);
        gettimeofday(&end_time, NULL);
 
@@ -3985,10 +3996,11 @@ free_mbuffer:
 free_buffer:
        nvme_free(buffer, huge);
 close_mfd:
-       if (strlen(cfg.metadata))
+       if (cfg.metadata)
                close(mfd);
 close_dfd:
-       close(dfd);
+       if (cfg.data)
+               close(dfd);
 close_fd:
        close(fd);
 ret:
diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c
new file mode 100644 (file)
index 0000000..1306152
--- /dev/null
@@ -0,0 +1,612 @@
+#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"
+
+#define CREATE_CMD
+#include "zns.h"
+
+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 err, fd;
+
+       struct config {
+               char *output_format;
+               int verbose;
+       };
+
+       struct config cfg = {
+               .output_format = "normal",
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_END()
+       };
+
+       err = 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_print_object(nvme_zns_id_ctrl_to_json(&ctrl, flags));
+       else
+               nvme_show_status("zns-id-ctrl", err);
+close_fd:
+       close(fd);
+       return nvme_status_to_errno(err, false);
+}
+
+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 *namespace_id = "identifier of desired namespace";
+       const char *verbose = "verbosely decode fields";
+
+       enum nvme_print_flags flags;
+       struct nvme_zns_id_ns ns;
+       struct nvme_id_ns id_ns;
+       int err, fd;
+
+       struct config {
+               char *output_format;
+               int 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()
+       };
+
+       err = 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;
+       if (cfg.verbose)
+               flags |= VERBOSE;
+
+       if (!cfg.namespace_id) {
+               cfg.namespace_id = nvme_get_nsid(fd);
+               if (cfg.namespace_id <= 0) {
+                       if (!namespace_id) {
+                               errno = EINVAL;
+                               err = -1;
+                       } else
+                               err = cfg.namespace_id;
+                       fprintf(stderr, "Error: retrieving namespace-id\n");
+                       goto close_fd;
+               }
+       }
+
+       err = nvme_identify_ns(fd, cfg.namespace_id, &id_ns);
+       if (err) {
+               nvme_show_status("id-ns", err);
+               goto close_fd;
+       }
+
+       err = nvme_zns_identify_ns(fd, cfg.namespace_id, &ns);
+       if (!err)
+               nvme_print_object(nvme_zns_id_ns_to_json(&ns, &id_ns, flags));
+       else
+               nvme_show_status("zns-id-ns", err);
+close_fd:
+       close(fd);
+       return nvme_status_to_errno(err, false);
+}
+
+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) {
+               namespace_id = nvme_get_nsid(fd);
+               if (namespace_id <= 0) {
+                       if (!namespace_id) {
+                               errno = EINVAL;
+                               err = -1;
+                       } else
+                               err = namespace_id;
+                       fprintf(stderr, "Error: retrieving namespace-id\n");
+                       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 *namespace_id = "identifier of desired namespace";
+       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(command, err);
+
+free:
+       free(command);
+       return nvme_status_to_errno(err, false);
+}
+
+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 *namespace_id = "identifier of desired namespace";
+       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 err, fd, ffd = STDIN_FILENO;
+       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()
+       };
+
+       err = 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");
+                       err = -1;
+                       goto close_fd;
+               }
+               memset(buf, 0, cfg.data_len);
+
+               if (cfg.file) {
+                       ffd = open(cfg.file, O_RDONLY);
+                       if (ffd < 0) {
+                               perror(cfg.file);
+                               err = -1;
+                               goto free;
+                       }
+               }
+
+               err = read(ffd, (void *)buf, cfg.data_len);
+               if (err < 0) {
+                       perror("read");
+                       err = -1;
+                       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("zone-mgmt-send", err);
+
+close_ffd:
+       if (cfg.file)
+               close(ffd);
+free:
+       if (buf)
+               free(buf);
+close_fd:
+       close(fd);
+       return nvme_status_to_errno(err, false);
+}
+
+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 *namespace_id = "identifier of desired namespace";
+       const char *data = "optional file for zone extention data (default stdin)";
+
+       int err, fd, ffd = STDIN_FILENO;
+       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()
+       };
+
+       err = fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return errno;
+
+       err = nvme_identify_ns(fd, cfg.namespace_id, &id_ns);
+       if (err) {
+               nvme_show_status("id-ns", err);
+               goto close_fd;
+       }
+
+       err = nvme_zns_identify_ns(fd, cfg.namespace_id, &ns);
+       if (err) {
+               nvme_show_status("zns-id-ns", 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 = malloc(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");
+               err = -1;
+               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("set-zone-desc", err);
+close_ffd:
+       if (cfg.file)
+               close(ffd);
+free:
+       free(buf);
+close_fd:
+       close(fd);
+       return nvme_status_to_errno(err, false);
+}
+
+static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       return 0;
+}
+
+static int report_zones(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       return 0;
+}
+
+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 = 0, fd, dfd = STDIN_FILENO, mfd = STDIN_FILENO;
+       unsigned int lba_size, meta_size;
+       void *buf = NULL, *mbuf = NULL;
+       __u16 nblocks, control = 0;
+       __u64 result;
+
+       nvme_ns_t ns;
+
+       struct config {
+               char  *data;
+               char  *metadata;
+               __u64  zslba;
+               __u64  data_size;
+               __u64  metadata_size;
+               int    limited_retry;
+               int    fua;
+               __u32  ref_tag;
+               __u16  lbat;
+               __u16  lbatm;
+               __u8   prinfo;
+       };
+
+       struct config cfg = {
+       };
+
+       OPT_ARGS(opts) = {
+               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()
+       };
+
+       err = 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;
+               err = -1;
+               goto close_fd;
+       }
+
+       ns = nvme_scan_namespace(devicename);
+       if (!ns) {
+               fprintf(stderr, "Failed to open requested namespace:%s\n",
+                       devicename);
+               errno = EINVAL;
+               err = -1;
+               goto close_fd;
+       }
+
+       lba_size = nvme_ns_get_lba_size(ns);
+       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;
+               err = -1;
+               goto close_ns;
+       }
+
+       meta_size = nvme_ns_get_meta_size(ns);
+       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;
+               err = -1;
+               goto close_ns;
+       }
+
+       if (cfg.prinfo > 0xf) {
+               fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo);
+               errno = EINVAL;
+               err = -1;
+               goto close_ns;
+       }
+
+       if (cfg.data) {
+               dfd = open(cfg.data, O_RDONLY);
+               if (dfd < 0) {
+                       perror(cfg.data);
+                       err = -1;
+                       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);
+               err = -1;
+               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_IO_LR;
+       if (cfg.fua)
+               control |= NVME_IO_FUA;
+
+       printf("sending zone append to %s namespace %d\n", devicename,
+               nvme_ns_get_nsid(ns));
+       err = nvme_zns_append(fd, nvme_ns_get_nsid(ns), 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("zone-append", 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:
+       nvme_free_ns(ns);
+close_fd:
+       close(fd);
+       return err;
+}
+
+static int change_zone_list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       return 0;
+}
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"
+
index 5f708798f78e4e33291a2c5b256a0b23a64b06d9..77a047769ebfa729acc3a259c33196c15d3d28e9 100644 (file)
@@ -917,7 +917,10 @@ static int display_tabular(struct json_object *jso, struct printbuf *p,
        json_object_object_foreach(jso, tkey, tval) {
                (void)tkey;
 
-               if (strlen(tkey) + 1 > len)
+               if (json_object_get_type(tval) == json_type_array) {
+                       if (strlen(tkey) + 4 > len)
+                               len = strlen(tkey) + 4;
+               } else if (strlen(tkey) + 1 > len)
                        len = strlen(tkey) + 1;
        }
 
@@ -4222,8 +4225,8 @@ struct json_object *nvme_resv_report_to_json(
        return jrs;
 }
 
-struct json_object *nvme_zns_id_ctrl_to_json(
-       struct nvme_zns_id_ctrl *ctrl, unsigned long flags)
+struct json_object *nvme_zns_id_ctrl_to_json( struct nvme_zns_id_ctrl *ctrl,
+       unsigned long flags)
 {
        struct json_object *jctrl;
 
@@ -4236,6 +4239,52 @@ struct json_object *nvme_zns_id_ctrl_to_json(
        return jctrl;
 }
 
+static void nvme_json_add_zns_id_ns_lbafe(struct json_object *j,
+       struct nvme_zns_lbafe *lbafe, bool in_use, uint32_t bs,
+       unsigned long flags)
+{
+       struct json_object *jlbaf = nvme_json_new_object(flags);
+
+       if (flags & NVME_JSON_HUMAN)
+               nvme_json_add_size_flags(jlbaf, "zsze",
+                       le64_to_cpu(lbafe->zsze) * bs, flags);
+       else
+               nvme_json_add_le64(jlbaf, "zsze", le64_to_cpu(lbafe->zsze));
+
+       nvme_json_add_size_flags(jlbaf, "zdes", lbafe->zdes, flags);
+       nvme_json_add_bool(jlbaf, "in-use", in_use);
+
+       json_object_array_add(j, jlbaf);
+}
+
+struct json_object *nvme_zns_id_ns_to_json( 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;
+       uint32_t bs = 1 << id_ns->lbaf[lbaf].ds;
+       struct json_object *jns, *jlbafs;
+       int i;
+
+       if (flags & NVME_JSON_BINARY)
+               return nvme_json_new_str_len_flags(ns, sizeof(*ns), flags);
+
+       jns = nvme_json_new_object(flags);
+       nvme_json_add_hex_le16_flags(jns, "zoc", ns->zoc, flags);
+       nvme_json_add_hex_le16_flags(jns, "ozcs", ns->ozcs, flags);
+       nvme_json_add_hex_le32_flags(jns, "mar", ns->mar, flags);
+       nvme_json_add_hex_le32_flags(jns, "mor", ns->mor, flags);
+       nvme_json_add_le32(jns, "rrl", ns->rrl);
+       nvme_json_add_le32(jns, "frl", ns->frl);
+
+       jlbafs = nvme_json_new_array();
+       for (i = 0; i <= id_ns->nlbaf; i++)
+               nvme_json_add_zns_id_ns_lbafe(jlbafs, &ns->lbafe[i], i == lbaf,
+                       bs, flags);
+       json_object_object_add(jns, "lbaf", jlbafs);
+
+       return jns;
+}
+
 static void nvme_show_ns_details(nvme_ns_t n)
 {
        char usage[128] = { 0 }, format[128] = { 0 };
index 0202d78ee0c82d03c0e28c7a78e32204f3b1aeab..59c85cf3cb08b77dc6747ba09ab14c8f0a4c1d19 100644 (file)
@@ -134,10 +134,12 @@ struct json_object *nvme_resv_report_to_json(
        struct nvme_resv_status *status, bool ext,
        unsigned long flags);
 
-struct json_object *nvme_zns_id_ctrl_to_json(
-       struct nvme_zns_id_ctrl *ctrl,
+struct json_object *nvme_zns_id_ctrl_to_json(struct nvme_zns_id_ctrl *ctrl,
        unsigned long flags);
 
+struct json_object *nvme_zns_id_ns_to_json( struct nvme_zns_id_ns *ns,
+       struct nvme_id_ns *id_ns, unsigned long flags);
+
 struct json_object *nvme_json_new_str_len(const char *v, int len);
 struct json_object *nvme_json_new_str_len_flags(const void *v, int len,
        unsigned long flags);