2025-02-16 12:16:06 +01:00
|
|
|
// 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"
|
2025-02-16 12:23:04 +01:00
|
|
|
#include "solidigm-util.h"
|
2025-02-16 12:16:06 +01:00
|
|
|
|
2025-02-16 12:24:03 +01:00
|
|
|
struct __packed gc_item {
|
2025-02-16 12:16:06 +01:00
|
|
|
__le32 timer_type;
|
|
|
|
__le64 timestamp;
|
2025-02-16 12:24:03 +01:00
|
|
|
};
|
2025-02-16 12:16:06 +01:00
|
|
|
|
|
|
|
#define VU_GC_MAX_ITEMS 100
|
2025-02-16 12:24:03 +01:00
|
|
|
struct garbage_control_collection_log {
|
2025-02-16 12:16:06 +01:00
|
|
|
__le16 version_major;
|
|
|
|
__le16 version_minor;
|
2025-02-16 12:24:03 +01:00
|
|
|
struct __packed gc_item item[VU_GC_MAX_ITEMS];
|
2025-02-16 12:16:06 +01:00
|
|
|
__u8 reserved[2892];
|
2025-02-16 12:24:03 +01:00
|
|
|
};
|
2025-02-16 12:16:06 +01:00
|
|
|
|
2025-02-16 12:24:03 +01:00
|
|
|
static void vu_gc_log_show_json(struct garbage_control_collection_log *payload, const char *devname)
|
2025-02-16 12:16:06 +01:00
|
|
|
{
|
|
|
|
struct json_object *gc_entries = json_create_array();
|
|
|
|
|
|
|
|
for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
|
2025-02-16 12:24:03 +01:00
|
|
|
struct __packed gc_item item = payload->item[i];
|
2025-02-16 12:16:06 +01:00
|
|
|
struct json_object *entry = json_create_object();
|
2025-02-16 12:24:03 +01:00
|
|
|
|
2025-02-16 12:16:06 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:24:03 +01:00
|
|
|
static void vu_gc_log_show(struct garbage_control_collection_log *payload, const char *devname,
|
2025-02-16 12:23:04 +01:00
|
|
|
__u8 uuid_index)
|
2025-02-16 12:16:06 +01:00
|
|
|
{
|
2025-02-16 12:23:04 +01:00
|
|
|
printf("Solidigm Garbage Collection Log for NVME device:%s UUID-idx:%d\n", devname,
|
|
|
|
uuid_index);
|
2025-02-16 12:16:06 +01:00
|
|
|
printf("Timestamp Timer Type\n");
|
|
|
|
|
|
|
|
for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
|
2025-02-16 12:24:03 +01:00
|
|
|
struct __packed gc_item item = payload->item[i];
|
|
|
|
|
2025-02-16 12:17:56 +01:00
|
|
|
printf("%-13" PRIu64 " %d\n", le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type));
|
2025-02-16 12:16:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.";
|
2025-02-16 12:17:56 +01:00
|
|
|
struct nvme_dev *dev;
|
|
|
|
int err;
|
2025-02-16 12:23:04 +01:00
|
|
|
__u8 uuid_index;
|
2025-02-16 12:16:06 +01:00
|
|
|
|
|
|
|
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()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:17:56 +01:00
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2025-02-16 12:16:06 +01:00
|
|
|
|
|
|
|
enum nvme_print_flags flags = validate_output_format(cfg.output_format);
|
2025-02-16 12:24:03 +01:00
|
|
|
|
2025-02-16 12:16:06 +01:00
|
|
|
if (flags == -EINVAL) {
|
|
|
|
fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
|
2025-02-16 12:17:56 +01:00
|
|
|
dev_close(dev);
|
2025-02-16 12:24:03 +01:00
|
|
|
return -EINVAL;
|
2025-02-16 12:16:06 +01:00
|
|
|
}
|
|
|
|
|
2025-02-16 12:23:04 +01:00
|
|
|
uuid_index = solidigm_get_vu_uuid_index(dev);
|
|
|
|
|
2025-02-16 12:24:03 +01:00
|
|
|
struct garbage_control_collection_log gc_log;
|
2025-02-16 12:16:06 +01:00
|
|
|
const int solidigm_vu_gc_log_id = 0xfd;
|
2025-02-16 12:23:04 +01:00
|
|
|
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,
|
|
|
|
};
|
2025-02-16 12:16:06 +01:00
|
|
|
|
2025-02-16 12:23:04 +01:00
|
|
|
err = nvme_get_log(&args);
|
2025-02-16 12:16:06 +01:00
|
|
|
if (!err) {
|
2025-02-16 12:24:03 +01:00
|
|
|
if (flags & BINARY)
|
2025-02-16 12:16:06 +01:00
|
|
|
d_raw((unsigned char *)&gc_log, sizeof(gc_log));
|
2025-02-16 12:24:03 +01:00
|
|
|
else if (flags & JSON)
|
2025-02-16 12:17:56 +01:00
|
|
|
vu_gc_log_show_json(&gc_log, dev->name);
|
2025-02-16 12:24:03 +01:00
|
|
|
else
|
2025-02-16 12:23:04 +01:00
|
|
|
vu_gc_log_show(&gc_log, dev->name, uuid_index);
|
2025-02-16 12:24:03 +01:00
|
|
|
} else if (err > 0) {
|
2025-02-16 12:16:06 +01:00
|
|
|
nvme_show_status(err);
|
|
|
|
}
|
2025-02-16 12:17:56 +01:00
|
|
|
|
|
|
|
/* Redundant close() to make static code analysis happy */
|
|
|
|
close(dev->direct.fd);
|
|
|
|
dev_close(dev);
|
2025-02-16 12:16:06 +01:00
|
|
|
return err;
|
|
|
|
}
|