1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2022-2024 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.";
nvme_print_flags_t 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;
}
sldgm_get_uuid_index(dev, &uuid_index);
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;
}
|