summaryrefslogtreecommitdiffstats
path: root/plugins/fdp/fdp.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plugins/fdp/fdp.c537
1 files changed, 537 insertions, 0 deletions
diff --git a/plugins/fdp/fdp.c b/plugins/fdp/fdp.c
new file mode 100644
index 0000000..9fef271
--- /dev/null
+++ b/plugins/fdp/fdp.c
@@ -0,0 +1,537 @@
+// 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 = flags = validate_output_format(cfg.output_format);
+ 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 = flags = validate_output_format(cfg.output_format);
+ 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 = flags = validate_output_format(cfg.output_format);
+ 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 = flags = validate_output_format(cfg.output_format);
+ 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 = flags = validate_output_format(cfg.output_format);
+ 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 = 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";
+
+ 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;
+ };
+
+ struct config cfg = {
+ .enable = 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_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,
+ .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;
+}