diff options
Diffstat (limited to '')
-rw-r--r-- | plugins/fdp/fdp.c | 541 | ||||
-rw-r--r-- | plugins/fdp/fdp.h | 24 |
2 files changed, 565 insertions, 0 deletions
diff --git a/plugins/fdp/fdp.c b/plugins/fdp/fdp.c new file mode 100644 index 0000000..2a221f8 --- /dev/null +++ b/plugins/fdp/fdp.c @@ -0,0 +1,541 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#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 "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "nvme-print.h" + +#define CREATE_CMD +#include "fdp.h" + +static int fdp_configs(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Get Flexible Data Placement Configurations"; + const char *egid = "Endurance group identifier"; + const char *human_readable = "show log in readable format"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_config_log hdr; + void *log = NULL; + int err; + + struct config { + __u16 egid; + char *output_format; + bool human_readable; + bool raw_binary; + }; + + struct config cfg = { + .egid = 0, + .output_format = "normal", + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("endgrp-id", 'e', &cfg.egid, egid), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + if (cfg.human_readable) + flags |= VERBOSE; + + if (!cfg.egid) { + fprintf(stderr, "endurance group identifier required\n"); + err = -EINVAL; + goto out; + } + + err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0, + sizeof(hdr), &hdr); + if (err) { + nvme_show_status(errno); + goto out; + } + + log = malloc(hdr.size); + if (!log) { + err = -ENOMEM; + goto out; + } + + err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0, + hdr.size, log); + if (err) { + nvme_show_status(errno); + goto out; + } + + nvme_show_fdp_configs(log, hdr.size, flags); + +out: + dev_close(dev); + free(log); + + return err; +} + +static int fdp_usage(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Get Flexible Data Placement Reclaim Unit Handle Usage"; + const char *egid = "Endurance group identifier"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_ruhu_log hdr; + size_t len; + void *log = NULL; + int err; + + struct config { + __u16 egid; + char *output_format; + bool raw_binary; + }; + + struct config cfg = { + .egid = 0, + .output_format = "normal", + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("endgrp-id", 'e', &cfg.egid, egid), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid, + 0, sizeof(hdr), &hdr); + if (err) { + nvme_show_status(err); + goto out; + } + + len = sizeof(hdr) + le16_to_cpu(hdr.nruh) * sizeof(struct nvme_fdp_ruhu_desc); + log = malloc(len); + if (!log) { + err = -ENOMEM; + goto out; + } + + err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid, + 0, len, log); + if (err) { + nvme_show_status(err); + goto out; + } + + nvme_show_fdp_usage(log, len, flags); + +out: + dev_close(dev); + free(log); + + return err; +} + +static int fdp_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Get Flexible Data Placement Statistics"; + const char *egid = "Endurance group identifier"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_stats_log stats; + int err; + + struct config { + __u16 egid; + char *output_format; + bool raw_binary; + }; + + struct config cfg = { + .egid = 0, + .output_format = "normal", + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("endgrp-id", 'e', &cfg.egid, egid), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + memset(&stats, 0x0, sizeof(stats)); + + err = nvme_get_log_fdp_stats(dev->direct.fd, cfg.egid, 0, sizeof(stats), &stats); + if (err) { + nvme_show_status(err); + goto out; + } + + nvme_show_fdp_stats(&stats, flags); + +out: + dev_close(dev); + + return err; +} + +static int fdp_events(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Get Flexible Data Placement Events"; + const char *egid = "Endurance group identifier"; + const char *host_events = "Get host events"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_events_log events; + int err; + + struct config { + __u16 egid; + bool host_events; + char *output_format; + bool raw_binary; + }; + + struct config cfg = { + .egid = 0, + .host_events = false, + .output_format = "normal", + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("endgrp-id", 'e', &cfg.egid, egid), + OPT_FLAG("host-events", 'E', &cfg.host_events, host_events), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + memset(&events, 0x0, sizeof(events)); + + err = nvme_get_log_fdp_events(dev->direct.fd, cfg.egid, + cfg.host_events, 0, sizeof(events), &events); + if (err) { + nvme_show_status(err); + goto out; + } + + nvme_show_fdp_events(&events, flags); + +out: + dev_close(dev); + + return err; +} + +static int fdp_status(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Reclaim Unit Handle Status"; + const char *namespace_id = "Namespace identifier"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_ruh_status hdr; + size_t len; + void *buf = NULL; + int err = -1; + + struct config { + __u32 namespace_id; + char *output_format; + bool raw_binary; + }; + + struct config cfg = { + .output_format = "normal", + .raw_binary = false, + }; + + 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("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + perror("get-namespace-id"); + goto out; + } + } + + err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev), + cfg.namespace_id, sizeof(hdr), &hdr); + if (err) { + nvme_show_status(err); + goto out; + } + + len = sizeof(struct nvme_fdp_ruh_status) + + le16_to_cpu(hdr.nruhsd) * sizeof(struct nvme_fdp_ruh_status_desc); + buf = malloc(len); + if (!buf) { + err = -ENOMEM; + goto out; + } + + err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev), + cfg.namespace_id, len, buf); + if (err) { + nvme_show_status(err); + goto out; + } + + nvme_show_fdp_ruh_status(buf, len, flags); + +out: + free(buf); + dev_close(dev); + + return err; +} + +static int fdp_update(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Reclaim Unit Handle Update"; + const char *namespace_id = "Namespace identifier"; + const char *_pids = "Comma-separated list of placement identifiers to update"; + + struct nvme_dev *dev; + unsigned short pids[256]; + __u16 buf[256]; + int npids; + int err = -1; + + struct config { + __u32 namespace_id; + char *pids; + }; + + struct config cfg = { + .pids = "", + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_LIST("pids", 'p', &cfg.pids, _pids), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + npids = argconfig_parse_comma_sep_array_short(cfg.pids, pids, ARRAY_SIZE(pids)); + if (npids < 0) { + perror("could not parse pids"); + err = -EINVAL; + goto out; + } else if (npids == 0) { + fprintf(stderr, "no placement identifiers set\n"); + err = -EINVAL; + goto out; + } + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + perror("get-namespace-id"); + goto out; + } + } + + for (unsigned int i = 0; i < npids; i++) + buf[i] = cpu_to_le16(pids[i]); + + err = nvme_fdp_reclaim_unit_handle_update(dev_fd(dev), cfg.namespace_id, npids, buf); + if (err) { + nvme_show_status(err); + goto out; + } + + printf("update: Success\n"); + +out: + dev_close(dev); + + return err; +} + +static int fdp_set_events(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Enable or disable FDP events"; + const char *namespace_id = "Namespace identifier"; + const char *enable = "Enable/disable event"; + const char *event_types = "Comma-separated list of event types"; + const char *ph = "Placement Handle"; + const char *save = "specifies that the controller shall save the attribute"; + + struct nvme_dev *dev; + int err = -1; + unsigned short evts[255]; + int nev; + __u8 buf[255]; + + struct config { + __u32 namespace_id; + __u16 ph; + char *event_types; + bool enable; + bool save; + }; + + struct config cfg = { + .enable = false, + .save = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_SHRT("placement-handle", 'p', &cfg.ph, ph), + OPT_FLAG("enable", 'e', &cfg.enable, enable), + OPT_FLAG("save", 's', &cfg.save, save), + OPT_LIST("event-types", 't', &cfg.event_types, event_types), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + nev = argconfig_parse_comma_sep_array_short(cfg.event_types, evts, ARRAY_SIZE(evts)); + if (nev < 0) { + perror("could not parse event types"); + err = -EINVAL; + goto out; + } else if (nev == 0) { + fprintf(stderr, "no event types set\n"); + err = -EINVAL; + goto out; + } else if (nev > 255) { + fprintf(stderr, "too many event types (max 255)\n"); + err = -EINVAL; + goto out; + } + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + if (errno != ENOTTY) { + fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); + goto out; + } + + cfg.namespace_id = NVME_NSID_ALL; + } + } + + for (unsigned int i = 0; i < nev; i++) + buf[i] = (__u8)evts[i]; + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = NVME_FEAT_FID_FDP_EVENTS, + .save = cfg.save, + .nsid = cfg.namespace_id, + .cdw11 = (nev << 16) | cfg.ph, + .cdw12 = cfg.enable ? 0x1 : 0x0, + .data_len = sizeof(buf), + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + + err = nvme_set_features(&args); + if (err) { + nvme_show_status(err); + goto out; + } + + printf("set-events: Success\n"); + +out: + dev_close(dev); + + return err; +} diff --git a/plugins/fdp/fdp.h b/plugins/fdp/fdp.h new file mode 100644 index 0000000..f162b32 --- /dev/null +++ b/plugins/fdp/fdp.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#undef CMD_INC_FILE +#define CMD_INC_FILE plugins/fdp/fdp + +#if !defined(FDP_NVME) || defined(CMD_HEADER_MULTI_READ) +#define FDP_NVME + +#include "cmd.h" + +PLUGIN(NAME("fdp", "Manage Flexible Data Placement enabled devices", NVME_VERSION), + COMMAND_LIST( + ENTRY("configs", "List configurations", fdp_configs) + ENTRY("usage", "Show reclaim unit handle usage", fdp_usage) + ENTRY("stats", "Show statistics", fdp_stats) + ENTRY("events", "List events affecting reclaim units and media usage", fdp_events) + ENTRY("status", "Show reclaim unit handle status", fdp_status) + ENTRY("update", "Update a reclaim unit handle", fdp_update) + ENTRY("set-events", "Enabled or disable events", fdp_set_events) + ) +); + +#endif + +#include "define_cmd.h" |