summaryrefslogtreecommitdiffstats
path: root/plugins/solidigm/solidigm-garbage-collection.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/solidigm/solidigm-garbage-collection.c')
-rw-r--r--plugins/solidigm/solidigm-garbage-collection.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/plugins/solidigm/solidigm-garbage-collection.c b/plugins/solidigm/solidigm-garbage-collection.c
new file mode 100644
index 0000000..a37e9c5
--- /dev/null
+++ b/plugins/solidigm/solidigm-garbage-collection.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+#include "solidigm-garbage-collection.h"
+#include "solidigm-util.h"
+
+struct __packed gc_item {
+ __le32 timer_type;
+ __le64 timestamp;
+};
+
+#define VU_GC_MAX_ITEMS 100
+struct garbage_control_collection_log {
+ __le16 version_major;
+ __le16 version_minor;
+ struct __packed gc_item item[VU_GC_MAX_ITEMS];
+ __u8 reserved[2892];
+};
+
+static void vu_gc_log_show_json(struct garbage_control_collection_log *payload, const char *devname)
+{
+ struct json_object *gc_entries = json_create_array();
+
+ for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
+ struct __packed gc_item item = payload->item[i];
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_int(entry, "timestamp", le64_to_cpu(item.timestamp));
+ json_object_add_value_int(entry, "timer_type", le32_to_cpu(item.timer_type));
+ json_array_add_value_object(gc_entries, entry);
+ }
+
+ json_print_object(gc_entries, NULL);
+ json_free_object(gc_entries);
+}
+
+static void vu_gc_log_show(struct garbage_control_collection_log *payload, const char *devname,
+ __u8 uuid_index)
+{
+ printf("Solidigm Garbage Collection Log for NVME device:%s UUID-idx:%d\n", devname,
+ uuid_index);
+ printf("Timestamp Timer Type\n");
+
+ for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
+ struct __packed gc_item item = payload->item[i];
+
+ printf("%-13" PRIu64 " %d\n", le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type));
+ }
+}
+
+int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get and parse Solidigm vendor specific garbage collection event log.";
+ enum nvme_print_flags flags;
+ struct nvme_dev *dev;
+ int err;
+ __u8 uuid_index;
+
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err) {
+ fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ uuid_index = solidigm_get_vu_uuid_index(dev);
+
+ struct garbage_control_collection_log gc_log;
+ const int solidigm_vu_gc_log_id = 0xfd;
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = &gc_log,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = solidigm_vu_gc_log_id,
+ .len = sizeof(gc_log),
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_LSP_NONE,
+ .uuidx = uuid_index,
+ .rae = false,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (!err) {
+ if (flags & BINARY)
+ d_raw((unsigned char *)&gc_log, sizeof(gc_log));
+ else if (flags & JSON)
+ vu_gc_log_show_json(&gc_log, dev->name);
+ else
+ vu_gc_log_show(&gc_log, dev->name, uuid_index);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}