From c9413baf4431d65ef9a7c33df9a2a909bcdcc0fd Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 4 Jun 2020 13:22:47 -0700 Subject: [PATCH] zns Signed-off-by: Keith Busch --- libnvme | 2 +- nvme.c | 52 ++-- plugins/zns/zns.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++ plugins/zns/zns.h | 30 +++ util/user-types.c | 55 ++++- util/user-types.h | 6 +- 6 files changed, 731 insertions(+), 26 deletions(-) create mode 100644 plugins/zns/zns.c create mode 100644 plugins/zns/zns.h diff --git a/libnvme b/libnvme index 5a0b27a..a4c001a 160000 --- a/libnvme +++ b/libnvme @@ -1 +1 @@ -Subproject commit 5a0b27adc70c92ee2c37b09b006d1e4098278e59 +Subproject commit a4c001a47663d0392d2cedfe33a8dec5654fc527 diff --git a/nvme.c b/nvme.c index 2eba494..a2893fb 100644 --- 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 index 0000000..1306152 --- /dev/null +++ b/plugins/zns/zns.c @@ -0,0 +1,612 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..4e9d363 --- /dev/null +++ b/plugins/zns/zns.h @@ -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" + diff --git a/util/user-types.c b/util/user-types.c index 5f70879..77a0477 100644 --- a/util/user-types.c +++ b/util/user-types.c @@ -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 }; diff --git a/util/user-types.h b/util/user-types.h index 0202d78..59c85cf 100644 --- a/util/user-types.h +++ b/util/user-types.h @@ -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); -- 2.50.1