NVME-VERSION-FILE: FORCE
@$(SHELL_PATH) ./NVME-VERSION-GEN
-include NVME-VERSION-FILE
-override CFLAGS += -DNVME_VERSION='"$(NVME_VERSION)"' -I$(LIBNVMEDIR)src/
+override CFLAGS += -DNVME_VERSION='"$(NVME_VERSION)"' -I$(LIBNVMEDIR)src/ -I$(LIBNVMEDIR)/ccan
NVME_DPKG_VERSION=1~`lsb_release -sc`
json_free_object(root);
}
-static void json_effects_log(struct nvme_cmd_effects_log *effects_log)
+struct json_object* json_effects_log(enum nvme_csi csi,
+ struct nvme_cmd_effects_log *effects_log)
{
struct json_object *root;
struct json_object *acs;
__u32 effect;
root = json_create_object();
+ json_object_add_value_uint(root, "command_set_identifier", csi);
+
acs = json_create_object();
for (opcode = 0; opcode < 256; opcode++) {
effect = le32_to_cpu(effects_log->acs[opcode]);
}
json_object_add_value_object(root, "io_cmd_set", iocs);
- json_print_object(root, NULL);
+ return root;
+}
+
+void json_effects_log_list(struct list_head *list) {
+ struct json_object *json_list;
+ nvme_effects_log_node_t *node;
+
+ json_list = json_create_array();
+
+ list_for_each(list, node, node) {
+ json_object *json_page =
+ json_effects_log(node->csi, &node->effects);
+ json_array_add_value_object(json_list, json_page);
+ }
+
+ json_print_object(json_list, NULL);
printf("\n");
- json_free_object(root);
+ json_free_object(json_list);
}
static void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log,
free(stream_location);
}
-void nvme_print_effects_log_page(struct nvme_cmd_effects_log *effects, int flags) {
+void nvme_print_effects_log_page(enum nvme_csi csi, struct nvme_cmd_effects_log *effects, int flags) {
int human = flags & VERBOSE;
+ switch (csi) {
+ case NVME_CSI_NVM:
+ printf("NVM Command Set Log Page\n");
+ printf("%-.80s\n", dash);
+ break;
+ case NVME_CSI_ZNS:
+ printf("ZNS Command Set Log Page\n");
+ printf("%-.80s\n", dash);
+ break;
+ default:
+ printf("Unknown Command Set Log Page\n");
+ printf("%-.80s\n", dash);
+ break;
+ }
+
nvme_print_effects_log_segment(1, 0, 0xbf, effects, "Admin Commands", human);
nvme_print_effects_log_segment(1, 0xc0, 0xff, effects, "Vendor Specific Admin Commands", human);
nvme_print_effects_log_segment(0, 0, 0x80, effects, "I/O Commands", human);
nvme_print_effects_log_segment(0, 0x80, 0x100, effects, "Vendor Specific I/O Commands", human);
}
-void nvme_show_effects_log(struct nvme_cmd_effects_log *effects,
- unsigned int flags)
+void nvme_print_effects_log_pages(struct list_head *list,
+ int flags)
{
- if (flags & BINARY)
- return d_raw((unsigned char *)effects, sizeof(*effects));
- else if (flags & JSON)
- return json_effects_log(effects);
+ if (flags & JSON)
+ return json_effects_log_list(list);
- nvme_print_effects_log_page(effects, flags);
+ nvme_effects_log_node_t *node;
+ list_for_each(list, node, node) {
+ if (flags & BINARY) {
+ d_raw((unsigned char *)&node->effects, sizeof(node->effects));
+ }
+ else {
+ nvme_print_effects_log_page(node->csi, &node->effects, flags);
+ }
+ }
}
uint64_t int48_to_long(__u8 *data)
#include "nvme.h"
#include <inttypes.h>
+#include <ccan/list/list.h>
+
+typedef struct nvme_effects_log_node {
+ enum nvme_csi csi;
+ struct nvme_cmd_effects_log effects;
+ struct list_node node;
+} nvme_effects_log_node_t;
+
void d(unsigned char *buf, int len, int width, int group);
void d_raw(unsigned char *buf, unsigned len);
uint64_t int48_to_long(__u8 *data);
__u32 size, const char *devname, enum nvme_print_flags flags);
void nvme_show_fw_log(struct nvme_firmware_slot *fw_log, const char *devname,
enum nvme_print_flags flags);
-void nvme_show_effects_log(struct nvme_cmd_effects_log *effects, unsigned int flags);
+void nvme_print_effects_log_pages(struct list_head *list, int flags);
void nvme_show_changed_ns_list_log(struct nvme_ns_list *log,
const char *devname, enum nvme_print_flags flags);
void nvme_show_endurance_log(struct nvme_endurance_group_log *endurance_log,
* This program uses NVMe IOCTLs to run native nvme commands to a device.
*/
+#include "nvme/tree.h"
+#include "nvme/types.h"
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
const char *output_format = "Output format: normal|json|binary";
static const char *output_format_no_binary = "Output format: normal|json";
-static void *__nvme_alloc(size_t len, bool *huge)
-{
+static void *mmap_registers(nvme_root_t r, const char *dev);
+
+static void *__nvme_alloc(size_t len, bool *huge) {
void *p;
if (!posix_memalign(&p, getpagesize(), len)) {
return nvme_status_to_errno(err, false);
}
+void collect_effects_log(int fd, enum nvme_csi csi, struct list_head *list, int flags)
+{
+ int err;
+ nvme_effects_log_node_t *node = malloc(sizeof(nvme_effects_log_node_t));
+ if (!node) {
+ perror("Failed to allocate memory");
+ return;
+ }
+ node->csi = csi;
+
+ err = nvme_get_log_cmd_effects(fd, csi, &node->effects);
+ if (!err) {
+ list_add(list, &node->node);
+ return;
+ }
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("effects log page");
+
+ free(node);
+}
+
static int get_effects_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Retrieve command effects log page and print the table.";
const char *raw = "show log in binary format";
const char *human_readable = "show log in readable format";
- struct nvme_cmd_effects_log effects;
+ const char *csi = "";
+ struct list_head log_pages;
+ nvme_effects_log_node_t *node;
+
+ void *bar = NULL;
int err = -1, fd;
enum nvme_print_flags flags;
struct config {
- int raw_binary;
- int human_readable;
- char *output_format;
+ int raw_binary;
+ int human_readable;
+ char *output_format;
+ int csi;
};
struct config cfg = {
.output_format = "normal",
+ .csi = -1,
};
OPT_ARGS(opts) = {
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_INT("csi", 'c', &cfg.csi, csi),
OPT_END()
};
if (cfg.human_readable)
flags |= VERBOSE;
- err = nvme_get_log_cmd_effects(fd, NVME_CSI_NVM, &effects);
- if (!err)
- nvme_show_effects_log(&effects, flags);
- else if (err > 0)
- nvme_show_status(err);
- else
- perror("effects log page");
+ list_head_init(&log_pages);
+
+ if (cfg.csi < 0) {
+ nvme_root_t nvme_root;
+ uint64_t cap_value;
+ int nvme_command_set_supported;
+ int other_command_sets_supported;
+ nvme_root = nvme_scan(NULL);
+ bar = mmap_registers(nvme_root, devicename);
+ nvme_free_tree(nvme_root);
+
+ if (!bar) {
+ goto close_fd;
+ }
+ cap_value = nvme_mmio_read64(bar + NVME_REG_CAP);
+ munmap(bar, getpagesize());
+
+ nvme_command_set_supported = (cap_value & (1UL << 37)) != 0;
+ other_command_sets_supported = (cap_value & (1UL << (37+6))) != 0;
+
+
+ if (nvme_command_set_supported) {
+ collect_effects_log(fd, NVME_CSI_NVM, &log_pages, flags);
+ }
+
+ if (other_command_sets_supported) {
+ collect_effects_log(fd, NVME_CSI_ZNS, &log_pages, flags);
+ }
+
+ nvme_print_effects_log_pages(&log_pages, flags);
+
+ }
+ else {
+ collect_effects_log(fd, cfg.csi, &log_pages, flags);
+ nvme_print_effects_log_pages(&log_pages, flags);
+ }
+
+
close_fd:
+ while ((node = list_pop(&log_pages, nvme_effects_log_node_t, node))) {
+ free(node);
+ }
+
close(fd);
ret:
return nvme_status_to_errno(err, false);