diff --git a/libnvme/src/nvme/types.h b/libnvme/src/nvme/types.h index 311bf78b23..1a479a6a0b 100644 --- a/libnvme/src/nvme/types.h +++ b/libnvme/src/nvme/types.h @@ -4554,6 +4554,36 @@ enum nvme_pel_ehai_pit { NVME_PEL_EHAI_PIT_NOT_ASSOCIATED = 3, }; +/** + * enum nvme_pel_vsedt_code - Persistent Event Log - Vendor Specific Event Data Type Code + * @NVME_PEL_VSEDT_RSVD: Reserved + * @NVME_PEL_VSEDT_EVENT_NAME: Event Name + * @NVME_PEL_VSEDT_ASCII_STRING: ASCII String + * @NVME_PEL_VSEDT_BINARY: Binary + * @NVME_PEL_VSEDT_SIGNED_INT: Signed Integer + */ +enum nvme_pel_vsedt_code { + NVME_PEL_VSEDT_RSVD = 0, + NVME_PEL_VSEDT_EVENT_NAME = 1, + NVME_PEL_VSEDT_ASCII_STRING = 2, + NVME_PEL_VSEDT_BINARY = 3, + NVME_PEL_VSEDT_SIGNED_INT = 4, +}; + +/** + * struct nvme_vs_event_desc - Vendor Specific Event Descriptor + * @vsec: Vendor Specific Event Code + * @vsedt: Vendor Specific Event Data Type + * @uidx: UUID Index + * @vsedl: Vendor Specific Event Data Length + */ +struct nvme_vs_event_desc { + __le16 vsec; + __u8 vsedt; + __u8 uidx; + __le16 vsedl; +}; + /** * struct nvme_fw_commit_event - Firmware Commit Event Data * @old_fw_rev: Old Firmware Revision diff --git a/nvme-print-json.c b/nvme-print-json.c index ca5d774830..b51485666f 100644 --- a/nvme-print-json.c +++ b/nvme-print-json.c @@ -1811,10 +1811,81 @@ static void json_pel_thermal_excursion(void *pevent_log_info, __u32 offset, obj_add_uint(valid_attrs, "threshold", thermal_exc_event->threshold); } +static void json_pel_vs_event_data(struct json_object *valid_attrs, void *vsed, + __u8 vsedt, __u16 vsedl) +{ + struct json_object *vs_data = json_create_object(); + char *str; + + switch (vsedt) { + case NVME_PEL_VSEDT_EVENT_NAME: + str = malloc(vsedl + 1); + if (str) { + memcpy(str, vsed, vsedl); + str[vsedl] = '\0'; + obj_add_str(vs_data, "event_name", str); + free(str); + } + break; + case NVME_PEL_VSEDT_ASCII_STRING: + str = malloc(vsedl + 1); + if (str) { + memcpy(str, vsed, vsedl); + str[vsedl] = '\0'; + obj_add_str(vs_data, "ascii_string_data", str); + free(str); + } + break; + case NVME_PEL_VSEDT_BINARY: + obj_d(vs_data, "binary_data", (unsigned char *)vsed, vsedl, 16, 1); + break; + case NVME_PEL_VSEDT_SIGNED_INT: + obj_add_int(vs_data, "signed_integer_data", *(int64_t *)vsed); + break; + default: + obj_d(vs_data, "reserved_data_type_bin", (unsigned char *)vsed, vsedl, 16, 1); + break; + } + + obj_add_obj(valid_attrs, "vs_event_data", vs_data); +} + +static void json_pel_vendor_specific_event(void *pevent_log_info, __u32 offset, + __u32 event_data_len, struct json_object *valid_attrs) +{ + __u32 progress = 0; + __u16 vsedl; + uint i; + struct nvme_vs_event_desc *vs_desc; + struct json_object *vs_events = json_create_array(); + + for (i = 0; progress < event_data_len; i++) { + struct json_object *vs_event = json_create_object(); + + vs_desc = pevent_log_info + offset + progress; + vsedl = le16_to_cpu(vs_desc->vsedl); + + obj_add_uint(vs_event, "vs_event_descriptor_number", i); + obj_add_uint(vs_event, "vs_event_code", le16_to_cpu(vs_desc->vsec)); + obj_add_uint(vs_event, "vs_event_data_type", vs_desc->vsedt); + obj_add_uint(vs_event, "vs_event_uuid_index", vs_desc->uidx); + obj_add_uint(vs_event, "vs_event_data_len", vsedl); + + if (vsedl) + json_pel_vs_event_data(vs_event, vs_desc + 1, vs_desc->vsedt, vsedl); + + array_add_obj(vs_events, vs_event); + progress += sizeof(*vs_desc) + vsedl; + } + + obj_add_array(valid_attrs, "vs_event_entry", vs_events); +} + static void json_pevent_entry(void *pevent_log_info, __u8 action, __u32 size, const char *devname, __u32 offset, struct json_object *valid) { int i; + __u16 vsil, el; struct nvme_persistent_event_log *pevent_log_head = pevent_log_info; struct nvme_persistent_event_entry *pevent_entry_head; struct json_object *valid_attrs; @@ -1824,8 +1895,10 @@ static void json_pevent_entry(void *pevent_log_info, __u8 action, __u32 size, co break; pevent_entry_head = pevent_log_info + offset; + vsil = le16_to_cpu(pevent_entry_head->vsil); + el = le16_to_cpu(pevent_entry_head->el); - if (offset + pevent_entry_head->ehl + 3 + le16_to_cpu(pevent_entry_head->el) >= + if (offset + pevent_entry_head->ehl + 3 + el >= size) break; @@ -1841,10 +1914,14 @@ static void json_pevent_entry(void *pevent_log_info, __u8 action, __u32 size, co obj_add_uint64(valid_attrs, "event_time_stamp", le64_to_cpu(pevent_entry_head->ets)); obj_add_uint(valid_attrs, "port_id", le16_to_cpu(pevent_entry_head->pelpid)); - obj_add_uint(valid_attrs, "vu_info_len", le16_to_cpu(pevent_entry_head->vsil)); - obj_add_uint(valid_attrs, "event_len", le16_to_cpu(pevent_entry_head->el)); + obj_add_uint(valid_attrs, "vu_info_len", vsil); + obj_add_uint(valid_attrs, "event_len", el); + + if (vsil) + obj_d(valid_attrs, "vs_info_bin", + (void *)pevent_entry_head + 1, vsil, 16, 1); - offset += pevent_entry_head->ehl + 3; + offset += pevent_entry_head->ehl + vsil + 3; switch (pevent_entry_head->etype) { case NVME_PEL_SMART_HEALTH_EVENT: @@ -1887,6 +1964,10 @@ static void json_pevent_entry(void *pevent_log_info, __u8 action, __u32 size, co case NVME_PEL_THERMAL_EXCURSION_EVENT: json_pel_thermal_excursion(pevent_log_info, offset, valid_attrs); break; + case NVME_PEL_VENDOR_SPECIFIC_EVENT: + json_pel_vendor_specific_event(pevent_log_info, offset, el - vsil, + valid_attrs); + break; default: break; } diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 7995052a3e..d1333f2d95 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -312,6 +312,8 @@ void nvme_show_pel_header(struct nvme_persistent_event_log *pevent_log_head, int static void pel_event_header(int i, struct nvme_persistent_event_entry *pevent_entry_head, int human) { + __u16 vsil = le16_to_cpu(pevent_entry_head->vsil); + printf("Event Number: %u\n", i); printf("Event Type: %s\n", nvme_pel_event_to_string(pevent_entry_head->etype)); printf("Event Type Revision: %u\n", pevent_entry_head->etype_rev); @@ -324,8 +326,13 @@ static void pel_event_header(int i, struct nvme_persistent_event_entry *pevent_e printf("Controller Identifier: %u\n", le16_to_cpu(pevent_entry_head->cntlid)); printf("Event Timestamp: %"PRIu64"\n", le64_to_cpu(pevent_entry_head->ets)); printf("Port Identifier: %u\n", le16_to_cpu(pevent_entry_head->pelpid)); - printf("Vendor Specific Information Length: %u\n", le16_to_cpu(pevent_entry_head->vsil)); + printf("Vendor Specific Information Length: %u\n", vsil); printf("Event Length: %u\n", le16_to_cpu(pevent_entry_head->el)); + + if (vsil) { + printf("Vendor Specific Information:\n"); + d((void *)pevent_entry_head + 1, vsil, 16, 1); + } } static void pel_smart_health_event(void *pevent_log_info, __u32 offset, const char *devname) @@ -493,11 +500,62 @@ static void pel_thermal_excursion_event(void *pevent_log_info, __u32 offset) printf("Threshold: %u\n", thermal_exc_event->threshold); } +static void pel_vs_event_data(void *vsed, __u8 vsedt, __u16 vsedl) +{ + printf("Vendor Specific Event Data:\n"); + switch (vsedt) { + case NVME_PEL_VSEDT_EVENT_NAME: + printf("Event Name for Vendor Specific Event Code:\n"); + printf("%.*s\n", vsedl, (char *)vsed); + break; + case NVME_PEL_VSEDT_ASCII_STRING: + printf("ASCII String Data:\n"); + printf("%.*s\n", vsedl, (char *)vsed); + break; + case NVME_PEL_VSEDT_BINARY: + printf("Binary Data:\n"); + d(vsed, vsedl, 16, 1); + break; + case NVME_PEL_VSEDT_SIGNED_INT: + printf("Signed Integer Data: %" PRId64 "\n", (int64_t)vsedt); + break; + default: + printf("Reserved data type. As Binary:\n"); + d(vsed, vsedl, 16, 1); + } +} + +static void pel_vendor_specific_event(void *pevent_log_info, __u32 offset, + __u32 event_data_len) +{ + __u32 progress = 0; + __u16 vsedl; + int i; + struct nvme_vs_event_desc *vs_desc; + + printf("Vendor Specific Event Entry:\n"); + for (i = 0; progress < event_data_len; i++) { + vs_desc = pevent_log_info + offset + progress; + vsedl = le16_to_cpu(vs_desc->vsedl); + + printf("Vendor Specific Event Descriptor %u:\n", i); + printf("Vendor Specific Event Code: %u\n", le16_to_cpu(vs_desc->vsec)); + printf("Vendor Specific Event Data Type: %u\n", vs_desc->vsedt); + printf("Vendor Specific Event UIndex: %u\n", vs_desc->uidx); + printf("Vendor Specific Event Data Length: %u\n", vsedl); + if (vsedl) + pel_vs_event_data(vs_desc + 1, vs_desc->vsedt, + vsedl); + progress += sizeof(*vs_desc) + vsedl; + } +} + static void stdout_persistent_event_log(void *pevent_log_info, __u8 action, __u32 size, const char *devname) { struct nvme_persistent_event_log *pevent_log_head; __u32 offset = sizeof(*pevent_log_head); + __u16 vsil, el; struct nvme_persistent_event_entry *pevent_entry_head; int human = stdout_print_ops.flags & VERBOSE; @@ -522,14 +580,15 @@ static void stdout_persistent_event_log(void *pevent_log_info, __u8 action, __u3 break; pevent_entry_head = pevent_log_info + offset; + vsil = le16_to_cpu(pevent_entry_head->vsil); + el = le16_to_cpu(pevent_entry_head->el); - if ((offset + pevent_entry_head->ehl + 3 + - le16_to_cpu(pevent_entry_head->el)) >= size) + if ((offset + pevent_entry_head->ehl + 3 + el) >= size) break; pel_event_header(i, pevent_entry_head, human); - offset += pevent_entry_head->ehl + 3; + offset += pevent_entry_head->ehl + vsil + 3; switch (pevent_entry_head->etype) { case NVME_PEL_SMART_HEALTH_EVENT: @@ -574,11 +633,14 @@ static void stdout_persistent_event_log(void *pevent_log_info, __u8 action, __u3 case NVME_PEL_SANITIZE_MEDIA_VERIF_EVENT: printf("Sanitize Media Verification Event\n"); break; + case NVME_PEL_VENDOR_SPECIFIC_EVENT: + pel_vendor_specific_event(pevent_log_info, offset, el - vsil); + break; default: printf("Reserved Event\n\n"); break; } - offset += le16_to_cpu(pevent_entry_head->el); + offset += el; printf("\n"); } }