From f2c543b4ccad3b9f8871d952cddf66b3b438595b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 2 Jul 2021 22:49:35 +0200 Subject: Merging upstream version 1.14. Signed-off-by: Daniel Baumann --- nvme-print.c | 1802 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 1632 insertions(+), 170 deletions(-) mode change 100644 => 100755 nvme-print.c (limited to 'nvme-print.c') diff --git a/nvme-print.c b/nvme-print.c old mode 100644 new mode 100755 index 30fca29..b01a842 --- a/nvme-print.c +++ b/nvme-print.c @@ -3,9 +3,10 @@ #include #include #include +#include +#include "nvme.h" #include "nvme-print.h" -#include "util/json.h" #include "nvme-models.h" #include "util/suffix.h" #include "common.h" @@ -43,7 +44,7 @@ static const char *nvme_ana_state_to_string(enum nvme_ana_state state) return "invalid state"; } -static const char *nvme_cmd_to_string(int admin, __u8 opcode) +const char *nvme_cmd_to_string(int admin, __u8 opcode) { if (admin) { switch (opcode) { @@ -73,6 +74,7 @@ static const char *nvme_cmd_to_string(int admin, __u8 opcode) case nvme_admin_security_send: return "Security Send"; case nvme_admin_security_recv: return "Security Receive"; case nvme_admin_sanitize_nvm: return "Sanitize"; + case nvme_admin_get_lba_status: return "Get LBA Status"; } } else { switch (opcode) { @@ -87,6 +89,8 @@ static const char *nvme_cmd_to_string(int admin, __u8 opcode) case nvme_cmd_resv_report: return "Reservation Report"; case nvme_cmd_resv_acquire: return "Reservation Acquire"; case nvme_cmd_resv_release: return "Reservation Release"; + case nvme_cmd_verify: return "Verify"; + case nvme_cmd_copy: return "Copy"; } } @@ -107,38 +111,29 @@ static const char *fw_to_string(__u64 fw) static const char *get_sanitize_log_sstat_status_str(__u16 status) { - const char *str; - switch (status & NVME_SANITIZE_LOG_STATUS_MASK) { case NVME_SANITIZE_LOG_NEVER_SANITIZED: - str = "NVM Subsystem has never been sanitized."; - break; + return "NVM Subsystem has never been sanitized."; case NVME_SANITIZE_LOG_COMPLETED_SUCCESS: - str = "Most Recent Sanitize Command Completed Successfully."; - break; + return "Most Recent Sanitize Command Completed Successfully."; case NVME_SANITIZE_LOG_IN_PROGESS: - str = "Sanitize in Progress."; - break; + return "Sanitize in Progress."; case NVME_SANITIZE_LOG_COMPLETED_FAILED: - str = "Most Recent Sanitize Command Failed."; - break; + return "Most Recent Sanitize Command Failed."; case NVME_SANITIZE_LOG_ND_COMPLETED_SUCCESS: - str = "Most Recent Sanitize Command (No-Deallocate After Sanitize) Completed Successfully."; - break; + return "Most Recent Sanitize Command (No-Deallocate After Sanitize) Completed Successfully."; default: - str = "Unknown."; + return "Unknown"; } - - return str; } -static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode) +static void json_nvme_id_ns(struct nvme_id_ns *ns) { char nguid_buf[2 * sizeof(ns->nguid) + 1], eui64_buf[2 * sizeof(ns->eui64) + 1]; char *nguid = nguid_buf, *eui64 = eui64_buf; struct json_object *root; - struct json_array *lbafs; + struct json_object *lbafs; int i; long double nvmcap = int128_to_double(ns->nvmcap); @@ -176,6 +171,10 @@ static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode) json_object_add_value_int(root, "nows", le16_to_cpu(ns->nows)); } + json_object_add_value_int(root, "mssrl", le16_to_cpu(ns->mssrl)); + json_object_add_value_int(root, "mcl", le32_to_cpu(ns->mcl)); + json_object_add_value_int(root, "msrc", ns->msrc); + json_object_add_value_int(root, "anagrpid", le32_to_cpu(ns->anagrpid)); json_object_add_value_int(root, "endgid", le16_to_cpu(ns->endgid)); @@ -209,11 +208,11 @@ static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode) json_free_object(root); } -static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, +static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, void (*vs)(__u8 *vs, struct json_object *root)) { struct json_object *root; - struct json_array *psds; + struct json_object *psds; long double tnvmcap = int128_to_double(ctrl->tnvmcap); long double unvmcap = int128_to_double(ctrl->unvmcap); @@ -296,7 +295,7 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, json_object_add_value_int(root, "vwc", ctrl->vwc); json_object_add_value_int(root, "awun", le16_to_cpu(ctrl->awun)); json_object_add_value_int(root, "awupf", le16_to_cpu(ctrl->awupf)); - json_object_add_value_int(root, "nvscc", ctrl->nvscc); + json_object_add_value_int(root, "icsvscc", ctrl->icsvscc); json_object_add_value_int(root, "nwpc", ctrl->nwpc); json_object_add_value_int(root, "acwu", le16_to_cpu(ctrl->acwu)); json_object_add_value_int(root, "sgls", le32_to_cpu(ctrl->sgls)); @@ -307,8 +306,9 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, json_object_add_value_int(root, "ioccsz", le32_to_cpu(ctrl->ioccsz)); json_object_add_value_int(root, "iorcsz", le32_to_cpu(ctrl->iorcsz)); json_object_add_value_int(root, "icdoff", le16_to_cpu(ctrl->icdoff)); - json_object_add_value_int(root, "ctrattr", ctrl->ctrattr); + json_object_add_value_int(root, "fcatt", ctrl->fcatt); json_object_add_value_int(root, "msdbd", ctrl->msdbd); + json_object_add_value_int(root, "ofcs", le16_to_cpu(ctrl->ofcs)); psds = json_create_array(); json_object_add_value_array(root, "psds", psds); @@ -353,7 +353,7 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, static void json_error_log(struct nvme_error_log_page *err_log, int entries) { struct json_object *root; - struct json_array *errors; + struct json_object *errors; int i; root = json_create_object(); @@ -370,7 +370,9 @@ static void json_error_log(struct nvme_error_log_page *err_log, int entries) json_object_add_value_int(error, "cmdid", le16_to_cpu(err_log[i].cmdid)); json_object_add_value_int(error, "status_field", - le16_to_cpu(err_log[i].status_field)); + le16_to_cpu(err_log[i].status_field >> 0x1)); + json_object_add_value_int(error, "phase_tag", + le16_to_cpu(err_log[i].status_field & 0x1)); json_object_add_value_int(error, "parm_error_location", le16_to_cpu(err_log[i].parm_error_location)); json_object_add_value_uint(error, "lba", @@ -396,7 +398,7 @@ static void json_nvme_resv_report(struct nvme_reservation_status *status, int bytes, __u32 cdw11) { struct json_object *root; - struct json_array *rcs; + struct json_object *rcs; int i, j, regctl, entries; regctl = status->regctl[0] | (status->regctl[1] << 8); @@ -678,8 +680,8 @@ static void json_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname) int offset = sizeof(struct nvme_ana_rsp_hdr); struct nvme_ana_rsp_hdr *hdr = ana_log; struct nvme_ana_group_desc *ana_desc; - struct json_array *desc_list; - struct json_array *ns_list; + struct json_object *desc_list; + struct json_object *ns_list; struct json_object *desc; struct json_object *nsid; struct json_object *root; @@ -690,7 +692,7 @@ static void json_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname) root = json_create_object(); json_object_add_value_string(root, - "Asynchronous Namespace Access Log for NVMe device", + "Asymmetric Namespace Access Log for NVMe device", devname); json_object_add_value_uint(root, "chgcnt", le64_to_cpu(hdr->chgcnt)); @@ -731,12 +733,13 @@ static void json_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname) json_free_object(root); } -static void json_self_test_log(struct nvme_self_test_log *self_test) +static void json_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries) { struct json_object *valid_attrs; struct json_object *root; - struct json_array *valid; + struct json_object *valid; int i; + __u32 num_entries; root = json_create_object(); json_object_add_value_int(root, "Current Device Self-Test Operation", @@ -745,7 +748,8 @@ static void json_self_test_log(struct nvme_self_test_log *self_test) self_test->crnt_dev_selftest_compln); valid = json_create_array(); - for (i = 0; i < NVME_ST_REPORTS; i++) { + num_entries = min(dst_entries, NVME_ST_REPORTS); + for (i = 0; i < num_entries; i++) { valid_attrs = json_create_object(); json_object_add_value_int(valid_attrs, "Self test result", self_test->result[i].dsts & 0xf); @@ -786,26 +790,36 @@ add: static void json_effects_log(struct nvme_effects_log_page *effects_log) { struct json_object *root; + struct json_object *acs; + struct json_object *iocs; unsigned int opcode; char key[128]; __u32 effect; root = json_create_object(); - + acs = json_create_object(); for (opcode = 0; opcode < 256; opcode++) { - sprintf(key, "ACS%d (%s)", opcode, - nvme_cmd_to_string(1, opcode)); effect = le32_to_cpu(effects_log->acs[opcode]); - json_object_add_value_uint(root, key, effect); + if (effect & NVME_CMD_EFFECTS_CSUPP) { + sprintf(key, "ACS_%u (%s)", opcode, + nvme_cmd_to_string(1, opcode)); + json_object_add_value_uint(acs, key, effect); + } } + json_object_add_value_object(root, "admin_cmd_set", acs); + + iocs = json_create_object(); for (opcode = 0; opcode < 256; opcode++) { - sprintf(key, "IOCS%d (%s)", opcode, - nvme_cmd_to_string(0, opcode)); effect = le32_to_cpu(effects_log->iocs[opcode]); - json_object_add_value_uint(root, key, effect); + if (effect & NVME_CMD_EFFECTS_CSUPP) { + sprintf(key, "IOCS_%u (%s)", opcode, + nvme_cmd_to_string(0, opcode)); + json_object_add_value_uint(iocs, key, effect); + } } + json_object_add_value_object(root, "io_cmd_set", iocs); json_print_object(root, NULL); printf("\n"); json_free_object(root); @@ -860,6 +874,915 @@ static void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log, json_free_object(root); } +void json_predictable_latency_per_nvmset( + struct nvme_predlat_per_nvmset_log_page *plpns_log, + __u16 nvmset_id) +{ + struct json_object *root; + + root = json_create_object(); + json_object_add_value_uint(root, "nvmset_id", + le16_to_cpu(nvmset_id)); + json_object_add_value_uint(root, "status", + plpns_log->status); + json_object_add_value_uint(root, "event_type", + le16_to_cpu(plpns_log->event_type)); + json_object_add_value_uint(root, "dtwin_reads_typical", + le64_to_cpu(plpns_log->dtwin_rtyp)); + json_object_add_value_uint(root, "dtwin_writes_typical", + le64_to_cpu(plpns_log->dtwin_wtyp)); + json_object_add_value_uint(root, "dtwin_time_maximum", + le64_to_cpu(plpns_log->dtwin_timemax)); + json_object_add_value_uint(root, "ndwin_time_minimum_high", + le64_to_cpu(plpns_log->ndwin_timemin_high)); + json_object_add_value_uint(root, "ndwin_time_minimum_low", + le64_to_cpu(plpns_log->ndwin_timemin_low)); + json_object_add_value_uint(root, "dtwin_reads_estimate", + le64_to_cpu(plpns_log->dtwin_restimate)); + json_object_add_value_uint(root, "dtwin_writes_estimate", + le64_to_cpu(plpns_log->dtwin_westimate)); + json_object_add_value_uint(root, "dtwin_time_estimate", + le64_to_cpu(plpns_log->dtwin_testimate)); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_predictable_latency_per_nvmset( + struct nvme_predlat_per_nvmset_log_page *plpns_log, + __u16 nvmset_id, const char *devname, + enum nvme_print_flags flags) +{ + if (flags & BINARY) + return d_raw((unsigned char *)plpns_log, + sizeof(*plpns_log)); + if (flags & JSON) + return json_predictable_latency_per_nvmset(plpns_log, + nvmset_id); + + printf("Predictable Latency Per NVM Set Log for device: %s\n", + devname); + printf("Predictable Latency Per NVM Set Log for NVM Set ID: %u\n", + le16_to_cpu(nvmset_id)); + printf("Status: %u\n", plpns_log->status); + printf("Event Type: %u\n", + le16_to_cpu(plpns_log->event_type)); + printf("DTWIN Reads Typical: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_rtyp)); + printf("DTWIN Writes Typical: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_wtyp)); + printf("DTWIN Time Maximum: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_timemax)); + printf("NDWIN Time Minimum High: %"PRIu64" \n", + le64_to_cpu(plpns_log->ndwin_timemin_high)); + printf("NDWIN Time Minimum Low: %"PRIu64"\n", + le64_to_cpu(plpns_log->ndwin_timemin_low)); + printf("DTWIN Reads Estimate: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_restimate)); + printf("DTWIN Writes Estimate: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_westimate)); + printf("DTWIN Time Estimate: %"PRIu64"\n\n\n", + le64_to_cpu(plpns_log->dtwin_testimate)); +} + +void json_predictable_latency_event_agg_log( + struct nvme_event_agg_log_page *pea_log, + __u64 log_entries) +{ + struct json_object *root; + struct json_object *valid_attrs; + struct json_object *valid; + __u64 num_iter; + __u64 num_entries; + + root = json_create_object(); + num_entries = le64_to_cpu(pea_log->num_entries); + json_object_add_value_uint(root, "num_entries_avail", + num_entries); + valid = json_create_array(); + + num_iter = min(num_entries, log_entries); + for (int i = 0; i < num_iter; i++) { + valid_attrs = json_create_object(); + json_object_add_value_uint(valid_attrs, "entry", + le16_to_cpu(pea_log->entries[i])); + json_array_add_value_object(valid, valid_attrs); + } + json_object_add_value_array(root, "list_of_entries", valid); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_predictable_latency_event_agg_log( + struct nvme_event_agg_log_page *pea_log, + __u64 log_entries, __u32 size, const char *devname, + enum nvme_print_flags flags) +{ + __u64 num_iter; + __u64 num_entries; + + if (flags & BINARY) + return d_raw((unsigned char *)pea_log, size); + if (flags & JSON) + return json_predictable_latency_event_agg_log(pea_log, + log_entries); + + num_entries = le64_to_cpu(pea_log->num_entries); + printf("Predictable Latency Event Aggregate Log for"\ + " device: %s\n", devname); + + printf("Number of Entries Available: %"PRIu64"\n", + (uint64_t)num_entries); + + num_iter = min(num_entries, log_entries); + for (int i = 0; i < num_iter; i++) { + printf("Entry[%d]: %u\n", i + 1, + le16_to_cpu(pea_log->entries[i])); + } +} + +static const char *nvme_show_nss_hw_error(__u16 error_code) +{ + switch (error_code) { + case 0x01: + return "PCIe Correctable Error"; + case 0x02: + return "PCIe Uncorrectable Non fatal Error"; + case 0x03: + return "PCIe Uncorrectable Fatal Error"; + case 0x04: + return "PCIe Link Status Change"; + case 0x05: + return "PCIe Link Not Active"; + case 0x06: + return "Critical Warning Condition"; + case 0x07: + return "Endurance Group Critical Warning Condition"; + case 0x08: + return "Unsafe Shutdown"; + case 0x09: + return "Controller Fatal Status"; + case 0xA: + return "Media and Data Integrity Status"; + default: + return "Reserved"; + } +} + +void json_persistent_event_log(void *pevent_log_info, __u32 size) +{ + struct json_object *root; + struct json_object *valid_attrs; + struct json_object *valid; + __u32 offset, por_info_len, por_info_list; + __u64 *fw_rev; + char key[128]; + struct nvme_smart_log *smart_event; + struct nvme_fw_commit_event *fw_commit_event; + struct nvme_time_stamp_change_event *ts_change_event; + struct nvme_power_on_reset_info_list *por_event; + struct nvme_nss_hw_err_event *nss_hw_err_event; + struct nvme_change_ns_event *ns_event; + struct nvme_format_nvm_start_event *format_start_event; + struct nvme_format_nvm_compln_event *format_cmpln_event; + struct nvme_sanitize_start_event *sanitize_start_event; + struct nvme_sanitize_compln_event *sanitize_cmpln_event; + struct nvme_thermal_exc_event *thermal_exc_event; + struct nvme_persistent_event_log_head *pevent_log_head; + struct nvme_persistent_event_entry_head *pevent_entry_head; + + root = json_create_object(); + valid = json_create_array(); + + offset = sizeof(*pevent_log_head); + if (size >= offset) { + pevent_log_head = pevent_log_info; + char sn[sizeof(pevent_log_head->sn) + 1], + mn[sizeof(pevent_log_head->mn) + 1], + subnqn[sizeof(pevent_log_head->subnqn) + 1]; + + snprintf(sn, sizeof(sn), "%-.*s", + (int)sizeof(pevent_log_head->sn), pevent_log_head->sn); + snprintf(mn, sizeof(mn), "%-.*s", + (int)sizeof(pevent_log_head->mn), pevent_log_head->mn); + snprintf(subnqn, sizeof(subnqn), "%-.*s", + (int)sizeof(pevent_log_head->subnqn), pevent_log_head->subnqn); + + json_object_add_value_uint(root, "log_id", + pevent_log_head->log_id); + json_object_add_value_uint(root, "total_num_of_events", + le32_to_cpu(pevent_log_head->tnev)); + json_object_add_value_uint(root, "total_log_len", + le64_to_cpu(pevent_log_head->tll)); + json_object_add_value_uint(root, "log_revision", + pevent_log_head->log_rev); + json_object_add_value_uint(root, "log_header_len", + le16_to_cpu(pevent_log_head->head_len)); + json_object_add_value_uint(root, "timestamp", + le64_to_cpu(pevent_log_head->timestamp)); + json_object_add_value_float(root, "power_on_hours", + int128_to_double(pevent_log_head->poh)); + json_object_add_value_uint(root, "power_cycle_count", + le64_to_cpu(pevent_log_head->pcc)); + json_object_add_value_uint(root, "pci_vid", + le16_to_cpu(pevent_log_head->vid)); + json_object_add_value_uint(root, "pci_ssvid", + le16_to_cpu(pevent_log_head->ssvid)); + json_object_add_value_string(root, "sn", sn); + json_object_add_value_string(root, "mn", mn); + json_object_add_value_string(root, "subnqn", subnqn); + for (int i = 0; i < 32; i++) { + if (pevent_log_head->supp_event_bm[i] == 0) + continue; + sprintf(key, "bitmap_%d", i); + json_object_add_value_uint(root, key, + pevent_log_head->supp_event_bm[i]); + } + } else { + printf("No log data can be shown with this log len at least " \ + "512 bytes is required or can be 0 to read the complete "\ + "log page after context established\n"); + return; + } + for (int i = 0; i < le32_to_cpu(pevent_log_head->tnev); i++) { + if (offset + sizeof(*pevent_entry_head) >= size) + break; + + pevent_entry_head = pevent_log_info + offset; + + if ((offset + pevent_entry_head->ehl + 3 + + le16_to_cpu(pevent_entry_head->el)) >= size) + break; + valid_attrs = json_create_object(); + + json_object_add_value_uint(valid_attrs, "event_type", + pevent_entry_head->etype); + json_object_add_value_uint(valid_attrs, "event_type_rev", + pevent_entry_head->etype_rev); + json_object_add_value_uint(valid_attrs, "event_header_len", + pevent_entry_head->ehl); + json_object_add_value_uint(valid_attrs, "ctrl_id", + le16_to_cpu(pevent_entry_head->ctrl_id)); + json_object_add_value_uint(valid_attrs, "event_time_stamp", + le64_to_cpu(pevent_entry_head->etimestamp)); + json_object_add_value_uint(valid_attrs, "vu_info_len", + le16_to_cpu(pevent_entry_head->vsil)); + json_object_add_value_uint(valid_attrs, "event_len", + le16_to_cpu(pevent_entry_head->el)); + + offset += pevent_entry_head->ehl + 3; + + switch (pevent_entry_head->etype) { + case NVME_SMART_HEALTH_EVENT: + smart_event = pevent_log_info + offset; + unsigned int temperature = ((smart_event->temperature[1] << 8) | + smart_event->temperature[0]); + + long double data_units_read = int128_to_double(smart_event->data_units_read); + long double data_units_written = int128_to_double(smart_event->data_units_written); + long double host_read_commands = int128_to_double(smart_event->host_reads); + long double host_write_commands = int128_to_double(smart_event->host_writes); + long double controller_busy_time = int128_to_double(smart_event->ctrl_busy_time); + long double power_cycles = int128_to_double(smart_event->power_cycles); + long double power_on_hours = int128_to_double(smart_event->power_on_hours); + long double unsafe_shutdowns = int128_to_double(smart_event->unsafe_shutdowns); + long double media_errors = int128_to_double(smart_event->media_errors); + long double num_err_log_entries = int128_to_double(smart_event->num_err_log_entries); + json_object_add_value_int(valid_attrs, "critical_warning", + smart_event->critical_warning); + + json_object_add_value_int(valid_attrs, "temperature", + temperature); + json_object_add_value_int(valid_attrs, "avail_spare", + smart_event->avail_spare); + json_object_add_value_int(valid_attrs, "spare_thresh", + smart_event->spare_thresh); + json_object_add_value_int(valid_attrs, "percent_used", + smart_event->percent_used); + json_object_add_value_int(valid_attrs, + "endurance_grp_critical_warning_summary", + smart_event->endu_grp_crit_warn_sumry); + json_object_add_value_float(valid_attrs, "data_units_read", + data_units_read); + json_object_add_value_float(valid_attrs, "data_units_written", + data_units_written); + json_object_add_value_float(valid_attrs, "host_read_commands", + host_read_commands); + json_object_add_value_float(valid_attrs, "host_write_commands", + host_write_commands); + json_object_add_value_float(valid_attrs, "controller_busy_time", + controller_busy_time); + json_object_add_value_float(valid_attrs, "power_cycles", + power_cycles); + json_object_add_value_float(valid_attrs, "power_on_hours", + power_on_hours); + json_object_add_value_float(valid_attrs, "unsafe_shutdowns", + unsafe_shutdowns); + json_object_add_value_float(valid_attrs, "media_errors", + media_errors); + json_object_add_value_float(valid_attrs, "num_err_log_entries", + num_err_log_entries); + json_object_add_value_uint(valid_attrs, "warning_temp_time", + le32_to_cpu(smart_event->warning_temp_time)); + json_object_add_value_uint(valid_attrs, "critical_comp_time", + le32_to_cpu(smart_event->critical_comp_time)); + + for (int c = 0; c < 8; c++) { + __s32 temp = le16_to_cpu(smart_event->temp_sensor[c]); + if (temp == 0) + continue; + sprintf(key, "temperature_sensor_%d",c + 1); + json_object_add_value_int(valid_attrs, key, temp); + } + + json_object_add_value_uint(valid_attrs, "thm_temp1_trans_count", + le32_to_cpu(smart_event->thm_temp1_trans_count)); + json_object_add_value_uint(valid_attrs, "thm_temp2_trans_count", + le32_to_cpu(smart_event->thm_temp2_trans_count)); + json_object_add_value_uint(valid_attrs, "thm_temp1_total_time", + le32_to_cpu(smart_event->thm_temp1_total_time)); + json_object_add_value_uint(valid_attrs, "thm_temp2_total_time", + le32_to_cpu(smart_event->thm_temp2_total_time)); + break; + case NVME_FW_COMMIT_EVENT: + fw_commit_event = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "old_fw_rev", + le64_to_cpu(fw_commit_event->old_fw_rev)); + json_object_add_value_uint(valid_attrs, "new_fw_rev", + le64_to_cpu(fw_commit_event->new_fw_rev)); + json_object_add_value_uint(valid_attrs, "fw_commit_action", + fw_commit_event->fw_commit_action); + json_object_add_value_uint(valid_attrs, "fw_slot", + fw_commit_event->fw_slot); + json_object_add_value_uint(valid_attrs, "sct_fw", + fw_commit_event->sct_fw); + json_object_add_value_uint(valid_attrs, "sc_fw", + fw_commit_event->sc_fw); + json_object_add_value_uint(valid_attrs, + "vu_assign_fw_commit_rc", + le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc)); + break; + case NVME_TIMESTAMP_EVENT: + ts_change_event = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "prev_ts", + le64_to_cpu(ts_change_event->previous_timestamp)); + json_object_add_value_uint(valid_attrs, + "ml_secs_since_reset", + le64_to_cpu(ts_change_event->ml_secs_since_reset)); + break; + case NVME_POWER_ON_RESET_EVENT: + por_info_len = (le16_to_cpu(pevent_entry_head->el) - + le16_to_cpu(pevent_entry_head->vsil) - sizeof(*fw_rev)); + + por_info_list = por_info_len / sizeof(*por_event); + + fw_rev = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "fw_rev", + le64_to_cpu(*fw_rev)); + for (int i = 0; i < por_info_list; i++) { + por_event = pevent_log_info + offset + + sizeof(*fw_rev) + i * sizeof(*por_event); + json_object_add_value_uint(valid_attrs, "ctrl_id", + le16_to_cpu(por_event->cid)); + json_object_add_value_uint(valid_attrs, "fw_act", + por_event->fw_act); + json_object_add_value_uint(valid_attrs, "op_in_prog", + por_event->op_in_prog); + json_object_add_value_uint(valid_attrs, "ctrl_power_cycle", + le32_to_cpu(por_event->ctrl_power_cycle)); + json_object_add_value_uint(valid_attrs, "power_on_ml_secs", + le64_to_cpu(por_event->power_on_ml_seconds)); + json_object_add_value_uint(valid_attrs, "ctrl_time_stamp", + le64_to_cpu(por_event->ctrl_time_stamp)); + } + break; + case NVME_NSS_HW_ERROR_EVENT: + nss_hw_err_event = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "nss_hw_err_code", + le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code)); + break; + case NVME_CHANGE_NS_EVENT: + ns_event = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "nsmgt_cdw10", + le32_to_cpu(ns_event->nsmgt_cdw10)); + json_object_add_value_uint(valid_attrs, "nsze", + le64_to_cpu(ns_event->nsze)); + json_object_add_value_uint(valid_attrs, "nscap", + le64_to_cpu(ns_event->nscap)); + json_object_add_value_uint(valid_attrs, "flbas", + ns_event->flbas); + json_object_add_value_uint(valid_attrs, "dps", + ns_event->dps); + json_object_add_value_uint(valid_attrs, "nmic", + ns_event->nmic); + json_object_add_value_uint(valid_attrs, "ana_grp_id", + le32_to_cpu(ns_event->ana_grp_id)); + json_object_add_value_uint(valid_attrs, "nvmset_id", + le16_to_cpu(ns_event->nvmset_id)); + json_object_add_value_uint(valid_attrs, "nsid", + le32_to_cpu(ns_event->nsid)); + break; + case NVME_FORMAT_START_EVENT: + format_start_event = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "nsid", + le32_to_cpu(format_start_event->nsid)); + json_object_add_value_uint(valid_attrs, "fna", + format_start_event->fna); + json_object_add_value_uint(valid_attrs, "format_nvm_cdw10", + le32_to_cpu(format_start_event->format_nvm_cdw10)); + break; + case NVME_FORMAT_COMPLETION_EVENT: + format_cmpln_event = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "nsid", + le32_to_cpu(format_cmpln_event->nsid)); + json_object_add_value_uint(valid_attrs, "smallest_fpi", + format_cmpln_event->smallest_fpi); + json_object_add_value_uint(valid_attrs, "format_nvm_status", + format_cmpln_event->format_nvm_status); + json_object_add_value_uint(valid_attrs, "compln_info", + le16_to_cpu(format_cmpln_event->compln_info)); + json_object_add_value_uint(valid_attrs, "status_field", + le32_to_cpu(format_cmpln_event->status_field)); + break; + case NVME_SANITIZE_START_EVENT: + sanitize_start_event = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "SANICAP", + le32_to_cpu(sanitize_start_event->sani_cap)); + json_object_add_value_uint(valid_attrs, "sani_cdw10", + le32_to_cpu(sanitize_start_event->sani_cdw10)); + json_object_add_value_uint(valid_attrs, "sani_cdw11", + le32_to_cpu(sanitize_start_event->sani_cdw11)); + break; + case NVME_SANITIZE_COMPLETION_EVENT: + sanitize_cmpln_event = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "sani_prog", + le16_to_cpu(sanitize_cmpln_event->sani_prog)); + json_object_add_value_uint(valid_attrs, "sani_status", + le16_to_cpu(sanitize_cmpln_event->sani_status)); + json_object_add_value_uint(valid_attrs, "cmpln_info", + le16_to_cpu(sanitize_cmpln_event->cmpln_info)); + break; + case NVME_THERMAL_EXCURSION_EVENT: + thermal_exc_event = pevent_log_info + offset; + json_object_add_value_uint(valid_attrs, "over_temp", + thermal_exc_event->over_temp); + json_object_add_value_uint(valid_attrs, "threshold", + thermal_exc_event->threshold); + break; + } + + json_array_add_value_object(valid, valid_attrs); + offset += le16_to_cpu(pevent_entry_head->el); + } + + json_object_add_value_array(root, "list_of_event_entries", valid); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_persistent_event_log(void *pevent_log_info, + __u8 action, __u32 size, const char *devname, + enum nvme_print_flags flags) +{ + __u32 offset, por_info_len, por_info_list; + __u64 *fw_rev; + struct nvme_smart_log *smart_event; + struct nvme_fw_commit_event *fw_commit_event; + struct nvme_time_stamp_change_event *ts_change_event; + struct nvme_power_on_reset_info_list *por_event; + struct nvme_nss_hw_err_event *nss_hw_err_event; + struct nvme_change_ns_event *ns_event; + struct nvme_format_nvm_start_event *format_start_event; + struct nvme_format_nvm_compln_event *format_cmpln_event; + struct nvme_sanitize_start_event *sanitize_start_event; + struct nvme_sanitize_compln_event *sanitize_cmpln_event; + struct nvme_thermal_exc_event *thermal_exc_event; + struct nvme_persistent_event_log_head *pevent_log_head; + struct nvme_persistent_event_entry_head *pevent_entry_head; + + if (flags & BINARY) + return d_raw((unsigned char *)pevent_log_info, size); + if (flags & JSON) + return json_persistent_event_log(pevent_log_info, size); + + offset = sizeof(*pevent_log_head); + + printf("Persistent Event Log for device: %s\n", devname); + printf("Action for Persistent Event Log: %u\n", action); + if (size >= offset) { + pevent_log_head = pevent_log_info; + printf("Log Identifier: %u\n", pevent_log_head->log_id); + printf("Total Number of Events: %u\n", + le32_to_cpu(pevent_log_head->tnev)); + printf("Total Log Length : %"PRIu64"\n", + le64_to_cpu(pevent_log_head->tll)); + printf("Log Revision: %u\n", pevent_log_head->log_rev); + printf("Log Header Length: %u\n", pevent_log_head->head_len); + printf("Timestamp: %"PRIu64"\n", + le64_to_cpu(pevent_log_head->timestamp)); + printf("Power On Hours (POH): %'.0Lf\n", + int128_to_double(pevent_log_head->poh)); + printf("Power Cycle Count: %"PRIu64"\n", + le64_to_cpu(pevent_log_head->pcc)); + printf("PCI Vendor ID (VID): %u\n", + le16_to_cpu(pevent_log_head->vid)); + printf("PCI Subsystem Vendor ID (SSVID): %u\n", + le16_to_cpu(pevent_log_head->ssvid)); + printf("Serial Number (SN): %-.*s\n", + (int)sizeof(pevent_log_head->sn), pevent_log_head->sn); + printf("Model Number (MN): %-.*s\n", + (int)sizeof(pevent_log_head->mn), pevent_log_head->mn); + printf("NVM Subsystem NVMe Qualified Name (SUBNQN): %-.*s\n", + (int)sizeof(pevent_log_head->subnqn), + pevent_log_head->subnqn); + printf("Supported Events Bitmap: "); + for (int i = 0; i < 32; i++) { + if (pevent_log_head->supp_event_bm[i] == 0) + continue; + printf("BitMap[%d] is 0x%x\n", i, + pevent_log_head->supp_event_bm[i]); + } + } else { + printf("No log data can be shown with this log len at least " \ + "512 bytes is required or can be 0 to read the complete "\ + "log page after context established\n"); + return; + } + printf("\n"); + printf("\nPersistent Event Entries:\n"); + for (int i = 0; i < le32_to_cpu(pevent_log_head->tnev); i++) { + if (offset + sizeof(*pevent_entry_head) >= size) + break; + + pevent_entry_head = pevent_log_info + offset; + + if ((offset + pevent_entry_head->ehl + 3 + + le16_to_cpu(pevent_entry_head->el)) >= size) + break; + + printf("Event Type: %u\n", pevent_entry_head->etype); + printf("Event Type Revision: %u\n", pevent_entry_head->etype_rev); + printf("Event Header Length: %u\n", pevent_entry_head->ehl); + printf("Controller Identifier: %u\n", + le16_to_cpu(pevent_entry_head->ctrl_id)); + printf("Event Timestamp: %"PRIu64"\n", + le64_to_cpu(pevent_entry_head->etimestamp)); + printf("Vendor Specific Information Length: %u\n", + le16_to_cpu(pevent_entry_head->vsil)); + printf("Event Length: %u\n", le16_to_cpu(pevent_entry_head->el)); + + offset += pevent_entry_head->ehl + 3; + + switch (pevent_entry_head->etype) { + case NVME_SMART_HEALTH_EVENT: + smart_event = pevent_log_info + offset; + printf("Smart Health Event: \n"); + nvme_show_smart_log(smart_event, NVME_NSID_ALL, devname, flags); + break; + case NVME_FW_COMMIT_EVENT: + fw_commit_event = pevent_log_info + offset; + printf("FW Commit Event: \n"); + printf("Old Firmware Revision: %"PRIu64"\n", + le64_to_cpu(fw_commit_event->old_fw_rev)); + printf("New Firmware Revision: %"PRIu64"\n", + le64_to_cpu(fw_commit_event->new_fw_rev)); + printf("FW Commit Action: %u\n", + fw_commit_event->fw_commit_action); + printf("FW Slot: %u\n", fw_commit_event->fw_slot); + printf("Status Code Type for Firmware Commit Command: %u\n", + fw_commit_event->sct_fw); + printf("Status Returned for Firmware Commit Command: %u\n", + fw_commit_event->sc_fw); + printf("Vendor Assigned Firmware Commit Result Code: %u\n", + le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc)); + break; + case NVME_TIMESTAMP_EVENT: + ts_change_event = pevent_log_info + offset; + printf("Time Stamp Change Event: \n"); + printf("Previous Timestamp: %"PRIu64"\n", + le64_to_cpu(ts_change_event->previous_timestamp)); + printf("Milliseconds Since Reset: %"PRIu64"\n", + le64_to_cpu(ts_change_event->ml_secs_since_reset)); + break; + case NVME_POWER_ON_RESET_EVENT: + por_info_len = (le16_to_cpu(pevent_entry_head->el) - + le16_to_cpu(pevent_entry_head->vsil) - sizeof(*fw_rev)); + + por_info_list = por_info_len / sizeof(*por_event); + + printf("Power On Reset Event: \n"); + fw_rev = pevent_log_info + offset; + printf("Firmware Revision: %"PRIu64"\n", le64_to_cpu(*fw_rev)); + printf("Reset Information List: \n"); + + for (int i = 0; i < por_info_list; i++) { + por_event = pevent_log_info + offset + + sizeof(*fw_rev) + i * sizeof(*por_event); + printf("Controller ID: %u\n", le16_to_cpu(por_event->cid)); + printf("Firmware Activation: %u\n", + por_event->fw_act); + printf("Operation in Progress: %u\n", + por_event->op_in_prog); + printf("Controller Power Cycle: %u\n", + le32_to_cpu(por_event->ctrl_power_cycle)); + printf("Power on milliseconds: %"PRIu64"\n", + le64_to_cpu(por_event->power_on_ml_seconds)); + printf("Controller Timestamp: %"PRIu64"\n", + le64_to_cpu(por_event->ctrl_time_stamp)); + } + break; + case NVME_NSS_HW_ERROR_EVENT: + nss_hw_err_event = pevent_log_info + offset; + printf("NVM Subsystem Hardware Error Event Code: %u, %s\n", + le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code), + nvme_show_nss_hw_error(nss_hw_err_event->nss_hw_err_event_code)); + break; + case NVME_CHANGE_NS_EVENT: + ns_event = pevent_log_info + offset; + printf("Change Namespace Event: \n"); + printf("Namespace Management CDW10: %u\n", + le32_to_cpu(ns_event->nsmgt_cdw10)); + printf("Namespace Size: %"PRIu64"\n", + le64_to_cpu(ns_event->nsze)); + printf("Namespace Capacity: %"PRIu64"\n", + le64_to_cpu(ns_event->nscap)); + printf("Formatted LBA Size: %u\n", ns_event->flbas); + printf("End-to-end Data Protection Type Settings: %u\n", + ns_event->dps); + printf("Namespace Multi-path I/O and Namespace Sharing" \ + " Capabilities: %u\n", ns_event->nmic); + printf("ANA Group Identifier: %u\n", + le32_to_cpu(ns_event->ana_grp_id)); + printf("NVM Set Identifier: %u\n", le16_to_cpu(ns_event->nvmset_id)); + printf("Namespace ID: %u\n", le32_to_cpu(ns_event->nsid)); + break; + case NVME_FORMAT_START_EVENT: + format_start_event = pevent_log_info + offset; + printf("Format NVM Start Event: \n"); + printf("Namespace Identifier: %u\n", + le32_to_cpu(format_start_event->nsid)); + printf("Format NVM Attributes: %u\n", + format_start_event->fna); + printf("Format NVM CDW10: %u\n", + le32_to_cpu(format_start_event->format_nvm_cdw10)); + break; + case NVME_FORMAT_COMPLETION_EVENT: + format_cmpln_event = pevent_log_info + offset; + printf("Format NVM Completion Event: \n"); + printf("Namespace Identifier: %u\n", + le32_to_cpu(format_cmpln_event->nsid)); + printf("Smallest Format Progress Indicator: %u\n", + format_cmpln_event->smallest_fpi); + printf("Format NVM Status: %u\n", + format_cmpln_event->format_nvm_status); + printf("Completion Information: %u\n", + le16_to_cpu(format_cmpln_event->compln_info)); + printf("Status Field: %u\n", + le32_to_cpu(format_cmpln_event->status_field)); + break; + case NVME_SANITIZE_START_EVENT: + sanitize_start_event = pevent_log_info + offset; + printf("Sanitize Start Event: \n"); + printf("SANICAP: %u\n", sanitize_start_event->sani_cap); + printf("Sanitize CDW10: %u\n", + le32_to_cpu(sanitize_start_event->sani_cdw10)); + printf("Sanitize CDW11: %u\n", + le32_to_cpu(sanitize_start_event->sani_cdw11)); + break; + case NVME_SANITIZE_COMPLETION_EVENT: + sanitize_cmpln_event = pevent_log_info + offset; + printf("Sanitize Completion Event: \n"); + printf("Sanitize Progress: %u\n", + le16_to_cpu(sanitize_cmpln_event->sani_prog)); + printf("Sanitize Status: %u\n", + le16_to_cpu(sanitize_cmpln_event->sani_status)); + printf("Completion Information: %u\n", + le16_to_cpu(sanitize_cmpln_event->cmpln_info)); + break; + case NVME_THERMAL_EXCURSION_EVENT: + thermal_exc_event = pevent_log_info + offset; + printf("Thermal Excursion Event: \n"); + printf("Over Temperature: %u\n", thermal_exc_event->over_temp); + printf("Threshold: %u\n", thermal_exc_event->threshold); + break; + default: + printf("Reserved Event\n\n"); + } + offset += le16_to_cpu(pevent_entry_head->el); + printf("\n"); + } +} + +void json_endurance_group_event_agg_log( + struct nvme_event_agg_log_page *endurance_log, + __u64 log_entries) +{ + struct json_object *root; + struct json_object *valid_attrs; + struct json_object *valid; + + root = json_create_object(); + json_object_add_value_uint(root, "num_entries_avail", + le64_to_cpu(endurance_log->num_entries)); + valid = json_create_array(); + + for (int i = 0; i < log_entries; i++) { + valid_attrs = json_create_object(); + json_object_add_value_uint(valid_attrs, "entry", + le16_to_cpu(endurance_log->entries[i])); + json_array_add_value_object(valid, valid_attrs); + } + json_object_add_value_array(root, "list_of_entries", valid); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_endurance_group_event_agg_log( + struct nvme_event_agg_log_page *endurance_log, + __u64 log_entries, __u32 size, const char *devname, + enum nvme_print_flags flags) +{ + + if (flags & BINARY) + return d_raw((unsigned char *)endurance_log, size); + if (flags & JSON) + return json_endurance_group_event_agg_log(endurance_log, + log_entries); + + printf("Endurance Group Event Aggregate Log for"\ + " device: %s\n", devname); + + printf("Number of Entries Available: %"PRIu64"\n", + le64_to_cpu(endurance_log->num_entries)); + + for (int i = 0; i < log_entries; i++) { + printf("Entry[%d]: %u\n", i + 1, + le16_to_cpu(endurance_log->entries[i])); + } +} + +void json_lba_status_log(void *lba_status) +{ + struct json_object *root; + struct json_object *desc; + struct json_object *element; + struct json_object *desc_list; + struct json_object *elements_list; + struct nvme_lba_status_hdr *hdr; + struct nvme_lba_status_ns_element *ns_element; + struct nvme_lba_status_range_desc *range_desc; + int offset = sizeof(*hdr); + __u32 num_lba_desc, num_elements; + + root = json_create_object(); + hdr = lba_status; + json_object_add_value_uint(root, "lslplen", le32_to_cpu(hdr->lslplen)); + num_elements = le32_to_cpu(hdr->nlslne); + json_object_add_value_uint(root, "nlslne", num_elements); + json_object_add_value_uint(root, "estulb", le32_to_cpu(hdr->estulb)); + json_object_add_value_uint(root, "lsgc", le16_to_cpu(hdr->lsgc)); + + elements_list = json_create_array(); + for (int ele = 0; ele < num_elements; ele++) { + ns_element = lba_status + offset; + element = json_create_object(); + json_object_add_value_uint(element, "neid", + le32_to_cpu(ns_element->neid)); + num_lba_desc = le32_to_cpu(ns_element->nlrd); + json_object_add_value_uint(element, "nlrd", num_lba_desc); + json_object_add_value_uint(element, "ratype", ns_element->ratype); + + offset += sizeof(*ns_element); + desc_list = json_create_array(); + if (num_lba_desc != 0xffffffff) { + for (int i = 0; i < num_lba_desc; i++) { + range_desc = lba_status + offset; + desc = json_create_object(); + json_object_add_value_uint(desc, "rslba", + le64_to_cpu(range_desc->rslba)); + json_object_add_value_uint(desc, "rnlb", + le32_to_cpu(range_desc->rnlb)); + + offset += sizeof(*range_desc); + json_array_add_value_object(desc_list, desc); + } + } else { + printf("Number of LBA Range Descriptors (NLRD) set to %#x for " \ + "NS element %d", num_lba_desc, ele); + } + + json_object_add_value_array(element, "descs", desc_list); + json_array_add_value_object(elements_list, element); + } + + json_object_add_value_array(root, "ns_elements", elements_list); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_lba_status_log(void *lba_status, __u32 size, + const char *devname, enum nvme_print_flags flags) +{ + struct nvme_lba_status_hdr *hdr; + struct nvme_lba_status_ns_element *ns_element; + struct nvme_lba_status_range_desc *range_desc; + int offset = sizeof(*hdr); + __u32 num_lba_desc, num_elements; + + if (flags & BINARY) + return d_raw((unsigned char *)lba_status, size); + if (flags & JSON) + return json_lba_status_log(lba_status); + + hdr = lba_status; + printf("LBA Status Log for device: %s\n", devname); + printf("LBA Status Log Page Length: %"PRIu32"\n", + le32_to_cpu(hdr->lslplen)); + num_elements = le32_to_cpu(hdr->nlslne); + printf("Number of LBA Status Log Namespace Elements: %"PRIu32"\n", + num_elements); + printf("Estimate of Unrecoverable Logical Blocks: %"PRIu32"\n", + le32_to_cpu(hdr->estulb)); + printf("LBA Status Generation Counter: %"PRIu16"\n", le16_to_cpu(hdr->lsgc)); + for (int ele = 0; ele < num_elements; ele++) { + ns_element = lba_status + offset; + printf("Namespace Element Identifier: %"PRIu32"\n", + le32_to_cpu(ns_element->neid)); + num_lba_desc = le32_to_cpu(ns_element->nlrd); + printf("Number of LBA Range Descriptors: %"PRIu32"\n", num_lba_desc); + printf("Recommended Action Type: %u\n", ns_element->ratype); + + offset += sizeof(*ns_element); + if (num_lba_desc != 0xffffffff) { + for (int i = 0; i < num_lba_desc; i++) { + range_desc = lba_status + offset; + printf("RSLBA[%d]: %"PRIu64"\n", i, + le64_to_cpu(range_desc->rslba)); + printf("RNLB[%d]: %"PRIu32"\n", i, + le32_to_cpu(range_desc->rnlb)); + offset += sizeof(*range_desc); + } + } else { + printf("Number of LBA Range Descriptors (NLRD) set to %#x for "\ + "NS element %d\n", num_lba_desc, ele); + } + } +} + +static const char *resv_notif_to_string(__u8 type) +{ + switch (type) { + case 0x1: return "Empty Log Page"; + case 0x2: return "Registration Preempted"; + case 0x3: return "Reservation Released"; + case 0x4: return "Reservation Preempted"; + default: return "Reserved"; + } +} + +static void json_resv_notif_log(struct nvme_resv_notif_log *resv) +{ + struct json_object *root; + + root = json_create_object(); + json_object_add_value_uint(root, "count", + le64_to_cpu(resv->log_page_count)); + json_object_add_value_uint(root, "rn_log_type", + resv->resv_notif_log_type); + json_object_add_value_uint(root, "num_logs", + resv->num_logs); + json_object_add_value_uint(root, "nsid", + le32_to_cpu(resv->nsid)); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_resv_notif_log(struct nvme_resv_notif_log *resv, + const char *devname, enum nvme_print_flags flags) +{ + if (flags & BINARY) + return d_raw((unsigned char *)resv, sizeof(*resv)); + if (flags & JSON) + return json_resv_notif_log(resv); + + printf("Reservation Notif Log for device: %s\n", devname); + printf("Log Page Count : %"PRIx64"\n", + le64_to_cpu(resv->log_page_count)); + printf("Resv Notif Log Page Type : %u (%s)\n", + resv->resv_notif_log_type, + resv_notif_to_string(resv->resv_notif_log_type)); + printf("Num of Available Log Pages : %u\n", resv->num_logs); + printf("Namespace ID: : %"PRIx32"\n", + le32_to_cpu(resv->nsid)); +} + static void nvme_show_subsystem(struct nvme_subsystem *s) { int i; @@ -869,9 +1792,9 @@ static void nvme_show_subsystem(struct nvme_subsystem *s) for (i = 0; i < s->nr_ctrls; i++) { printf(" +- %s %s %s %s %s\n", s->ctrls[i].name, - s->ctrls[i].transport, - s->ctrls[i].address, - s->ctrls[i].state, + s->ctrls[i].transport ? : "", + s->ctrls[i].address ? : "", + s->ctrls[i].state ? : "", s->ctrls[i].ana_state ? : ""); } } @@ -879,7 +1802,7 @@ static void nvme_show_subsystem(struct nvme_subsystem *s) static void json_print_nvme_subsystem_list(struct nvme_topology *t) { struct json_object *subsystem_attrs, *path_attrs; - struct json_array *subsystems, *paths; + struct json_object *subsystems, *paths; struct json_object *root; int i, j; @@ -904,12 +1827,15 @@ static void json_print_nvme_subsystem_list(struct nvme_topology *t) path_attrs = json_create_object(); json_object_add_value_string(path_attrs, "Name", c->name); - json_object_add_value_string(path_attrs, "Transport", - c->transport); - json_object_add_value_string(path_attrs, "Address", - c->address); - json_object_add_value_string(path_attrs, "State", - c->state); + if (c->transport) + json_object_add_value_string(path_attrs, + "Transport", c->transport); + if (c->address) + json_object_add_value_string(path_attrs, + "Address", c->address); + if (c->state) + json_object_add_value_string(path_attrs, + "State", c->state); if (c->ana_state) json_object_add_value_string(path_attrs, "ANAState", c->ana_state); @@ -946,14 +1872,16 @@ static void nvme_show_registers_cap(struct nvme_bar_cap *cap) "Not Supported"); printf("\tPersistent Memory Region Supported (PMRS): The Persistent Memory Region is %s\n", (cap->rsvd_cmbs_pmrs & 0x01) ? "Supported" : "Not Supported"); - printf("\tMemory Page Size Maximum (MPSMAX): %u bytes\n", + printf("\tMemory Page Size Maximum (MPSMAX): %u bytes\n", 1 << (12 + ((cap->mpsmax_mpsmin & 0xf0) >> 4))); printf("\tMemory Page Size Minimum (MPSMIN): %u bytes\n", 1 << (12 + (cap->mpsmax_mpsmin & 0x0f))); printf("\tBoot Partition Support (BPS): %s\n", (cap->bps_css_nssrs_dstrd & 0x2000) ? "Yes":"No"); printf("\tCommand Sets Supported (CSS): NVM command set is %s\n", - (cap->bps_css_nssrs_dstrd & 0x0020) ? "supported":"not supported"); + (cap->bps_css_nssrs_dstrd & 0x0020) ? "Supported" : "Not Supported"); + printf("\t One or more I/O Command Sets are %s\n", + (cap->bps_css_nssrs_dstrd & 0x0800) ? "Supported" : "Not Supported"); printf("\tNVM Subsystem Reset Supported (NSSRS): %s\n", (cap->bps_css_nssrs_dstrd & 0x0010) ? "Yes":"No"); printf("\tDoorbell Stride (DSTRD): %u bytes\n", @@ -962,7 +1890,7 @@ static void nvme_show_registers_cap(struct nvme_bar_cap *cap) cap->to * 500); printf("\tArbitration Mechanism Supported (AMS): Weighted Round Robin with Urgent Priority Class is %s\n", (cap->ams_cqr & 0x02) ? "supported":"not supported"); - printf("\tContiguous Queues Required (CQR): %s\n", + printf("\tContiguous Queues Required (CQR): %s\n", (cap->ams_cqr & 0x01) ? "Yes":"No"); printf("\tMaximum Queue Entries Supported (MQES): %u\n\n", cap->mqes + 1); @@ -1020,8 +1948,10 @@ static void nvme_show_registers_cc(__u32 cc) nvme_show_registers_cc_ams((cc & 0x00003800) >> NVME_CC_AMS_SHIFT); printf("\tMemory Page Size (MPS): %u bytes\n", 1 << (12 + ((cc & 0x00000780) >> NVME_CC_MPS_SHIFT))); - printf("\tI/O Command Sets Selected (CSS): %s\n", - (cc & 0x00000070) ? "Reserved":"NVM Command Set"); + printf("\tI/O Command Set Selected (CSS): %s\n", + (cc & 0x00000070) == 0x00 ? "NVM Command Set" : + (cc & 0x00000070) == 0x60 ? "All supported I/O Command Sets" : + (cc & 0x00000070) == 0x70 ? "Admin Command Set only" : "Reserved"); printf("\tEnable (EN): %s\n\n", (cc & 0x00000001) ? "Yes":"No"); } @@ -1199,11 +2129,11 @@ static void nvme_show_registers_bpmbl(uint64_t bpmbl) static void nvme_show_registers_cmbmsc(uint64_t cmbmsc) { - printf("\tController Base Address (CBA) : %" PRIx64 "\n", + printf("\tController Base Address (CBA): %" PRIx64 "\n", (cmbmsc & 0xfffffffffffff000) >> 12); printf("\tController Memory Space Enable (CMSE): %" PRIx64 "\n", (cmbmsc & 0x0000000000000002) >> 1); - printf("\tCapabilities Registers Enabled (CRE) : CMBLOC and "\ + printf("\tCapabilities Registers Enabled (CRE): CMBLOC and "\ "CMBSZ registers are%senabled\n\n", (cmbmsc & 0x0000000000000001) ? " " : " NOT "); } @@ -1216,20 +2146,20 @@ static void nvme_show_registers_cmbsts(__u32 cmbsts) static void nvme_show_registers_pmrcap(__u32 pmrcap) { - printf("\tController Memory Space Supported (CMSS) : "\ + printf("\tController Memory Space Supported (CMSS): "\ "Referencing PMR with host supplied addresses is %s\n", ((pmrcap & 0x01000000) >> 24) ? "Supported" : "Not Supported"); - printf("\tPersistent Memory Region Timeout (PMRTO): %x\n", + printf("\tPersistent Memory Region Timeout (PMRTO): %x\n", (pmrcap & 0x00ff0000) >> 16); - printf("\tPersistent Memory Region Write Barrier Mechanisms(PMRWBM): %x\n", + printf("\tPersistent Memory Region Write Barrier Mechanisms (PMRWBM): %x\n", (pmrcap & 0x00003c00) >> 10); - printf("\tPersistent Memory Region Time Units (PMRTU): PMR time unit is %s\n", + printf("\tPersistent Memory Region Time Units (PMRTU): PMR time unit is %s\n", (pmrcap & 0x00000300) >> 8 ? "minutes":"500 milliseconds"); - printf("\tBase Indicator Register (BIR): %x\n", + printf("\tBase Indicator Register (BIR): %x\n", (pmrcap & 0x000000e0) >> 5); - printf("\tWrite Data Support (WDS): Write data to the PMR is %s\n", + printf("\tWrite Data Support (WDS): Write data to the PMR is %s\n", (pmrcap & 0x00000010) ? "supported":"not supported"); - printf("\tRead Data Support (RDS): Read data from the PMR is %s\n", + printf("\tRead Data Support (RDS): Read data from the PMR is %s\n", (pmrcap & 0x00000008) ? "supported":"not supported"); } @@ -1254,14 +2184,14 @@ static void nvme_show_registers_pmrsts(__u32 pmrsts, __u32 pmrctl) { printf("\tController Base Address Invalid (CBAI): %x\n", (pmrsts & 0x00001000) >> 12); - printf("\tHealth Status (HSTS): %s\n", + printf("\tHealth Status (HSTS): %s\n", nvme_register_pmr_hsts_to_string((pmrsts & 0x00000e00) >> 9)); - printf("\tNot Ready (NRDY): "\ + printf("\tNot Ready (NRDY): "\ "The Persistent Memory Region is %s to process "\ "PCI Express memory read and write requests\n", (pmrsts & 0x00000100) == 0 && (pmrctl & 0x00000001) ? "READY":"Not Ready"); - printf("\tError (ERR) : %x\n", (pmrsts & 0x000000ff)); + printf("\tError (ERR): %x\n", (pmrsts & 0x000000ff)); } static const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu) @@ -1278,7 +2208,7 @@ static const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu) static void nvme_show_registers_pmrebs(__u32 pmrebs) { printf("\tPMR Elasticity Buffer Size Base (PMRWBZ): %x\n", (pmrebs & 0xffffff00) >> 8); - printf("\tRead Bypass Behavior : memory reads not conflicting with memory writes "\ + printf("\tRead Bypass Behavior : memory reads not conflicting with memory writes "\ "in the PMR Elasticity Buffer %s bypass those memory writes\n", (pmrebs & 0x00000010) ? "SHALL":"MAY"); printf("\tPMR Elasticity Buffer Size Units (PMRSZU): %s\n", @@ -1293,12 +2223,18 @@ static void nvme_show_registers_pmrswtp(__u32 pmrswtp) nvme_register_pmr_pmrszu_to_string(pmrswtp & 0x0000000f)); } -static void nvme_show_registers_pmrmsc(uint64_t pmrmsc) +static void nvme_show_registers_pmrmscl(uint32_t pmrmscl) +{ + printf("\tController Base Address (CBA): %#x\n", + (pmrmscl & 0xfffff000) >> 12); + printf("\tController Memory Space Enable (CMSE): %#x\n\n", + (pmrmscl & 0x00000002) >> 1); +} + +static void nvme_show_registers_pmrmscu(uint32_t pmrmscu) { - printf("\tController Base Address (CBA) : %" PRIx64 "\n", - (pmrmsc & 0xfffffffffffff000) >> 12); - printf("\tController Memory Space Enable (CMSE) : %" PRIx64 "\n\n", - (pmrmsc & 0x0000000000000002) >> 1); + printf("\tController Base Address (CBA): %#x\n", + pmrmscu); } static inline uint32_t mmio_read32(void *addr) @@ -1311,16 +2247,21 @@ static inline uint32_t mmio_read32(void *addr) /* Access 64-bit registers as 2 32-bit; Some devices fail 64-bit MMIO. */ static inline __u64 mmio_read64(void *addr) { - __le32 *p = addr; + const volatile __u32 *p = addr; + __u32 low, high; + + low = le32_to_cpu(*p); + high = le32_to_cpu(*(p + 1)); - return le32_to_cpu(*p) | ((uint64_t)le32_to_cpu(*(p + 1)) << 32); + return ((__u64) high << 32) | low; } static void json_ctrl_registers(void *bar) { - uint64_t cap, asq, acq, bpmbl, cmbmsc, pmrmsc; + uint64_t cap, asq, acq, bpmbl, cmbmsc; uint32_t vs, intms, intmc, cc, csts, nssr, aqa, cmbsz, cmbloc, - bpinfo, bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp; + bpinfo, bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp, + pmrmscl, pmrmscu; struct json_object *root; cap = mmio_read64(bar + NVME_REG_CAP); @@ -1345,7 +2286,8 @@ static void json_ctrl_registers(void *bar) pmrsts = mmio_read32(bar + NVME_REG_PMRSTS); pmrebs = mmio_read32(bar + NVME_REG_PMREBS); pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP); - pmrmsc = mmio_read64(bar + NVME_REG_PMRMSC); + pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL); + pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU); root = json_create_object(); json_object_add_value_uint(root, "cap", cap); @@ -1370,7 +2312,8 @@ static void json_ctrl_registers(void *bar) json_object_add_value_int(root, "pmrsts", pmrsts); json_object_add_value_int(root, "pmrebs", pmrebs); json_object_add_value_int(root, "pmrswtp", pmrswtp); - json_object_add_value_uint(root, "pmrmsc", pmrmsc); + json_object_add_value_uint(root, "pmrmscl", pmrmscl); + json_object_add_value_uint(root, "pmrmscu", pmrmscu); json_print_object(root, NULL); printf("\n"); json_free_object(root); @@ -1378,10 +2321,11 @@ static void json_ctrl_registers(void *bar) void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags) { - const unsigned int reg_size = 0x50; /* 00h to 4Fh */ - uint64_t cap, asq, acq, bpmbl, cmbmsc, pmrmsc; + const unsigned int reg_size = 0x0e1c; /* 0x0000 to 0x0e1b */ + uint64_t cap, asq, acq, bpmbl, cmbmsc; uint32_t vs, intms, intmc, cc, csts, nssr, aqa, cmbsz, cmbloc, bpinfo, - bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp; + bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp, + pmrmscl, pmrmscu; int human = flags & VERBOSE; if (flags & BINARY) @@ -1411,7 +2355,8 @@ void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags fla pmrsts = mmio_read32(bar + NVME_REG_PMRSTS); pmrebs = mmio_read32(bar + NVME_REG_PMREBS); pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP); - pmrmsc = mmio_read64(bar + NVME_REG_PMRMSC); + pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL); + pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU); if (human) { if (cap != 0xffffffff) { @@ -1490,8 +2435,11 @@ void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags fla printf("pmrswtp : %x\n", pmrswtp); nvme_show_registers_pmrswtp(pmrswtp); - printf("pmrmsc : %"PRIx64"\n", pmrmsc); - nvme_show_registers_pmrmsc(pmrmsc); + printf("pmrmscl : %#x\n", pmrmscl); + nvme_show_registers_pmrmscl(pmrmscl); + + printf("pmrmscu : %#x\n", pmrmscu); + nvme_show_registers_pmrmscu(pmrmscu); } } else { if (cap != 0xffffffff) @@ -1522,7 +2470,8 @@ void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags fla printf("pmrsts : %x\n", pmrsts); printf("pmrebs : %x\n", pmrebs); printf("pmrswtp : %x\n", pmrswtp); - printf("pmrmsc : %"PRIx64"\n", pmrmsc); + printf("pmrmscl : %#x\n", pmrmscl); + printf("pmrmscu : %#x\n", pmrmscu); } } } @@ -1615,7 +2564,7 @@ void nvme_show_relatives(const char *name) free(path); return; } - err = scan_subsystems(&t, subsysnqn, 0); + err = scan_subsystems(&t, subsysnqn, 0, 0, NULL); if (err || t.nr_subsystems != 1) { free(subsysnqn); free(path); @@ -1698,7 +2647,7 @@ void d_raw(unsigned char *buf, unsigned len) { unsigned i; for (i = 0; i < len; i++) - putchar(*(buf+i)); + putchar(*(buf + i)); } void nvme_show_status(__u16 status) @@ -1765,17 +2714,23 @@ static void nvme_show_id_ctrl_cmic(__u8 cmic) static void nvme_show_id_ctrl_oaes(__le32 ctrl_oaes) { __u32 oaes = le32_to_cpu(ctrl_oaes); - __u32 rsvd0 = (oaes & 0xFFFF8000) >> 15; + __u32 rsvd0 = (oaes & 0xF0000000) >> 28; + __u32 zicn = (oaes & 0x08000000) >> 27; + __u32 rsvd1 = (oaes & 0x07FF8000) >> 15; __u32 nace = (oaes & 0x100) >> 8; __u32 fan = (oaes & 0x200) >> 9; __u32 anacn = (oaes & 0x800) >> 11; __u32 plealcn = (oaes & 0x1000) >> 12; __u32 lbasin = (oaes & 0x2000) >> 13; __u32 egealpcn = (oaes & 0x4000) >> 14; - __u32 rsvd1 = oaes & 0xFF; + __u32 rsvd2 = oaes & 0xFF; if (rsvd0) - printf(" [31:10] : %#x\tReserved\n", rsvd0); + printf(" [31:28] : %#x\tReserved\n", rsvd0); + printf("[27:27] : %#x\tZone Descriptor Changed Notices %sSupported\n", + zicn, zicn ? "" : "Not "); + if (rsvd1) + printf(" [26:15] : %#x\tReserved\n", rsvd1); printf("[14:14] : %#x\tEndurance Group Event Aggregate Log Page"\ " Change Notice %sSupported\n", egealpcn, egealpcn ? "" : "Not "); @@ -1790,7 +2745,7 @@ static void nvme_show_id_ctrl_oaes(__le32 ctrl_oaes) fan, fan ? "" : "Not "); printf(" [8:8] : %#x\tNamespace Attribute Changed Event %sSupported\n", nace, nace ? "" : "Not "); - if (rsvd1) + if (rsvd2) printf(" [7:0] : %#x\tReserved\n", rsvd1); printf("\n"); } @@ -1955,7 +2910,7 @@ static void nvme_show_id_ctrl_apsta(__u8 apsta) printf("\n"); } -static void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs) +void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs) { __u32 rpmbs = le32_to_cpu(ctrl_rpmbs); __u32 asz = (rpmbs & 0xFF000000) >> 24; @@ -2068,7 +3023,8 @@ static void nvme_show_id_ctrl_cqes(__u8 cqes) static void nvme_show_id_ctrl_oncs(__le16 ctrl_oncs) { __u16 oncs = le16_to_cpu(ctrl_oncs); - __u16 rsvd = (oncs & 0xFF00) >> 8; + __u16 rsvd = (oncs & 0xFE00) >> 9; + __u16 copy = (oncs & 0x100) >> 8; __u16 vrfy = (oncs & 0x80) >> 7; __u16 tmst = (oncs & 0x40) >> 6; __u16 resv = (oncs & 0x20) >> 5; @@ -2079,7 +3035,9 @@ static void nvme_show_id_ctrl_oncs(__le16 ctrl_oncs) __u16 cmp = oncs & 0x1; if (rsvd) - printf(" [15:8] : %#x\tReserved\n", rsvd); + printf(" [15:9] : %#x\tReserved\n", rsvd); + printf(" [8:8] : %#x\tCopy %sSupported\n", + copy, copy ? "" : "Not "); printf(" [7:7] : %#x\tVerify %sSupported\n", vrfy, vrfy ? "" : "Not "); printf(" [6:6] : %#x\tTimestamp %sSupported\n", @@ -2150,10 +3108,10 @@ static void nvme_show_id_ctrl_vwc(__u8 vwc) printf("\n"); } -static void nvme_show_id_ctrl_nvscc(__u8 nvscc) +static void nvme_show_id_ctrl_icsvscc(__u8 icsvscc) { - __u8 rsvd = (nvscc & 0xFE) >> 1; - __u8 fmt = nvscc & 0x1; + __u8 rsvd = (icsvscc & 0xFE) >> 1; + __u8 fmt = icsvscc & 0x1; if (rsvd) printf(" [7:1] : %#x\tReserved\n", rsvd); printf(" [0:0] : %#x\tNVM Vendor Specific Commands uses %s Format\n", @@ -2233,10 +3191,10 @@ static void nvme_show_id_ctrl_sgls(__le32 ctrl_sgls) printf("\n"); } -static void nvme_show_id_ctrl_ctrattr(__u8 ctrattr) +static void nvme_show_id_ctrl_fcatt(__u8 fcatt) { - __u8 rsvd = (ctrattr & 0xFE) >> 1; - __u8 scm = ctrattr & 0x1; + __u8 rsvd = (fcatt & 0xFE) >> 1; + __u8 scm = fcatt & 0x1; if (rsvd) printf(" [7:1] : %#x\tReserved\n", rsvd); printf(" [0:0] : %#x\t%s Controller Model\n", @@ -2244,10 +3202,23 @@ static void nvme_show_id_ctrl_ctrattr(__u8 ctrattr) printf("\n"); } +static void nvme_show_id_ctrl_ofcs(__le16 ofcs) +{ + __u16 rsvd = (ofcs & 0xfffe) >> 1; + __u8 disconn = ofcs & 0x1; + if (rsvd) + printf(" [15:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\tDisconnect command %s Supported\n", + disconn, disconn ? "" : "Not"); + printf("\n"); + +} + static void nvme_show_id_ns_nsfeat(__u8 nsfeat) { __u8 rsvd = (nsfeat & 0xE0) >> 5; __u8 ioopt = (nsfeat & 0x10) >> 4; + __u8 uidreuse = (nsfeat & 0x8) >> 3; __u8 dulbe = (nsfeat & 0x4) >> 2; __u8 na = (nsfeat & 0x2) >> 1; __u8 thin = nsfeat & 0x1; @@ -2255,6 +3226,8 @@ static void nvme_show_id_ns_nsfeat(__u8 nsfeat) printf(" [7:5] : %#x\tReserved\n", rsvd); printf(" [4:4] : %#x\tNPWG, NPWA, NPDG, NPDA, and NOWS are %sSupported\n", ioopt, ioopt ? "" : "Not "); + printf(" [3:3] : %#x\tNGUID and EUI64 fields if non-zero, %sReused\n", + uidreuse, uidreuse ? "Never " : ""); printf(" [2:2] : %#x\tDeallocated or Unwritten Logical Block error %sSupported\n", dulbe, dulbe ? "" : "Not "); printf(" [1:1] : %#x\tNamespace uses %s\n", @@ -2344,7 +3317,7 @@ static void nvme_show_id_ns_nmic(__u8 nmic) static void nvme_show_id_ns_rescap(__u8 rescap) { - __u8 rsvd = (rescap & 0x80) >> 7; + __u8 iekr = (rescap & 0x80) >> 7; __u8 eaar = (rescap & 0x40) >> 6; __u8 wear = (rescap & 0x20) >> 5; __u8 earo = (rescap & 0x10) >> 4; @@ -2352,8 +3325,9 @@ static void nvme_show_id_ns_rescap(__u8 rescap) __u8 ea = (rescap & 0x4) >> 2; __u8 we = (rescap & 0x2) >> 1; __u8 ptpl = rescap & 0x1; - if (rsvd) - printf(" [7:7] : %#x\tReserved\n", rsvd); + + printf(" [7:7] : %#x\tIgnore Existing Key - Used as defined in revision %s\n", + iekr, iekr ? "1.3 or later" : "1.2.1 or earlier"); printf(" [6:6] : %#x\tExclusive Access - All Registrants %sSupported\n", eaar, eaar ? "" : "Not "); printf(" [5:5] : %#x\tWrite Exclusive - All Registrants %sSupported\n", @@ -2412,7 +3386,7 @@ void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid, if (flags & BINARY) return d_raw((unsigned char *)ns, sizeof(*ns)); if (flags & JSON) - return json_nvme_id_ns(ns, flags); + return json_nvme_id_ns(ns); printf("NVME Identify Namespace %d:\n", nsid); printf("nsze : %#"PRIx64"\n", le64_to_cpu(ns->nsze)); @@ -2461,9 +3435,12 @@ void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid, printf("npda : %u\n", le16_to_cpu(ns->npda)); printf("nows : %u\n", le16_to_cpu(ns->nows)); } + printf("mssrl : %u\n", le16_to_cpu(ns->mssrl)); + printf("mcl : %d\n", le32_to_cpu(ns->mcl)); + printf("msrc : %u\n", ns->msrc); + printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid)); printf("nsattr : %u\n", ns->nsattr); printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid)); - printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid)); printf("endgid : %d\n", le16_to_cpu(ns->endgid)); printf("nguid : "); @@ -2492,6 +3469,7 @@ void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid, ns->lbaf[i].rp, i == (ns->flbas & 0xf) ? "(in use)" : ""); } + if (vs) { printf("vs[]:\n"); d(ns->vs, sizeof(ns->vs), 16, 1); @@ -2512,10 +3490,11 @@ static void json_nvme_id_ns_descs(void *data) #ifdef LIBUUID uuid_t uuid; #endif + __u8 csi; } desc; struct json_object *root; - struct json_array *json_array = NULL; + struct json_object *json_array = NULL; off_t off; int pos, len = 0; @@ -2557,6 +3536,12 @@ static void json_nvme_id_ns_descs(void *data) nidt_name = "uuid"; break; #endif + case NVME_NIDT_CSI: + memcpy(&desc.csi, data + off, sizeof(desc.csi)); + json_str_p += sprintf(json_str_p, "%#x", desc.csi); + len += sizeof(desc.csi); + nidt_name = "csi"; + break; default: /* Skip unnkown types */ len = cur->nidl; @@ -2602,6 +3587,7 @@ void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flag #endif __u8 eui64[8]; __u8 nguid[16]; + __u8 csi; if (flags & BINARY) return d_raw((unsigned char *)data, 0x1000); @@ -2640,6 +3626,11 @@ void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flag len = sizeof(uuid); break; #endif + case NVME_NIDT_CSI: + memcpy(&csi, data + pos + sizeof(*cur), 1); + printf("csi : %#x\n", csi); + len += sizeof(csi); + break; default: /* Skip unnkown types */ len = cur->nidl; @@ -2716,7 +3707,7 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, if (flags & BINARY) return d_raw((unsigned char *)ctrl, sizeof(*ctrl)); else if (flags & JSON) - return json_nvme_id_ctrl(ctrl, flags, vendor_show); + return json_nvme_id_ctrl(ctrl, vendor_show); printf("NVME Identify Controller:\n"); printf("vid : %#x\n", le16_to_cpu(ctrl->vid)); @@ -2824,9 +3815,9 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, nvme_show_id_ctrl_vwc(ctrl->vwc); printf("awun : %d\n", le16_to_cpu(ctrl->awun)); printf("awupf : %d\n", le16_to_cpu(ctrl->awupf)); - printf("nvscc : %d\n", ctrl->nvscc); + printf("icsvscc : %d\n", ctrl->icsvscc); if (human) - nvme_show_id_ctrl_nvscc(ctrl->nvscc); + nvme_show_id_ctrl_icsvscc(ctrl->icsvscc); printf("nwpc : %d\n", ctrl->nwpc); if (human) nvme_show_id_ctrl_nwpc(ctrl->nwpc); @@ -2839,10 +3830,13 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, printf("ioccsz : %d\n", le32_to_cpu(ctrl->ioccsz)); printf("iorcsz : %d\n", le32_to_cpu(ctrl->iorcsz)); printf("icdoff : %d\n", le16_to_cpu(ctrl->icdoff)); - printf("ctrattr : %#x\n", ctrl->ctrattr); + printf("fcatt : %#x\n", ctrl->fcatt); if (human) - nvme_show_id_ctrl_ctrattr(ctrl->ctrattr); + nvme_show_id_ctrl_fcatt(ctrl->fcatt); printf("msdbd : %d\n", ctrl->msdbd); + printf("ofcs : %d\n", le16_to_cpu(ctrl->ofcs)); + if (human) + nvme_show_id_ctrl_ofcs(ctrl->ofcs); nvme_show_id_ctrl_power(ctrl); if (vendor_show) @@ -2858,10 +3852,292 @@ void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode) __nvme_show_id_ctrl(ctrl, mode, NULL); } +static void json_nvme_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm) +{ + struct json_object *root; + + root = json_create_object(); + json_object_add_value_uint(root, "vsl", ctrl_nvm->vsl); + json_object_add_value_uint(root, "wzsl", ctrl_nvm->wzsl); + json_object_add_value_uint(root, "wusl", ctrl_nvm->wusl); + json_object_add_value_uint(root, "dmrl", ctrl_nvm->dmrl); + json_object_add_value_uint(root, "dmrsl", ctrl_nvm->dmrsl); + json_object_add_value_uint(root, "dmsl", ctrl_nvm->dmsl); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm, + enum nvme_print_flags flags) +{ + if (flags & BINARY) + return d_raw((unsigned char *)ctrl_nvm, sizeof(*ctrl_nvm)); + else if (flags & JSON) + return json_nvme_id_ctrl_nvm(ctrl_nvm); + + printf("NVMe Identify Controller NVM:\n"); + printf("vsl : %u\n", ctrl_nvm->vsl); + printf("wzsl : %u\n", ctrl_nvm->wzsl); + printf("wusl : %u\n", ctrl_nvm->wusl); + printf("dmrl : %u\n", ctrl_nvm->dmrl); + printf("dmrsl : %u\n", le32_to_cpu(ctrl_nvm->dmrsl)); + printf("dmsl : %"PRIu64"\n", le64_to_cpu(ctrl_nvm->dmsl)); +} + +static void json_nvme_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl) +{ + struct json_object *root; + + root = json_create_object(); + json_object_add_value_int(root, "zasl", ctrl->zasl); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode) +{ + if (mode & BINARY) + return d_raw((unsigned char *)ctrl, sizeof(*ctrl)); + else if (mode & JSON) + return json_nvme_zns_id_ctrl(ctrl); + + printf("NVMe ZNS Identify Controller:\n"); + printf("zasl : %u\n", ctrl->zasl); +} + +void json_nvme_zns_id_ns(struct nvme_zns_id_ns *ns, + struct nvme_id_ns *id_ns) +{ + struct json_object *root; + struct json_object *lbafs; + int i; + + root = json_create_object(); + json_object_add_value_int(root, "zoc", le16_to_cpu(ns->zoc)); + json_object_add_value_int(root, "ozcs", le16_to_cpu(ns->ozcs)); + json_object_add_value_int(root, "mar", le32_to_cpu(ns->mar)); + json_object_add_value_int(root, "mor", le32_to_cpu(ns->mor)); + json_object_add_value_int(root, "rrl", le32_to_cpu(ns->rrl)); + json_object_add_value_int(root, "frl", le32_to_cpu(ns->frl)); + + lbafs = json_create_array(); + json_object_add_value_array(root, "lbafe", lbafs); + + for (i = 0; i <= id_ns->nlbaf; i++) { + struct json_object *lbaf = json_create_object(); + + json_object_add_value_int(lbaf, "zsze", + le64_to_cpu(ns->lbafe[i].zsze)); + json_object_add_value_int(lbaf, "zdes", ns->lbafe[i].zdes); + + json_array_add_value_object(lbafs, lbaf); + } + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +static void show_nvme_id_ns_zoned_zoc(__le16 ns_zoc) +{ + __u16 zoc = le16_to_cpu(ns_zoc); + __u8 rsvd = (zoc & 0xfffc) >> 2; + __u8 ze = (zoc & 0x2) >> 1; + __u8 vzc = zoc & 0x1; + if (rsvd) + printf(" [15:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\t Zone Active Excursions: %s\n", + ze, ze ? "Yes (Host support required)" : "No"); + printf(" [0:0] : %#x\t Variable Zone Capacity: %s\n", + vzc, vzc ? "Yes (Host support required)" : "No"); + printf("\n"); +} + +static void show_nvme_id_ns_zoned_ozcs(__le16 ns_ozcs) +{ + __u16 ozcs = le16_to_cpu(ns_ozcs); + __u8 rsvd = (ozcs & 0xfffe) >> 1; + __u8 razb = ozcs & 0x1; + + if (rsvd) + printf(" [15:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\t Read Across Zone Boundaries: %s\n", + razb, razb ? "Yes" : "No"); +} + +void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns, + struct nvme_id_ns *id_ns, unsigned long flags) +{ + int human = flags & VERBOSE, vs = flags & VS; + uint8_t lbaf = id_ns->flbas & NVME_NS_FLBAS_LBA_MASK; + int i; + + if (flags & BINARY) + return d_raw((unsigned char *)ns, sizeof(*ns)); + else if (flags & JSON) + return json_nvme_zns_id_ns(ns, id_ns); + + printf("ZNS Command Set Identify Namespace:\n"); + + if (human) { + printf("zoc : %u\tZone Operation Characteristics\n", le16_to_cpu(ns->zoc)); + show_nvme_id_ns_zoned_zoc(ns->zoc); + } else { + printf("zoc : %u\n", le16_to_cpu(ns->zoc)); + } + + if (human) { + printf("ozcs : %u\tOptional Zoned Command Support\n", le16_to_cpu(ns->ozcs)); + show_nvme_id_ns_zoned_ozcs(ns->ozcs); + } else { + printf("ozcs : %u\n", le16_to_cpu(ns->ozcs)); + } + + if (human) { + if (ns->mar == 0xffffffff) { + printf("mar : No Active Resource Limit\n"); + } else { + printf("mar : %u\tActive Resources\n", le32_to_cpu(ns->mar) + 1); + } + } else { + printf("mar : %#x\n", le32_to_cpu(ns->mar)); + } + + if (human) { + if (ns->mor == 0xffffffff) { + printf("mor : No Open Resource Limit\n"); + } else { + printf("mor : %u\tOpen Resources\n", le32_to_cpu(ns->mor) + 1); + } + } else { + printf("mor : %#x\n", le32_to_cpu(ns->mor)); + } + + if (!le32_to_cpu(ns->rrl) && human) + printf("rrl : Not Reported\n"); + else + printf("rrl : %d\n", le32_to_cpu(ns->rrl)); + + if (!le32_to_cpu(ns->frl) && human) + printf("frl : Not Reported\n"); + else + printf("frl : %d\n", le32_to_cpu(ns->frl)); + + for (i = 0; i <= id_ns->nlbaf; i++){ + if (human) + printf("LBA Format Extension %2d : Zone Size: 0x%"PRIx64" LBAs - " + "Zone Descriptor Extension Size: %-1d bytes%s\n", + i, le64_to_cpu(ns->lbafe[i].zsze), ns->lbafe[i].zdes << 6, + i == lbaf ? " (in use)" : ""); + else + printf("lbafe %2d: zsze:0x%"PRIx64" zdes:%u%s\n", i, + (uint64_t)le64_to_cpu(ns->lbafe[i].zsze), + ns->lbafe[i].zdes, i == lbaf ? " (in use)" : ""); + } + + if (vs) { + printf("vs[] :\n"); + d(ns->vs, sizeof(ns->vs), 16, 1); + } +} + +void nvme_show_zns_changed(struct nvme_zns_changed_zone_log *log, + unsigned long flags) +{ + uint16_t nrzid; + int i; + + if (flags & BINARY) + return d_raw((unsigned char *)log, sizeof(*log)); + + nrzid = le16_to_cpu(log->nrzid); + printf("NVMe Changed Zone List:\n"); + + if (nrzid == 0xFFFF) { + printf("Too many zones have changed to fit into the log. Use report zones for changes.\n"); + return; + } + + printf("nrzid: %u\n", nrzid); + for (i = 0; i < nrzid; i++) + printf("zid %03d: %"PRIu64"\n", i, (uint64_t)le64_to_cpu(log->zid[i])); +} + +char *zone_type_to_string(__u8 cond) +{ + switch (cond) { + case NVME_ZONE_TYPE_SEQWRITE_REQ: + return "SEQWRITE_REQ"; + default: + return "Unknown"; + } +} + +char *zone_state_to_string(__u8 state) +{ + switch (state) { + case NVME_ZNS_ZS_EMPTY: + return "EMPTY"; + case NVME_ZNS_ZS_IMPL_OPEN: + return "IMP_OPENED"; + case NVME_ZNS_ZS_EXPL_OPEN: + return "EXP_OPENED"; + case NVME_ZNS_ZS_CLOSED: + return "CLOSED"; + case NVME_ZNS_ZS_READ_ONLY: + return "READONLY"; + case NVME_ZNS_ZS_FULL: + return "FULL"; + case NVME_ZNS_ZS_OFFLINE: + return "OFFLINE"; + default: + return "Unknown State"; + } +} + +void nvme_show_zns_report_zones(void *report, __u32 descs, + __u8 ext_size, __u32 report_size, unsigned long flags) +{ + struct nvme_zone_report *r = report; + struct nvme_zns_desc *desc; + int i; + + __u64 nr_zones = le64_to_cpu(r->nr_zones); + + if (nr_zones < descs) + descs = nr_zones; + + if (flags & BINARY) + return d_raw((unsigned char *)report, report_size); + + printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(r->nr_zones)); + for (i = 0; i < descs; i++) { + desc = (struct nvme_zns_desc *) + (report + sizeof(*r) + i * (sizeof(*desc) + ext_size)); + printf("SLBA: 0x%-8"PRIx64" WP: 0x%-8"PRIx64" Cap: 0x%-8"PRIx64" State: %-12s Type: %-14s Attrs: 0x%-x\n", + (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp), + (uint64_t)le64_to_cpu(desc->zcap), zone_state_to_string(desc->zs >> 4), + zone_type_to_string(desc->zt), desc->za); + + if (ext_size) { + printf("Extension Data: "); + if (desc->za & NVME_ZNS_ZA_ZDEV) { + d((unsigned char *)desc + sizeof(*desc), ext_size, 16, 1); + printf("..\n"); + } else { + printf(" Not valid\n"); + } + } + } +} + static void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset) { __u32 nent = nvmset->nid; - struct json_array *entries; + struct json_object *entries; struct json_object *root; int i; @@ -2926,12 +4202,83 @@ void nvme_show_id_nvmset(struct nvme_id_nvmset *nvmset, unsigned nvmset_id, } } +static void json_nvme_primary_ctrl_caps(const struct nvme_primary_ctrl_caps *caps) +{ + struct json_object *root; + + root = json_create_object(); + + json_object_add_value_uint(root, "cntlid", le16_to_cpu(caps->cntlid)); + json_object_add_value_uint(root, "portid", le16_to_cpu(caps->portid)); + json_object_add_value_uint(root, "crt", caps->crt); + + json_object_add_value_int(root, "vqfrt", le32_to_cpu(caps->vqfrt)); + json_object_add_value_int(root, "vqrfa", le32_to_cpu(caps->vqrfa)); + json_object_add_value_int(root, "vqrfap", le16_to_cpu(caps->vqrfap)); + json_object_add_value_int(root, "vqprt", le16_to_cpu(caps->vqprt)); + json_object_add_value_int(root, "vqfrsm", le16_to_cpu(caps->vqfrsm)); + json_object_add_value_int(root, "vqgran", le16_to_cpu(caps->vqgran)); + + json_object_add_value_int(root, "vifrt", le32_to_cpu(caps->vifrt)); + json_object_add_value_int(root, "virfa", le32_to_cpu(caps->virfa)); + json_object_add_value_int(root, "virfap", le16_to_cpu(caps->virfap)); + json_object_add_value_int(root, "viprt", le16_to_cpu(caps->viprt)); + json_object_add_value_int(root, "vifrsm", le16_to_cpu(caps->vifrsm)); + json_object_add_value_int(root, "vigran", le16_to_cpu(caps->vigran)); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +static void nvme_show_primary_ctrl_caps_crt(__u8 crt) +{ + __u8 rsvd = (crt & 0xFC) >> 2; + __u8 vi = (crt & 0x2) >> 1; + __u8 vq = crt & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] %#x\tVI Resources are %ssupported\n", vi, vi ? "" : "not "); + printf(" [0:0] %#x\tVQ Resources are %ssupported\n", vq, vq ? "" : "not "); +} + +void nvme_show_primary_ctrl_caps(const struct nvme_primary_ctrl_caps *caps, + enum nvme_print_flags flags) +{ + int human = flags & VERBOSE; + + if (flags & BINARY) + return d_raw((unsigned char *)caps, sizeof(*caps)); + else if (flags & JSON) + return json_nvme_primary_ctrl_caps(caps); + + printf("NVME Identify Primary Controller Capabilities:\n"); + printf("cntlid : %#x\n", le16_to_cpu(caps->cntlid)); + printf("portid : %#x\n", le16_to_cpu(caps->portid)); + printf("crt : %#x\n", caps->crt); + if (human) + nvme_show_primary_ctrl_caps_crt(caps->crt); + printf("vqfrt : %d\n", le32_to_cpu(caps->vqfrt)); + printf("vqrfa : %d\n", le32_to_cpu(caps->vqrfa)); + printf("vqrfap : %d\n", le16_to_cpu(caps->vqrfap)); + printf("vqprt : %d\n", le16_to_cpu(caps->vqprt)); + printf("vqfrsm : %d\n", le16_to_cpu(caps->vqfrsm)); + printf("vqgran : %d\n", le16_to_cpu(caps->vqgran)); + printf("vifrt : %d\n", le32_to_cpu(caps->vifrt)); + printf("virfa : %d\n", le32_to_cpu(caps->virfa)); + printf("virfap : %d\n", le16_to_cpu(caps->virfap)); + printf("viprt : %d\n", le16_to_cpu(caps->viprt)); + printf("vifrsm : %d\n", le16_to_cpu(caps->vifrsm)); + printf("vigran : %d\n", le16_to_cpu(caps->vigran)); +} + static void json_nvme_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list, __u32 count) { const struct nvme_secondary_controller_entry *sc_entry = &sc_list->sc_entry[0]; __u32 nent = min(sc_list->num, count); - struct json_array *entries; + struct json_object *entries; struct json_object *root; int i; @@ -3011,7 +4358,7 @@ static void json_nvme_id_ns_granularity_list( { int i; struct json_object *root; - struct json_array *entries; + struct json_object *entries; root = json_create_object(); @@ -3067,7 +4414,7 @@ void nvme_show_id_ns_granularity_list(const struct nvme_id_ns_granularity_list * static void json_nvme_id_uuid_list(const struct nvme_id_uuid_list *uuid_list) { struct json_object *root; - struct json_array *entries; + struct json_object *entries; int i; root = json_create_object(); @@ -3140,9 +4487,19 @@ void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list, } } +void nvme_show_id_iocs(struct nvme_id_iocs *iocs) +{ + __u16 i; + + for (i = 0; i < 512; i++) + if (iocs->iocs[i]) + printf("I/O Command Set Combination[%u]:%"PRIx64"\n", i, + (uint64_t)le64_to_cpu(iocs->iocs[i])); +} + static const char *nvme_trtype_to_string(__u8 trtype) { - switch(trtype) { + switch (trtype) { case 0: return "The transport type is not indicated or the error "\ "is not transport related."; case 1: return "RDMA Transport error."; @@ -3174,9 +4531,11 @@ void nvme_show_error_log(struct nvme_error_log_page *err_log, int entries, le64_to_cpu(err_log[i].error_count)); printf("sqid : %d\n", err_log[i].sqid); printf("cmdid : %#x\n", err_log[i].cmdid); - printf("status_field : %#x(%s)\n", err_log[i].status_field, + printf("status_field : %#x(%s)\n", err_log[i].status_field >> 0x1, nvme_status_to_string( le16_to_cpu(err_log[i].status_field) >> 1)); + printf("phase_tag : %#x\n", + le16_to_cpu(err_log[i].status_field & 0x1)); printf("parm_err_loc : %#x\n", err_log[i].parm_error_location); printf("lba : %#"PRIx64"\n", @@ -3503,7 +4862,7 @@ void nvme_show_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname, else if (flags & JSON) return json_ana_log(ana_log, devname); - printf("Asynchronous Namespace Access Log for NVMe device: %s\n", + printf("Asymmetric Namespace Access Log for NVMe device: %s\n", devname); printf("ANA LOG HEADER :-\n"); printf("chgcnt : %"PRIu64"\n", @@ -3608,20 +4967,22 @@ static void nvme_show_self_test_result(struct nvme_self_test_res *res, res->vs[0], res->vs[1]); } -void nvme_show_self_test_log(struct nvme_self_test_log *self_test, const char *devname, - enum nvme_print_flags flags) +void nvme_show_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries, + __u32 size, const char *devname, enum nvme_print_flags flags) { int i; + __u8 num_entries; if (flags & BINARY) - return d_raw((unsigned char *)self_test, sizeof(*self_test)); + return d_raw((unsigned char *)self_test, size); if (flags & JSON) - return json_self_test_log(self_test); + return json_self_test_log(self_test, dst_entries); printf("Device Self Test Log for NVME device:%s\n", devname); printf("Current operation : %#x\n", self_test->crnt_dev_selftest_oprn); printf("Current Completion : %u%%\n", self_test->crnt_dev_selftest_compln); - for (i = 0; i < NVME_ST_REPORTS; i++) { + num_entries = min(dst_entries, NVME_ST_REPORTS); + for (i = 0; i < num_entries; i++) { printf("Self Test Result[%d]:\n", i); nvme_show_self_test_result(&self_test->result[i], flags); } @@ -3704,9 +5065,10 @@ void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize, le32_to_cpu(sanitize->est_crypto_erase_time_with_no_deallocate)); } -const char *nvme_feature_to_string(int feature) +const char *nvme_feature_to_string(enum nvme_feat feature) { switch (feature) { + case NVME_FEAT_NONE: return "Reserved"; case NVME_FEAT_ARBITRATION: return "Arbitration"; case NVME_FEAT_POWER_MGMT: return "Power Management"; case NVME_FEAT_LBA_RANGE: return "LBA Range Type"; @@ -3725,6 +5087,9 @@ const char *nvme_feature_to_string(int feature) case NVME_FEAT_RRL: return "Read Recovery Level"; case NVME_FEAT_PLM_CONFIG: return "Predicatable Latency Mode Config"; case NVME_FEAT_PLM_WINDOW: return "Predicatable Latency Mode Window"; + case NVME_LBA_STATUS_INFO: return "LBA Status Infomation Attributes"; + case NVME_FEAT_ENDURANCE: return "Enduarance Event Group Configuration"; + case NVME_FEAT_IOCS_PROFILE: return "I/O Command Set Profile"; case NVME_FEAT_SW_PROGRESS: return "Software Progress"; case NVME_FEAT_HOST_ID: return "Host Identifier"; case NVME_FEAT_RESV_MASK: return "Reservation Notification Mask"; @@ -3734,8 +5099,13 @@ const char *nvme_feature_to_string(int feature) case NVME_FEAT_HCTM: return "Host Controlled Thermal Management"; case NVME_FEAT_HOST_BEHAVIOR: return "Host Behavior"; case NVME_FEAT_SANITIZE: return "Sanitize"; - default: return "Unknown"; } + /* + * We don't use the "default:" statement to let the compiler warning if + * some values of the enum nvme_feat are missing in the switch(). + * The following return is acting as the default: statement. + */ + return "Unknown"; } const char *nvme_register_to_string(int reg) @@ -3778,9 +5148,9 @@ void nvme_show_select_result(__u32 result) printf(" Feature is changeable\n"); } -const char *nvme_status_to_string(__u32 status) +const char *nvme_status_to_string(__u16 status) { - switch (status & 0x3ff) { + switch (status & 0x7ff) { case NVME_SC_SUCCESS: return "SUCCESS: The command completed successfully"; case NVME_SC_INVALID_OPCODE: @@ -3839,6 +5209,14 @@ const char *nvme_status_to_string(__u32 status) return "SANITIZE_FAILED: The most recent sanitize operation failed and no recovery actions has been successfully completed"; case NVME_SC_SANITIZE_IN_PROGRESS: return "SANITIZE_IN_PROGRESS: The requested function is prohibited while a sanitize operation is in progress"; + case NVME_SC_IOCS_NOT_SUPPORTED: + return "IOCS_NOT_SUPPORTED: The I/O command set is not supported"; + case NVME_SC_IOCS_NOT_ENABLED: + return "IOCS_NOT_ENABLED: The I/O command set is not enabled"; + case NVME_SC_IOCS_COMBINATION_REJECTED: + return "IOCS_COMBINATION_REJECTED: The I/O command set combination is rejected"; + case NVME_SC_INVALID_IOCS: + return "INVALID_IOCS: the I/O command set is invalid"; case NVME_SC_LBA_RANGE: return "LBA_RANGE: The command references a LBA that exceeds the size of the namespace"; case NVME_SC_NS_WRITE_PROTECTED: @@ -3853,6 +5231,22 @@ const char *nvme_status_to_string(__u32 status) return "RESERVATION_CONFLICT: The command was aborted due to a conflict with a reservation held on the accessed namespace"; case NVME_SC_FORMAT_IN_PROGRESS: return "FORMAT_IN_PROGRESS: A Format NVM command is in progress on the namespace."; + case NVME_SC_ZONE_BOUNDARY_ERROR: + return "ZONE_BOUNDARY_ERROR: Invalid Zone Boundary crossing"; + case NVME_SC_ZONE_IS_FULL: + return "ZONE_IS_FULL: The accessed zone is in ZSF:Full state"; + case NVME_SC_ZONE_IS_READ_ONLY: + return "ZONE_IS_READ_ONLY: The accessed zone is in ZSRO:Read Only state"; + case NVME_SC_ZONE_IS_OFFLINE: + return "ZONE_IS_OFFLINE: The access zone is in ZSO:Offline state"; + case NVME_SC_ZONE_INVALID_WRITE: + return "ZONE_INVALID_WRITE: The write to zone was not at the write pointer offset"; + case NVME_SC_TOO_MANY_ACTIVE_ZONES: + return "TOO_MANY_ACTIVE_ZONES: The controller does not allow additional active zones"; + case NVME_SC_TOO_MANY_OPEN_ZONES: + return "TOO_MANY_OPEN_ZONES: The controller does not allow additional open zones"; + case NVME_SC_ZONE_INVALID_STATE_TRANSITION: + return "INVALID_ZONE_STATE_TRANSITION: The zone state change was invalid"; case NVME_SC_CQ_INVALID: return "CQ_INVALID: The Completion Queue identifier specified in the command does not exist"; case NVME_SC_QID_INVALID: @@ -3927,6 +5321,12 @@ const char *nvme_status_to_string(__u32 status) return "ANA_ATTACH_FAIL: The controller is not attached to the namespace as a result of an ANA condition"; case NVME_SC_BAD_ATTRIBUTES: return "BAD_ATTRIBUTES: Bad attributes were given"; + case NVME_SC_INVALID_PI: + return "INVALID_PROTECION_INFO: The Protection Information Field settings specified in the command are invalid"; + case NVME_SC_READ_ONLY: + return "WRITE_ATTEMPT_READ_ONLY_RANGE: The LBA range specified contains read-only blocks"; + case NVME_SC_CMD_SIZE_LIMIT_EXCEEDED: + return "CMD_SIZE_LIMIT_EXCEEDED: Command size limit exceeded"; case NVME_SC_WRITE_FAULT: return "WRITE_FAULT: The write data could not be committed to the media"; case NVME_SC_READ_ERROR: @@ -3943,12 +5343,20 @@ const char *nvme_status_to_string(__u32 status) return "ACCESS_DENIED: Access to the namespace and/or LBA range is denied due to lack of access rights"; case NVME_SC_UNWRITTEN_BLOCK: return "UNWRITTEN_BLOCK: The command failed due to an attempt to read from an LBA range containing a deallocated or unwritten logical block"; + case NVME_SC_INTERNAL_PATH_ERROR: + return "INTERNAL_PATH_ERROT: The command was not completed as the result of a controller internal error"; case NVME_SC_ANA_PERSISTENT_LOSS: return "ASYMMETRIC_NAMESPACE_ACCESS_PERSISTENT_LOSS: The requested function (e.g., command) is not able to be performed as a result of the relationship between the controller and the namespace being in the ANA Persistent Loss state"; case NVME_SC_ANA_INACCESSIBLE: return "ASYMMETRIC_NAMESPACE_ACCESS_INACCESSIBLE: The requested function (e.g., command) is not able to be performed as a result of the relationship between the controller and the namespace being in the ANA Inaccessible state"; case NVME_SC_ANA_TRANSITION: return "ASYMMETRIC_NAMESPACE_ACCESS_TRANSITION: The requested function (e.g., command) is not able to be performed as a result of the relationship between the controller and the namespace transitioning between Asymmetric Namespace Access states"; + case NVME_SC_CTRL_PATHING_ERROR: + return "CONTROLLER_PATHING_ERROR: A pathing error was detected by the controller"; + case NVME_SC_HOST_PATHING_ERROR: + return "HOST_PATHING_ERROR: A pathing error was detected by the host"; + case NVME_SC_HOST_CMD_ABORT: + return "HOST_COMMAND_ABORT: The command was aborted as a result of host action"; case NVME_SC_CMD_INTERRUPTED: return "CMD_INTERRUPTED: Command processing was interrupted and the controller is unable to successfully complete the command. The host should retry the command."; case NVME_SC_PMR_SAN_PROHIBITED: @@ -3967,7 +5375,7 @@ static const char *nvme_feature_lba_type_to_string(__u8 type) case 3: return "Cache"; case 4: return "Page / Swap file"; default: - if (type>=0x05 && type<=0x7f) + if (type >= 0x05 && type <= 0x7f) return "Reserved"; else return "Vendor Specific"; @@ -4019,8 +5427,7 @@ static const char *nvme_feature_temp_type_to_string(__u8 type) static const char *nvme_feature_temp_sel_to_string(__u8 sel) { - switch (sel) - { + switch (sel) { case 0: return "Composite Temperature"; case 1: return "Temperature Sensor 1"; case 2: return "Temperature Sensor 2"; @@ -4077,13 +5484,13 @@ static void nvme_show_timestamp(struct nvme_timestamp *ts) static void nvme_show_host_mem_buffer(struct nvme_host_mem_buffer *hmb) { printf("\tHost Memory Descriptor List Entry Count (HMDLEC): %u\n", - hmb->hmdlec); + le32_to_cpu(hmb->hmdlec)); printf("\tHost Memory Descriptor List Address (HMDLAU): 0x%x\n", - hmb->hmdlau); + le32_to_cpu(hmb->hmdlau)); printf("\tHost Memory Descriptor List Address (HMDLAL): 0x%x\n", - hmb->hmdlal); + le32_to_cpu(hmb->hmdlal)); printf("\tHost Memory Buffer Size (HSIZE): %u\n", - hmb->hsize); + le32_to_cpu(hmb->hsize)); } static void nvme_directive_show_fields(__u8 dtype, __u8 doper, @@ -4121,6 +5528,8 @@ static void nvme_directive_show_fields(__u8 dtype, __u8 doper, *(__u16 *) (field + 2)); printf("\tNVM Subsystem Streams Open (NSSO): %u\n", *(__u16 *) (field + 4)); + printf("\tNVM Subsystem Stream Capability (NSSC): %u\n", + *(__u16 *) (field + 6)); printf("\tStream Write Size (in unit of LB size) (SWS): %u\n", *(__u32 *) (field + 16)); printf("\tStream Granularity Size (in unit of SWS) (SGS): %u\n", @@ -4183,6 +5592,11 @@ static const char *nvme_plm_window(__u32 plm) } } +void nvme_show_lba_status_info(__u32 result) { + printf("\tLBA Status Information Poll Interval (LSIPI) : %u\n", (result >> 16) & 0xffff); + printf("\tLBA Status Information Report Interval (LSIRI): %u\n", result & 0xffff); +} + static void nvme_show_plm_config(struct nvme_plm_config *plmcfg) { printf("\tEnable Event :%04x\n", le16_to_cpu(plmcfg->enable_event)); @@ -4191,12 +5605,15 @@ static void nvme_show_plm_config(struct nvme_plm_config *plmcfg) printf("\tDTWIN Time Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwin_time_thresh)); } -void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf) +void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned char *buf) { __u8 field; uint64_t ull; switch (fid) { + case NVME_FEAT_NONE: + printf("\tFeature Identifier Reserved\n"); + break; case NVME_FEAT_ARBITRATION: printf("\tHigh Priority Weight (HPW): %u\n", ((result & 0xff000000) >> 24) + 1); printf("\tMedium Priority Weight (MPW): %u\n", ((result & 0x00ff0000) >> 16) + 1); @@ -4247,6 +5664,10 @@ void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf printf("\tDisable Normal (DN): %s\n", (result & 0x00000001) ? "True":"False"); break; case NVME_FEAT_ASYNC_EVENT: + printf("\tEndurance Group Event Aggregate Log Change Notices: %s\n", ((result & 0x00004000) >> 14) ? "Send async event":"Do not send async event"); + printf("\tLBA Status Information Notices : %s\n", ((result & 0x00002000) >> 13) ? "Send async event":"Do not send async event"); + printf("\tPredictable Latency Event Aggregate Log Change Notices: %s\n", ((result & 0x00001000) >> 12) ? "Send async event":"Do not send async event"); + printf("\tAsymmetric Namespace Access Change Notices: %s\n", ((result & 0x00000800) >> 11) ? "Send async event":"Do not send async event"); printf("\tTelemetry Log Notices : %s\n", ((result & 0x00000400) >> 10) ? "Send async event":"Do not send async event"); printf("\tFirmware Activation Notices : %s\n", ((result & 0x00000200) >> 9) ? "Send async event":"Do not send async event"); printf("\tNamespace Attribute Notices : %s\n", ((result & 0x00000100) >> 8) ? "Send async event":"Do not send async event"); @@ -4257,7 +5678,6 @@ void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf nvme_show_auto_pst((struct nvme_auto_pst *)buf); break; case NVME_FEAT_HOST_MEM_BUF: - printf("\tMemory Return (MR): %s\n", ((result & 0x00000002) >> 1) ? "True":"False"); printf("\tEnable Host Memory (EHM): %s\n", (result & 0x00000001) ? "Enabled":"Disabled"); nvme_show_host_mem_buffer((struct nvme_host_mem_buffer *)buf); break; @@ -4271,6 +5691,16 @@ void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf case NVME_FEAT_PLM_WINDOW: printf("\tWindow Select: %s", nvme_plm_window(result)); break; + case NVME_LBA_STATUS_INFO: + nvme_show_lba_status_info(result); + break; + case NVME_FEAT_ENDURANCE: + printf("\tEndurance Group Identifier (ENDGID): %u\n", result & 0xffff); + printf("\tEndurance Group Critical Warnings : %u\n", (result >> 16) & 0xff); + break; + case NVME_FEAT_IOCS_PROFILE: + printf("\tI/O Command Set Comination Index(IOCSCI): %u\n", result & 0x1ff); + break; case NVME_FEAT_HOST_ID: ull = buf[7]; ull <<= 8; ull |= buf[6]; ull <<= 8; ull |= buf[5]; ull <<= 8; ull |= buf[4]; ull <<= 8; ull |= buf[3]; ull <<= 8; ull |= buf[2]; ull <<= 8; @@ -4304,6 +5734,12 @@ void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf case NVME_FEAT_HOST_BEHAVIOR: printf("\tHost Behavior Support: %s\n", (buf[0] & 0x1) ? "True" : "False"); break; + case NVME_FEAT_SANITIZE: + printf("\tNo-Deallocate Response Mode (NODRM) : %u\n", result & 0x1); + break; + case NVME_FEAT_RRL: + printf("\tRead Recovery Level (RRL): %u\n", result & 0xf); + break; } } @@ -4351,13 +5787,20 @@ static void nvme_show_list_item(struct nvme_namespace *n) const char *l_suffix = suffix_binary_get(&lba); char usage[128]; - char format[128]; + char format[128], path[256]; + struct stat st; + int ret; + + sprintf(path, "%s%s", n->ctrl->path, n->name); + ret = stat(path, &st); + if (ret < 0) + return; sprintf(usage,"%6.2f %2sB / %6.2f %2sB", nuse, u_suffix, nsze, s_suffix); sprintf(format,"%3.0f %2sB + %2d B", (double)lba, l_suffix, le16_to_cpu(n->ns.lbaf[(n->ns.flbas & 0x0f)].ms)); - printf("/dev/%-11s %-*.*s %-*.*s %-9d %-26s %-16s %-.*s\n", n->name, + printf("%-21s %-*.*s %-*.*s %-9d %-26s %-16s %-.*s\n", path, (int)sizeof(n->ctrl->id.sn), (int)sizeof(n->ctrl->id.sn), n->ctrl->id.sn, (int)sizeof(n->ctrl->id.mn), (int)sizeof(n->ctrl->id.mn), n->ctrl->id.mn, n->nsid, usage, format, (int)sizeof(n->ctrl->id.fr), n->ctrl->id.fr); @@ -4367,9 +5810,9 @@ static void nvme_show_simple_list(struct nvme_topology *t) { int i, j, k; - printf("%-16s %-20s %-40s %-9s %-26s %-16s %-8s\n", + printf("%-21s %-20s %-40s %-9s %-26s %-16s %-8s\n", "Node", "SN", "Model", "Namespace", "Usage", "Format", "FW Rev"); - printf("%-.16s %-.20s %-.40s %-.9s %-.26s %-.16s %-.8s\n", dash, dash, + printf("%-.21s %-.20s %-.40s %-.9s %-.26s %-.16s %-.8s\n", dash, dash, dash, dash, dash, dash, dash); for (i = 0; i < t->nr_subsystems; i++) { @@ -4409,16 +5852,28 @@ static void nvme_show_details_ns(struct nvme_namespace *n, bool ctrl) sprintf(format,"%3.0f %2sB + %2d B", (double)lba, l_suffix, le16_to_cpu(n->ns.lbaf[(n->ns.flbas & 0x0f)].ms)); - printf("%-12s %-8x %-26s %-16s ", n->name, n->nsid, usage, format); + printf("%-12s %-8d %-26s %-16s ", n->name, n->nsid, usage, format); if (ctrl) printf("%s", n->ctrl->name); else { struct nvme_subsystem *s = n->ctrl->subsys; - int i; + int i, j; + bool comma = false; - for (i = 0; i < s->nr_ctrls; i++) - printf("%s%s", i ? ", " : "", s->ctrls[i].name); + for (i = 0; i < s->nr_ctrls; i++) { + struct nvme_ctrl *c = &s->ctrls[i]; + + for (j = 0; j < c->nr_namespaces; j++) { + struct nvme_namespace *ns = &c->namespaces[j]; + + if (ns->nsid == n->nsid) { + printf("%s%s", comma ? ", " : "", + c->name); + comma = true; + } + } + } } printf("\n"); } @@ -4456,15 +5911,11 @@ static void nvme_show_detailed_list(struct nvme_topology *t) printf("%-8s %-.20s %-.40s %-.8s %-6s %-14s %-12s ", c->name, c->id.sn, c->id.mn, c->id.fr, - c->transport, c->address, s->name); + c->transport ? : "", c->address ? : "", s->name); for (k = 0; k < c->nr_namespaces; k++) { struct nvme_namespace *n = &c->namespaces[k]; - printf("%s%s", comma ? ", " : "", n->name); - comma = true; - } - for (k = 0; k < s->nr_namespaces; k++) { - struct nvme_namespace *n = &s->namespaces[k]; + printf("%s%s", comma ? ", " : "", n->name); comma = true; } @@ -4479,18 +5930,21 @@ static void nvme_show_detailed_list(struct nvme_topology *t) for (i = 0; i < t->nr_subsystems; i++) { struct nvme_subsystem *s = &t->subsystems[i]; - for (j = 0; j < s->nr_ctrls; j++) { - struct nvme_ctrl *c = &s->ctrls[j]; + if (s->nr_namespaces) { + for (j = 0; j < s->nr_namespaces; j++) { + struct nvme_namespace *n = &s->namespaces[j]; + nvme_show_details_ns(n, false); + } + } else { + for (j = 0; j < s->nr_ctrls; j++) { + struct nvme_ctrl *c = &s->ctrls[j]; - for (k = 0; k < c->nr_namespaces; k++) { - struct nvme_namespace *n = &c->namespaces[k]; - nvme_show_details_ns(n, true); + for (k = 0; k < c->nr_namespaces; k++) { + struct nvme_namespace *n = &c->namespaces[k]; + nvme_show_details_ns(n, true); + } } } - for (j = 0; j < s->nr_namespaces; j++) { - struct nvme_namespace *n = &s->namespaces[j]; - nvme_show_details_ns(n, false); - } } } @@ -4517,7 +5971,7 @@ static void json_detail_list(struct nvme_topology *t) { int i, j, k; struct json_object *root; - struct json_array *devices; + struct json_object *devices; char formatter[41] = { 0 }; root = json_create_object(); @@ -4526,7 +5980,7 @@ static void json_detail_list(struct nvme_topology *t) for (i = 0; i < t->nr_subsystems; i++) { struct nvme_subsystem *s = &t->subsystems[i]; struct json_object *subsys_attrs; - struct json_array *namespaces, *ctrls; + struct json_object *namespaces, *ctrls; subsys_attrs = json_create_object(); json_object_add_value_string(subsys_attrs, "Subsystem", s->name); @@ -4537,12 +5991,15 @@ static void json_detail_list(struct nvme_topology *t) for (j = 0; j < s->nr_ctrls; j++) { struct json_object *ctrl_attrs = json_create_object(); struct nvme_ctrl *c = &s->ctrls[j]; - struct json_array *namespaces; + struct json_object *namespaces; json_object_add_value_string(ctrl_attrs, "Controller", c->name); - json_object_add_value_string(ctrl_attrs, "Transport", c->transport); - json_object_add_value_string(ctrl_attrs, "Address", c->address); - json_object_add_value_string(ctrl_attrs, "State", c->state); + if (c->transport) + json_object_add_value_string(ctrl_attrs, "Transport", c->transport); + if (c->address) + json_object_add_value_string(ctrl_attrs, "Address", c->address); + if (c->state) + json_object_add_value_string(ctrl_attrs, "State", c->state); if (c->hostnqn) json_object_add_value_string(ctrl_attrs, "HostNQN", c->hostnqn); if (c->hostid) @@ -4596,16 +6053,21 @@ static void json_detail_list(struct nvme_topology *t) json_free_object(root); } -static void json_simple_ns(struct nvme_namespace *n, struct json_array *devices) +static void json_simple_ns(struct nvme_namespace *n, struct json_object *devices) { struct json_object *device_attrs; char formatter[41] = { 0 }; double nsze, nuse; - int index = -1; + int ret, index = -1; long long lba; char *devnode; + struct stat st; + + if (asprintf(&devnode, "%s%s", n->ctrl->path, n->name) < 0) + return; - if (asprintf(&devnode, "/dev/%s", n->name) < 0) + ret = stat(devnode, &st); + if (ret < 0) return; device_attrs = json_create_object(); @@ -4629,7 +6091,7 @@ static void json_simple_ns(struct nvme_namespace *n, struct json_array *devices) json_object_add_value_string(device_attrs, "ModelNumber", formatter); - if (index >= 0 && !strcmp(n->ctrl->transport, "pcie")) { + if (index >= 0 && n->ctrl->transport && !strcmp(n->ctrl->transport, "pcie")) { char *product = nvme_product_name(index); json_object_add_value_string(device_attrs, "ProductName", product); @@ -4658,7 +6120,7 @@ static void json_simple_ns(struct nvme_namespace *n, struct json_array *devices) static void json_simple_list(struct nvme_topology *t) { struct json_object *root; - struct json_array *devices; + struct json_object *devices; int i, j, k; root = json_create_object(); -- cgit v1.2.3