diff --git a/Documentation/nvme-ocp-persistent-event-log.txt b/Documentation/nvme-ocp-persistent-event-log.txt new file mode 100644 index 0000000000..4cb1f42ddb --- /dev/null +++ b/Documentation/nvme-ocp-persistent-event-log.txt @@ -0,0 +1,79 @@ +nvme-ocp-persistent-event-log(1) +================================ + +NAME +---- +nvme-ocp-persistent-event-log - Send NVMe persistent event log page request, +returns result and log additional OCP-specific data + +SYNOPSIS +-------- +[verse] +'nvme ocp persistent-event-log' [--action= | -a ] + [--log-len= | -l ] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Retrieves the NVMe persistent event log page from an NVMe device +and provides the returned structure. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). + +On success, the returned persistent event log structure may be returned +in one of several ways depending on the option flags; the structure may +parsed by the program and printed in a readable format or the raw buffer +may be printed to stdout for another program to parse. + +OPTIONS +------- +-a :: +--action=:: + While try to retrieve this log action the controller shall take + during processing this persistent log page command. This mandatory + field, based on the value issued it may Read Log Data, Establish + Context and Read Log Data or Release Context can occur. For More + details see NVM Express 1.4 Spec. Section 5.14.1.13 Persistent + Event Log (Log Identifier 0Dh) + +-l :: +--log-len=:: + Allocates a buffer of bytes size and requests this + many bytes be returned in the constructed NVMe command. This + param is mandatory. If given is 0 and action is 0, + it will read the Total Log Length(TLL) of the page. + +-b:: +--raw-binary:: + Print the raw persistent event log buffer to stdout. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* Print the persistent event log page in a human readable format: ++ +------------ +# nvme ocp persistent-event-log /dev/nvme0 +------------ ++ + +* Print the raw persistent event log to a file: ++ +------------ +# nvme ocp persistent-event-log /dev/nvme0 --raw-binary > persistent_log.raw +------------ ++ +It is probably a bad idea to not redirect stdout when using this mode. + +NVME +---- +Part of the nvme-user suite diff --git a/nvme-print-json.c b/nvme-print-json.c index 81510c5684..fa8cd5e222 100644 --- a/nvme-print-json.c +++ b/nvme-print-json.c @@ -1560,8 +1560,8 @@ static void json_add_bitmap(int i, __u8 seb, struct json_object *r) } } -static void json_pevent_log_head(struct nvme_persistent_event_log *pevent_log_head, - struct json_object *r) +void nvme_json_pevent_log_head(struct nvme_persistent_event_log *pevent_log_head, + struct json_object *r) { int i; char sn[sizeof(pevent_log_head->sn) + 1]; @@ -1596,8 +1596,8 @@ static void json_pevent_log_head(struct nvme_persistent_event_log *pevent_log_he } } -static void json_pel_smart_health(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs) +void nvme_json_pel_smart_health(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { char key[128]; struct nvme_smart_log *smart_event = pevent_log_info + offset; @@ -1654,7 +1654,8 @@ static void json_pel_smart_health(void *pevent_log_info, __u32 offset, le32_to_cpu(smart_event->thm_temp2_total_time)); } -static void json_pel_fw_commit(void *pevent_log_info, __u32 offset, struct json_object *valid_attrs) +void nvme_json_pel_fw_commit(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { char fw_str[50]; struct nvme_fw_commit_event *fw_commit_event = pevent_log_info + offset; @@ -1673,7 +1674,8 @@ static void json_pel_fw_commit(void *pevent_log_info, __u32 offset, struct json_ le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc)); } -static void json_pel_timestamp(void *pevent_log_info, __u32 offset, struct json_object *valid_attrs) +void nvme_json_pel_timestamp(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { struct nvme_time_stamp_change_event *ts_change_event = pevent_log_info + offset; @@ -1682,8 +1684,9 @@ static void json_pel_timestamp(void *pevent_log_info, __u32 offset, struct json_ le64_to_cpu(ts_change_event->ml_secs_since_reset)); } -static void json_pel_power_on_reset(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs, __le16 vsil, __le16 el) +void nvme_json_pel_power_on_reset(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs, + __le16 vsil, __le16 el) { __u64 *fw_rev; char fw_str[50]; @@ -1711,8 +1714,8 @@ static void json_pel_power_on_reset(void *pevent_log_info, __u32 offset, } } -static void json_pel_nss_hw_error(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs) +void nvme_json_pel_nss_hw_error(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { struct nvme_nss_hw_err_event *nss_hw_err_event = pevent_log_info + offset; @@ -1720,7 +1723,8 @@ static void json_pel_nss_hw_error(void *pevent_log_info, __u32 offset, le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code)); } -static void json_pel_change_ns(void *pevent_log_info, __u32 offset, struct json_object *valid_attrs) +void nvme_json_pel_change_ns(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { struct nvme_change_ns_event *ns_event = pevent_log_info + offset; @@ -1735,8 +1739,8 @@ static void json_pel_change_ns(void *pevent_log_info, __u32 offset, struct json_ obj_add_uint(valid_attrs, "nsid", le32_to_cpu(ns_event->nsid)); } -static void json_pel_format_start(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs) +void nvme_json_pel_format_start(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { struct nvme_format_nvm_start_event *format_start_event = pevent_log_info + offset; @@ -1746,8 +1750,8 @@ static void json_pel_format_start(void *pevent_log_info, __u32 offset, le32_to_cpu(format_start_event->format_nvm_cdw10)); } -static void json_pel_format_completion(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs) +void nvme_json_pel_format_completion(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { struct nvme_format_nvm_compln_event *format_cmpln_event = pevent_log_info + offset; @@ -1757,8 +1761,8 @@ static void json_pel_format_completion(void *pevent_log_info, __u32 offset, obj_add_uint(valid_attrs, "compln_info", le16_to_cpu(format_cmpln_event->compln_info)); obj_add_uint(valid_attrs, "status_field", le32_to_cpu(format_cmpln_event->status_field)); } -static void json_pel_sanitize_start(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs) +void nvme_json_pel_sanitize_start(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { struct nvme_sanitize_start_event *sanitize_start_event = pevent_log_info + offset; @@ -1767,8 +1771,8 @@ static void json_pel_sanitize_start(void *pevent_log_info, __u32 offset, obj_add_uint(valid_attrs, "sani_cdw11", le32_to_cpu(sanitize_start_event->sani_cdw11)); } -static void json_pel_sanitize_completion(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs) +void nvme_json_pel_sanitize_completion(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { struct nvme_sanitize_compln_event *sanitize_cmpln_event = pevent_log_info + offset; @@ -1777,8 +1781,8 @@ static void json_pel_sanitize_completion(void *pevent_log_info, __u32 offset, obj_add_uint(valid_attrs, "cmpln_info", le16_to_cpu(sanitize_cmpln_event->cmpln_info)); } -static void json_pel_set_feature(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs) +void nvme_json_pel_set_feature(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { struct nvme_set_feature_event *set_feat_event = pevent_log_info + offset; int fid = NVME_GET(le32_to_cpu(set_feat_event->cdw_mem[0]), SET_FEATURES_CDW10_FID); @@ -1796,14 +1800,14 @@ static void json_pel_set_feature(void *pevent_log_info, __u32 offset, } } -static void json_pel_telemetry_crt(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs) +void nvme_json_pel_telemetry_crt(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { obj_d(valid_attrs, "create", pevent_log_info + offset, 512, 16, 1); } -static void json_pel_thermal_excursion(void *pevent_log_info, __u32 offset, - struct json_object *valid_attrs) +void nvme_json_pel_thermal_excursion(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) { struct nvme_thermal_exc_event *thermal_exc_event = pevent_log_info + offset; @@ -1850,8 +1854,9 @@ static void json_pel_vs_event_data(struct json_object *valid_attrs, void *vsed, 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) +void nvme_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; @@ -1925,48 +1930,49 @@ static void json_pevent_entry(void *pevent_log_info, __u8 action, __u32 size, co switch (pevent_entry_head->etype) { case NVME_PEL_SMART_HEALTH_EVENT: - json_pel_smart_health(pevent_log_info, offset, valid_attrs); + nvme_json_pel_smart_health(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_FW_COMMIT_EVENT: - json_pel_fw_commit(pevent_log_info, offset, valid_attrs); + nvme_json_pel_fw_commit(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_TIMESTAMP_EVENT: - json_pel_timestamp(pevent_log_info, offset, valid_attrs); + nvme_json_pel_timestamp(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_POWER_ON_RESET_EVENT: - json_pel_power_on_reset(pevent_log_info, offset, valid_attrs, - pevent_entry_head->vsil, pevent_entry_head->el); + nvme_json_pel_power_on_reset(pevent_log_info, offset, valid_attrs, + pevent_entry_head->vsil, + pevent_entry_head->el); break; case NVME_PEL_NSS_HW_ERROR_EVENT: - json_pel_nss_hw_error(pevent_log_info, offset, valid_attrs); + nvme_json_pel_nss_hw_error(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_CHANGE_NS_EVENT: - json_pel_change_ns(pevent_log_info, offset, valid_attrs); + nvme_json_pel_change_ns(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_FORMAT_START_EVENT: - json_pel_format_start(pevent_log_info, offset, valid_attrs); + nvme_json_pel_format_start(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_FORMAT_COMPLETION_EVENT: - json_pel_format_completion(pevent_log_info, offset, valid_attrs); + nvme_json_pel_format_completion(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_SANITIZE_START_EVENT: - json_pel_sanitize_start(pevent_log_info, offset, valid_attrs); + nvme_json_pel_sanitize_start(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_SANITIZE_COMPLETION_EVENT: - json_pel_sanitize_completion(pevent_log_info, offset, valid_attrs); + nvme_json_pel_sanitize_completion(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_SET_FEATURE_EVENT: - json_pel_set_feature(pevent_log_info, offset, valid_attrs); + nvme_json_pel_set_feature(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_TELEMETRY_CRT: - json_pel_telemetry_crt(pevent_log_info, offset, valid_attrs); + nvme_json_pel_telemetry_crt(pevent_log_info, offset, valid_attrs); break; case NVME_PEL_THERMAL_EXCURSION_EVENT: - json_pel_thermal_excursion(pevent_log_info, offset, valid_attrs); + nvme_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); + nvme_json_pel_vendor_specific_event(pevent_log_info, offset, el - vsil, + valid_attrs); break; default: break; @@ -1985,7 +1991,7 @@ static void json_persistent_event_log(void *pevent_log_info, __u8 action, __u32 offset = sizeof(struct nvme_persistent_event_log); if (size >= offset) { - json_pevent_log_head(pevent_log_info, r); + nvme_json_pevent_log_head(pevent_log_info, r); json_pevent_entry(pevent_log_info, action, size, devname, offset, valid); obj_add_array(r, "list_of_event_entries", valid); } else { diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index a920f79b39..94dd089c55 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -309,8 +309,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) +void nvme_show_pel_event_header(int i, struct nvme_persistent_event_entry *pevent_entry_head, + int human) { __u16 vsil = le16_to_cpu(pevent_entry_head->vsil); @@ -335,7 +335,8 @@ static void pel_event_header(int i, struct nvme_persistent_event_entry *pevent_e } } -static void pel_smart_health_event(void *pevent_log_info, __u32 offset, const char *devname) +void nvme_show_pel_smart_health_event(void *pevent_log_info, __u32 offset, + const char *devname) { struct nvme_smart_log *smart_event = pevent_log_info + offset; @@ -343,7 +344,7 @@ static void pel_smart_health_event(void *pevent_log_info, __u32 offset, const ch stdout_smart_log(smart_event, NVME_NSID_ALL, devname); } -static void pel_fw_commit_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_fw_commit_event(void *pevent_log_info, __u32 offset) { struct nvme_fw_commit_event *fw_commit_event = pevent_log_info + offset; @@ -360,7 +361,7 @@ static void pel_fw_commit_event(void *pevent_log_info, __u32 offset) le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc)); } -static void pel_timestamp_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_timestamp_event(void *pevent_log_info, __u32 offset) { struct nvme_time_stamp_change_event *ts_change_event = pevent_log_info + offset; @@ -370,8 +371,8 @@ static void pel_timestamp_event(void *pevent_log_info, __u32 offset) le64_to_cpu(ts_change_event->ml_secs_since_reset)); } -static void pel_power_on_reset_event(void *pevent_log_info, __u32 offset, - struct nvme_persistent_event_entry *pevent_entry_head) +void nvme_show_pel_power_on_reset_event(void *pevent_log_info, __u32 offset, + struct nvme_persistent_event_entry *pevent_entry_head) { __u64 *fw_rev; __u32 por_info_len = le16_to_cpu(pevent_entry_head->el) - @@ -398,7 +399,7 @@ static void pel_power_on_reset_event(void *pevent_log_info, __u32 offset, } } -static void pel_nss_hw_error_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_nss_hw_error_event(void *pevent_log_info, __u32 offset) { struct nvme_nss_hw_err_event *nss_hw_err_event = pevent_log_info + offset; @@ -407,7 +408,7 @@ static void pel_nss_hw_error_event(void *pevent_log_info, __u32 offset) nvme_nss_hw_error_to_string(nss_hw_err_event->nss_hw_err_event_code)); } -static void pel_change_ns_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_change_ns_event(void *pevent_log_info, __u32 offset) { struct nvme_change_ns_event *ns_event = pevent_log_info + offset; @@ -423,7 +424,7 @@ static void pel_change_ns_event(void *pevent_log_info, __u32 offset) printf("Namespace ID: %u\n", le32_to_cpu(ns_event->nsid)); } -static void pel_format_start_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_format_start_event(void *pevent_log_info, __u32 offset) { struct nvme_format_nvm_start_event *format_start_event = pevent_log_info + offset; @@ -433,7 +434,7 @@ static void pel_format_start_event(void *pevent_log_info, __u32 offset) printf("Format NVM CDW10: %u\n", le32_to_cpu(format_start_event->format_nvm_cdw10)); } -static void pel_format_completion_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_format_completion_event(void *pevent_log_info, __u32 offset) { struct nvme_format_nvm_compln_event *format_cmpln_event = pevent_log_info + offset; @@ -445,7 +446,7 @@ static void pel_format_completion_event(void *pevent_log_info, __u32 offset) printf("Status Field: %u\n", le32_to_cpu(format_cmpln_event->status_field)); } -static void pel_sanitize_start_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_sanitize_start_event(void *pevent_log_info, __u32 offset) { struct nvme_sanitize_start_event *sanitize_start_event = pevent_log_info + offset; @@ -455,7 +456,7 @@ static void pel_sanitize_start_event(void *pevent_log_info, __u32 offset) printf("Sanitize CDW11: %u\n", le32_to_cpu(sanitize_start_event->sani_cdw11)); } -static void pel_sanitize_completion_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_sanitize_completion_event(void *pevent_log_info, __u32 offset) { struct nvme_sanitize_compln_event *sanitize_cmpln_event = pevent_log_info + offset; @@ -465,7 +466,7 @@ static void pel_sanitize_completion_event(void *pevent_log_info, __u32 offset) printf("Completion Information: %u\n", le16_to_cpu(sanitize_cmpln_event->cmpln_info)); } -static void pel_set_feature_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_set_feature_event(void *pevent_log_info, __u32 offset) { int fid, cdw11, cdw12, dword_cnt; unsigned char *mem_buf; @@ -491,7 +492,7 @@ static void pel_set_feature_event(void *pevent_log_info, __u32 offset) } } -static void pel_thermal_excursion_event(void *pevent_log_info, __u32 offset) +void nvme_show_pel_thermal_excursion_event(void *pevent_log_info, __u32 offset) { struct nvme_thermal_exc_event *thermal_exc_event = pevent_log_info + offset; @@ -525,8 +526,8 @@ static void pel_vs_event_data(void *vsed, __u8 vsedt, __u16 vsedl) } } -static void pel_vendor_specific_event(void *pevent_log_info, __u32 offset, - __u32 event_data_len) +void nvme_show_pel_vendor_specific_event(void *pevent_log_info, __u32 offset, + __u32 event_data_len) { __u32 progress = 0; __u16 vsedl; @@ -586,55 +587,66 @@ static void stdout_persistent_event_log(void *pevent_log_info, __u8 action, __u3 if ((offset + pevent_entry_head->ehl + 3 + el) >= size) break; - pel_event_header(i, pevent_entry_head, human); + nvme_show_pel_event_header(i, pevent_entry_head, human); offset += pevent_entry_head->ehl + vsil + 3; switch (pevent_entry_head->etype) { case NVME_PEL_SMART_HEALTH_EVENT: - pel_smart_health_event(pevent_log_info, offset, devname); + nvme_show_pel_smart_health_event(pevent_log_info, + offset, devname); break; case NVME_PEL_FW_COMMIT_EVENT: - pel_fw_commit_event(pevent_log_info, offset); + nvme_show_pel_fw_commit_event(pevent_log_info, offset); break; case NVME_PEL_TIMESTAMP_EVENT: - pel_timestamp_event(pevent_log_info, offset); + nvme_show_pel_timestamp_event(pevent_log_info, offset); break; case NVME_PEL_POWER_ON_RESET_EVENT: - pel_power_on_reset_event(pevent_log_info, offset, pevent_entry_head); + nvme_show_pel_power_on_reset_event(pevent_log_info, + offset, + pevent_entry_head); break; case NVME_PEL_NSS_HW_ERROR_EVENT: - pel_nss_hw_error_event(pevent_log_info, offset); + nvme_show_pel_nss_hw_error_event(pevent_log_info, + offset); break; case NVME_PEL_CHANGE_NS_EVENT: - pel_change_ns_event(pevent_log_info, offset); + nvme_show_pel_change_ns_event(pevent_log_info, offset); break; case NVME_PEL_FORMAT_START_EVENT: - pel_format_start_event(pevent_log_info, offset); + nvme_show_pel_format_start_event(pevent_log_info, + offset); break; case NVME_PEL_FORMAT_COMPLETION_EVENT: - pel_format_completion_event(pevent_log_info, offset); + nvme_show_pel_format_completion_event(pevent_log_info, + offset); break; case NVME_PEL_SANITIZE_START_EVENT: - pel_sanitize_start_event(pevent_log_info, offset); + nvme_show_pel_sanitize_start_event(pevent_log_info, + offset); break; case NVME_PEL_SANITIZE_COMPLETION_EVENT: - pel_sanitize_completion_event(pevent_log_info, offset); + nvme_show_pel_sanitize_completion_event(pevent_log_info, + offset); break; case NVME_PEL_SET_FEATURE_EVENT: - pel_set_feature_event(pevent_log_info, offset); + nvme_show_pel_set_feature_event(pevent_log_info, + offset); break; case NVME_PEL_TELEMETRY_CRT: d(pevent_log_info + offset, 512, 16, 1); break; case NVME_PEL_THERMAL_EXCURSION_EVENT: - pel_thermal_excursion_event(pevent_log_info, offset); + nvme_show_pel_thermal_excursion_event(pevent_log_info, + offset); break; 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); + nvme_show_pel_vendor_specific_event(pevent_log_info, + offset, el - vsil); break; default: printf("Reserved Event\n\n"); diff --git a/nvme-print.h b/nvme-print.h index 0f371d8502..45413e5ec5 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -375,6 +375,56 @@ void nvme_show_pull_model_ddc_req_log(struct nvme_pull_model_ddc_req_log *log, nvme_print_flags_t flags); void nvme_show_log(const char *devname, struct nvme_get_log_args *args, nvme_print_flags_t flags); void nvme_show_pel_header(struct nvme_persistent_event_log *pevent_log_head, int human); +void nvme_show_pel_event_header(int i, struct nvme_persistent_event_entry *pevent_entry_head, + int human); +void nvme_show_pel_smart_health_event(void *pevent_log_info, __u32 offset, + const char *devname); +void nvme_show_pel_fw_commit_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_timestamp_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_power_on_reset_event(void *pevent_log_info, __u32 offset, + struct nvme_persistent_event_entry *pevent_entry_head); +void nvme_show_pel_nss_hw_error_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_change_ns_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_format_start_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_format_completion_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_sanitize_start_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_sanitize_completion_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_set_feature_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_thermal_excursion_event(void *pevent_log_info, __u32 offset); +void nvme_show_pel_vendor_specific_event(void *pevent_log_info, __u32 offset, + __u32 event_data_len); +void nvme_json_pevent_log_head(struct nvme_persistent_event_log *pevent_log_head, + struct json_object *r); +void nvme_json_pel_smart_health(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_fw_commit(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_timestamp(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_power_on_reset(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs, + __le16 vsil, __le16 el); +void nvme_json_pel_nss_hw_error(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_change_ns(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_format_start(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_format_completion(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_sanitize_start(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_sanitize_completion(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_set_feature(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_telemetry_crt(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_thermal_excursion(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs); +void nvme_json_pel_vendor_specific_event(void *pevent_log_info, __u32 offset, + __u32 event_data_len, + struct json_object *valid_attrs); extern char *alloc_error; #endif /* NVME_PRINT_H */ diff --git a/plugins/ocp/ocp-nvme.c b/plugins/ocp/ocp-nvme.c index d7efc2cdb0..288293d070 100644 --- a/plugins/ocp/ocp-nvme.c +++ b/plugins/ocp/ocp-nvme.c @@ -195,6 +195,7 @@ static const char *type = "Error injection type"; static const char *nrtdp = "Number of reads to trigger device panic"; static const char *save = "Specifies that the controller shall save the attribute"; static const char *enable_ieee1667_silo = "enable IEEE1667 silo"; +static const char *raw_use = "use binary output"; static int get_c3_log_page(struct nvme_transport_handle *hdl, char *format) { @@ -2974,3 +2975,125 @@ static int hwcomp_log(int argc, char **argv, struct command *acmd, struct plugin { return ocp_hwcomp_log(argc, argv, acmd, plugin); } + +static int ocp_get_persistent_event_log(int argc, char **argv, + struct command *command, struct plugin *plugin) +{ + const char *desc = "Retrieve Persistent Event log info for the given " \ + "device in either decoded format(default), json or binary."; + const char *action = "action the controller shall take during " \ + "processing this persistent log page command."; + const char *log_len = "number of bytes to retrieve"; + + _cleanup_free_ struct nvme_persistent_event_log *pevent = NULL; + struct nvme_persistent_event_log *pevent_collected = NULL; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; + _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; + _cleanup_nvme_transport_handle_ struct nvme_transport_handle *hdl = NULL; + + nvme_print_flags_t flags; + void *pevent_log_info; + int err; + + struct config { + __u8 action; + __u32 log_len; + bool raw_binary; + }; + + struct config cfg = { + .action = 0xff, + .log_len = 0, + .raw_binary = false, + }; + + NVME_ARGS(opts, + OPT_BYTE("action", 'a', &cfg.action, action), + OPT_UINT("log_len", 'l', &cfg.log_len, log_len), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use)); + + err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(nvme_cfg.output_format, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } + + if (cfg.raw_binary) + flags = BINARY; + + pevent = nvme_alloc(sizeof(*pevent)); + if (!pevent) + return -ENOMEM; + + err = nvme_get_log_persistent_event(hdl, cfg.action, + pevent, sizeof(*pevent)); + if (err < 0) { + nvme_show_error("persistent event log: %s", nvme_strerror(err)); + return err; + } else if (err) { + nvme_show_status(err); + return err; + } + + if (cfg.action == NVME_PEVENT_LOG_RELEASE_CTX) { + printf("Releasing Persistent Event Log Context\n"); + return 0; + } + + if (!cfg.log_len && cfg.action != NVME_PEVENT_LOG_EST_CTX_AND_READ) { + cfg.log_len = le64_to_cpu(pevent->tll); + } else if (!cfg.log_len && cfg.action == NVME_PEVENT_LOG_EST_CTX_AND_READ) { + printf("Establishing Persistent Event Log Context\n"); + return 0; + } + + /* + * if header already read with context establish action 0x1, + * action shall not be 0x1 again in the subsequent request, + * until the current context is released by issuing action + * with 0x2, otherwise throws command sequence error, make + * it as zero to read the log page + */ + if (cfg.action == NVME_PEVENT_LOG_EST_CTX_AND_READ) + cfg.action = NVME_PEVENT_LOG_READ; + + pevent_log_info = nvme_alloc_huge(cfg.log_len, &mh); + if (!pevent_log_info) { + nvme_show_error("failed to allocate huge memory"); + return -ENOMEM; + } + + err = nvme_get_log_persistent_event(hdl, cfg.action, + pevent_log_info, cfg.log_len); + if (!err) { + err = nvme_get_log_persistent_event(hdl, cfg.action, + pevent, + sizeof(*pevent)); + if (err < 0) { + nvme_show_error("persistent event log: %s", nvme_strerror(err)); + return err; + } else if (err) { + nvme_show_status(err); + return err; + } + pevent_collected = pevent_log_info; + if (pevent_collected->gen_number != pevent->gen_number) { + printf("Collected Persistent Event Log may be invalid,\n" + "Re-read the log is required\n"); + return -EINVAL; + } + + ocp_show_persistent_event_log(pevent_log_info, cfg.action, + cfg.log_len, nvme_transport_handle_get_name(hdl), flags); + } else if (err > 0) { + nvme_show_status(err); + } else { + nvme_show_error("persistent event log: %s", nvme_strerror(err)); + } + + return err; +} diff --git a/plugins/ocp/ocp-nvme.h b/plugins/ocp/ocp-nvme.h index 6a447b049e..1f38353965 100644 --- a/plugins/ocp/ocp-nvme.h +++ b/plugins/ocp/ocp-nvme.h @@ -48,6 +48,8 @@ PLUGIN(NAME("ocp", "OCP cloud SSD extensions", OCP_PLUGIN_VERSION), get_clear_pcie_correctable_error_counters) ENTRY("get-telemetry-profile", "Get Telemetry Profile Feature", ocp_get_telemetry_profile_feature) + ENTRY("persistent-event-log", "Retrieve Persistent Event Log with OCP events", + ocp_get_persistent_event_log) ) ); @@ -280,4 +282,28 @@ enum ocp_dssd_feature_id { OCP_FID_TEL_CFG, /* Telemetry Profile */ OCP_FID_DAEC, /* DSSD Asynchronous Event Configuration */ }; + +/* + * struct tcg_activity_event_data - TCG Activity Event Data + * @rsvd: Reserved + * @tcg_command_count: TCG Command Count + * @invoking_id: Invoking ID + * @method_id: Method ID + * @com_id: Com ID + * @protocol_id: Protocol ID + * @status: Status of the TCG command + * @process_time: Time in milliseconds to process command + * @tcg_activity_specific_context: Additional context for the TCG activity + */ +struct __packed tcg_activity_event_data { + __u8 rsvd[2]; + __le32 tcg_command_count; + __le64 invoking_id; + __le64 method_id; + __le16 com_id; + __le16 protocol_id; + __u8 status; + __le16 process_time; + __u8 tcg_activity_specific_context[10]; +}; #endif /* OCP_NVME_H */ diff --git a/plugins/ocp/ocp-print-binary.c b/plugins/ocp/ocp-print-binary.c index 50604296bc..d98a062dde 100644 --- a/plugins/ocp/ocp-print-binary.c +++ b/plugins/ocp/ocp-print-binary.c @@ -15,6 +15,12 @@ static void binary_hwcomp_log(struct hwcomp_log *log, __u32 id, bool list) d_raw((unsigned char *)log, log_bytes); } +static void binary_persistent_event_log(void *pevent_log_info, + __u8 action, __u32 size, const char *devname) +{ + d_raw((unsigned char *)pevent_log_info, size); +} + static void binary_c5_log(struct nvme_transport_handle *hdl, struct unsupported_requirement_log *log_data) { d_raw((unsigned char *)log_data, sizeof(*log_data)); @@ -43,6 +49,7 @@ static void binary_c7_log(struct nvme_transport_handle *hdl, struct tcg_configur static struct ocp_print_ops binary_print_ops = { .hwcomp_log = binary_hwcomp_log, + .persistent_event_log = binary_persistent_event_log, .c5_log = binary_c5_log, .c1_log = binary_c1_log, .c4_log = binary_c4_log, diff --git a/plugins/ocp/ocp-print-json.c b/plugins/ocp/ocp-print-json.c index 4a88ff2b23..1d873d9ca8 100644 --- a/plugins/ocp/ocp-print-json.c +++ b/plugins/ocp/ocp-print-json.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later +#include "util/json.h" #include "util/types.h" #include "common.h" #include "nvme-print.h" @@ -8,6 +9,71 @@ #include "ocp-smart-extended-log.h" #include "ocp-telemetry-decode.h" #include "ocp-nvme.h" +#include "ocp-utils.h" + +#define array_add_obj json_array_add_value_object +#define array_add_str json_array_add_value_string + +#define obj_add_array json_object_add_value_array +#define obj_add_int json_object_add_value_int +#define obj_add_obj json_object_add_value_object +#define obj_add_uint json_object_add_value_uint +#define obj_add_uint128 json_object_add_value_uint128 +#define obj_add_uint64 json_object_add_value_uint64 +#define obj_add_str json_object_add_value_string +#define obj_add_uint_02x json_object_add_uint_02x +#define obj_add_uint_0x json_object_add_uint_0x +#define obj_add_byte_array json_object_add_byte_array +#define obj_add_nprix64 json_object_add_nprix64 +#define obj_add_uint_0nx json_object_add_uint_0nx +#define obj_add_0nprix64 json_object_add_0nprix64 +#define obj_add_string json_object_add_string + +static void d_json(unsigned char *buf, int len, int width, int group, struct json_object *array) +{ + int i; + char ascii[32 + 1] = { 0 }; + + assert(width < sizeof(ascii)); + + for (i = 0; i < len; i++) { + ascii[i % width] = (buf[i] >= '!' && buf[i] <= '~') ? buf[i] : '.'; + if (!((i + 1) % width)) { + array_add_str(array, ascii); + memset(ascii, 0, sizeof(ascii)); + } + } + + if (strlen(ascii)) { + ascii[i % width + 1] = '\0'; + array_add_str(array, ascii); + } +} + +static void obj_d(struct json_object *o, const char *k, unsigned char *buf, int len, int width, + int group) +{ + struct json_object *data = json_create_array(); + + d_json(buf, len, width, group, data); + obj_add_array(o, k, data); +} + +static void obj_add_result(struct json_object *o, const char *v, ...) +{ + va_list ap; + + _cleanup_free_ char *value = NULL; + + va_start(ap, v); + + if (vasprintf(&value, v, ap) < 0) + value = alloc_error; + + obj_add_str(o, "Result", value); + + va_end(ap); +} static void print_hwcomp_desc_json(struct hwcomp_desc_entry *e, struct json_object *r) { @@ -1119,9 +1185,185 @@ static void json_c7_log(struct nvme_transport_handle *hdl, struct tcg_configurat json_free_object(root); } +static void pel_tcg_activity_event(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) +{ + __u16 vsedl; + struct nvme_vs_event_desc *vs_desc; + struct tcg_activity_event_data *tcg_event_data; + struct json_object *tcg_event_obj = json_create_object(); + + vs_desc = pevent_log_info + offset; + tcg_event_data = (struct tcg_activity_event_data *)(vs_desc + 1); + vsedl = le16_to_cpu(vs_desc->vsedl); + + /* Only one descriptor (0) defined for the TCG Activity Event */ + json_object_add_value_uint(tcg_event_obj, "vendor_specific_event_descriptor", + 0); + json_object_add_value_uint(tcg_event_obj, "vendor_specific_event_code", + le16_to_cpu(vs_desc->vsec)); + json_object_add_value_uint(tcg_event_obj, "vendor_specific_event_data_type", + vs_desc->vsedt); + json_object_add_value_uint(tcg_event_obj, "vendor_specific_event_uindex", + vs_desc->uidx); + json_object_add_value_uint(tcg_event_obj, "vendor_specific_event_data_length", + vsedl); + json_object_add_value_uint(tcg_event_obj, "tcg_command_count", + le32_to_cpu(tcg_event_data->tcg_command_count)); + json_object_add_value_uint64(tcg_event_obj, "invoking_id", + le64_to_cpu(tcg_event_data->invoking_id)); + json_object_add_value_uint64(tcg_event_obj, "method_id", + le64_to_cpu(tcg_event_data->method_id)); + json_object_add_value_uint(tcg_event_obj, "com_id", + le16_to_cpu(tcg_event_data->com_id)); + json_object_add_value_uint(tcg_event_obj, "protocol_id", + tcg_event_data->protocol_id); + json_object_add_value_uint(tcg_event_obj, "status", + tcg_event_data->status); + json_object_add_value_uint(tcg_event_obj, "process_time", + le16_to_cpu(tcg_event_data->process_time)); + obj_d(tcg_event_obj, "tcg_activity_specific_context", + (void *)tcg_event_data->tcg_activity_specific_context, 10, 16, 1); + + json_object_add_value_object(valid_attrs, "tcg_activity_event_data", + tcg_event_obj); +} + +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; + + for (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; + vsil = le16_to_cpu(pevent_entry_head->vsil); + el = le16_to_cpu(pevent_entry_head->el); + + if (offset + pevent_entry_head->ehl + 3 + el >= + size) + break; + + valid_attrs = json_create_object(); + + obj_add_uint(valid_attrs, "event_number", i); + obj_add_str(valid_attrs, "event_type", + nvme_pel_event_to_string(pevent_entry_head->etype)); + obj_add_uint(valid_attrs, "event_type_rev", pevent_entry_head->etype_rev); + obj_add_uint(valid_attrs, "event_header_len", pevent_entry_head->ehl); + obj_add_uint(valid_attrs, "event_header_additional_info", pevent_entry_head->ehai); + obj_add_uint(valid_attrs, "ctrl_id", le16_to_cpu(pevent_entry_head->cntlid)); + 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", 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 + vsil + 3; + + switch (pevent_entry_head->etype) { + case NVME_PEL_SMART_HEALTH_EVENT: + nvme_json_pel_smart_health(pevent_log_info, offset, + valid_attrs); + break; + case NVME_PEL_FW_COMMIT_EVENT: + nvme_json_pel_fw_commit(pevent_log_info, offset, + valid_attrs); + break; + case NVME_PEL_TIMESTAMP_EVENT: + nvme_json_pel_timestamp(pevent_log_info, offset, + valid_attrs); + break; + case NVME_PEL_POWER_ON_RESET_EVENT: + nvme_json_pel_power_on_reset(pevent_log_info, offset, + valid_attrs, + pevent_entry_head->vsil, + pevent_entry_head->el); + break; + case NVME_PEL_NSS_HW_ERROR_EVENT: + nvme_json_pel_nss_hw_error(pevent_log_info, offset, + valid_attrs); + break; + case NVME_PEL_CHANGE_NS_EVENT: + nvme_json_pel_change_ns(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_FORMAT_START_EVENT: + nvme_json_pel_format_start(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_FORMAT_COMPLETION_EVENT: + nvme_json_pel_format_completion(pevent_log_info, + offset, valid_attrs); + break; + case NVME_PEL_SANITIZE_START_EVENT: + nvme_json_pel_sanitize_start(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_SANITIZE_COMPLETION_EVENT: + nvme_json_pel_sanitize_completion(pevent_log_info, + offset, valid_attrs); + break; + case NVME_PEL_SET_FEATURE_EVENT: + nvme_json_pel_set_feature(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_TELEMETRY_CRT: + nvme_json_pel_telemetry_crt(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_THERMAL_EXCURSION_EVENT: + nvme_json_pel_thermal_excursion(pevent_log_info, + offset, valid_attrs); + break; + case NVME_PEL_VENDOR_SPECIFIC_EVENT: + if (ocp_is_tcg_activity_event(pevent_entry_head, el, + vsil)) + pel_tcg_activity_event(pevent_log_info, offset, + valid_attrs); + else + nvme_json_pel_vendor_specific_event(pevent_log_info, + offset, el - vsil, + valid_attrs); + break; + default: + break; + } + + array_add_obj(valid, valid_attrs); + offset += le16_to_cpu(pevent_entry_head->el); + } +} + +static void json_persistent_event_log(void *pevent_log_info, __u8 action, + __u32 size, const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *valid = json_create_array(); + __u32 offset = sizeof(struct nvme_persistent_event_log); + + if (size >= offset) { + nvme_json_pevent_log_head(pevent_log_info, r); + json_pevent_entry(pevent_log_info, action, size, devname, offset, valid); + obj_add_array(r, "list_of_event_entries", valid); + } else { + obj_add_result(r, "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"); + } + + json_print(r); +} + static struct ocp_print_ops json_print_ops = { .hwcomp_log = json_hwcomp_log, .fw_act_history = json_fw_activation_history, + .persistent_event_log = json_persistent_event_log, .smart_extended_log = json_smart_extended_log, .telemetry_log = json_telemetry_log, .c3_log = json_c3_log, diff --git a/plugins/ocp/ocp-print-stdout.c b/plugins/ocp/ocp-print-stdout.c index 185b99a3ac..8110f17670 100644 --- a/plugins/ocp/ocp-print-stdout.c +++ b/plugins/ocp/ocp-print-stdout.c @@ -8,6 +8,9 @@ #include "ocp-smart-extended-log.h" #include "ocp-telemetry-decode.h" #include "ocp-nvme.h" +#include "ocp-utils.h" + +static struct ocp_print_ops stdout_print_ops; static void print_hwcomp_desc(struct hwcomp_desc_entry *e, bool list, int num) { @@ -765,9 +768,154 @@ static void stdout_c7_log(struct nvme_transport_handle *hdl, struct tcg_configur printf("\n"); } +static void pel_tcg_activity_event(void *pevent_log_info, __u32 offset) +{ + __u16 vsedl; + struct nvme_vs_event_desc *vs_desc; + struct tcg_activity_event_data *tcg_event_data; + + printf("TCG Activity Event Entry:\n"); + vs_desc = pevent_log_info + offset; + tcg_event_data = (struct tcg_activity_event_data *)(vs_desc + 1); + vsedl = le16_to_cpu(vs_desc->vsedl); + + printf("Vendor Specific Event Descriptor 0:\n"); + 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); + printf("TCG Activity Event Data:\n"); + printf("TCG Command Count: %u\n", + le32_to_cpu(tcg_event_data->tcg_command_count)); + printf("Invoking ID: %" PRIu64 "\n", + le64_to_cpu(tcg_event_data->invoking_id)); + printf("Method ID: %" PRIu64 "\n", + le64_to_cpu(tcg_event_data->method_id)); + printf("Com ID: %u\n", le16_to_cpu(tcg_event_data->com_id)); + printf("Protocol ID: %u\n", tcg_event_data->protocol_id); + printf("Status: %u\n", tcg_event_data->status); + printf("Process Time: %u\n", + le16_to_cpu(tcg_event_data->process_time)); + printf("TCG Activity Specific Context:\n"); + d((void *)tcg_event_data->tcg_activity_specific_context, 10, 16, 1); +} + +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; + + printf("Persistent Event Log for device: %s\n", devname); + printf("Action for Persistent Event Log: %u\n", action); + + if (size < offset) { + 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; + } + + pevent_log_head = pevent_log_info; + + nvme_show_pel_header(pevent_log_head, human); + + 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; + vsil = le16_to_cpu(pevent_entry_head->vsil); + el = le16_to_cpu(pevent_entry_head->el); + + if ((offset + pevent_entry_head->ehl + 3 + el) >= size) + break; + + nvme_show_pel_event_header(i, pevent_entry_head, human); + + offset += pevent_entry_head->ehl + vsil + 3; + + switch (pevent_entry_head->etype) { + case NVME_PEL_SMART_HEALTH_EVENT: + nvme_show_pel_smart_health_event(pevent_log_info, + offset, devname); + break; + case NVME_PEL_FW_COMMIT_EVENT: + nvme_show_pel_fw_commit_event(pevent_log_info, offset); + break; + case NVME_PEL_TIMESTAMP_EVENT: + nvme_show_pel_timestamp_event(pevent_log_info, offset); + break; + case NVME_PEL_POWER_ON_RESET_EVENT: + nvme_show_pel_power_on_reset_event(pevent_log_info, + offset, + pevent_entry_head); + break; + case NVME_PEL_NSS_HW_ERROR_EVENT: + nvme_show_pel_nss_hw_error_event(pevent_log_info, + offset); + break; + case NVME_PEL_CHANGE_NS_EVENT: + nvme_show_pel_change_ns_event(pevent_log_info, offset); + break; + case NVME_PEL_FORMAT_START_EVENT: + nvme_show_pel_format_start_event(pevent_log_info, + offset); + break; + case NVME_PEL_FORMAT_COMPLETION_EVENT: + nvme_show_pel_format_completion_event(pevent_log_info, + offset); + break; + case NVME_PEL_SANITIZE_START_EVENT: + nvme_show_pel_sanitize_start_event(pevent_log_info, + offset); + break; + case NVME_PEL_SANITIZE_COMPLETION_EVENT: + nvme_show_pel_sanitize_completion_event(pevent_log_info, + offset); + break; + case NVME_PEL_SET_FEATURE_EVENT: + nvme_show_pel_set_feature_event(pevent_log_info, + offset); + break; + case NVME_PEL_TELEMETRY_CRT: + d(pevent_log_info + offset, 512, 16, 1); + break; + case NVME_PEL_THERMAL_EXCURSION_EVENT: + nvme_show_pel_thermal_excursion_event(pevent_log_info, + offset); + break; + case NVME_PEL_SANITIZE_MEDIA_VERIF_EVENT: + printf("Sanitize Media Verification Event\n"); + break; + case NVME_PEL_VENDOR_SPECIFIC_EVENT: + if (ocp_is_tcg_activity_event(pevent_entry_head, el, + vsil)) + pel_tcg_activity_event(pevent_log_info, + offset); + else + nvme_show_pel_vendor_specific_event(pevent_log_info, + offset, + el - vsil); + break; + default: + printf("Reserved Event\n\n"); + break; + } + offset += el; + printf("\n"); + } +} + static struct ocp_print_ops stdout_print_ops = { .hwcomp_log = stdout_hwcomp_log, .fw_act_history = stdout_fw_activation_history, + .persistent_event_log = stdout_persistent_event_log, .smart_extended_log = stdout_smart_extended_log, .telemetry_log = stdout_telemetry_log, .c3_log = stdout_c3_log, diff --git a/plugins/ocp/ocp-print.c b/plugins/ocp/ocp-print.c index 43acf729c2..0dc5ba59d0 100644 --- a/plugins/ocp/ocp-print.c +++ b/plugins/ocp/ocp-print.c @@ -36,6 +36,14 @@ void ocp_fw_act_history(const struct fw_activation_history *fw_history, nvme_pri ocp_print(fw_act_history, flags, fw_history); } +void ocp_show_persistent_event_log(void *pevent_log_info, + __u8 action, __u32 size, const char *devname, + nvme_print_flags_t flags) +{ + ocp_print(persistent_event_log, flags, + pevent_log_info, action, size, devname); +} + void ocp_smart_extended_log(struct ocp_smart_extended_log *log, unsigned int version, nvme_print_flags_t flags) { diff --git a/plugins/ocp/ocp-print.h b/plugins/ocp/ocp-print.h index 35b9e10c1a..a1a72aa34f 100644 --- a/plugins/ocp/ocp-print.h +++ b/plugins/ocp/ocp-print.h @@ -11,6 +11,7 @@ struct ocp_print_ops { void (*hwcomp_log)(struct hwcomp_log *log, __u32 id, bool list); void (*fw_act_history)(const struct fw_activation_history *fw_history); + void (*persistent_event_log)(void *pevent_log_info, __u8 action, __u32 size, const char *devname); void (*smart_extended_log)(struct ocp_smart_extended_log *log, unsigned int version); void (*telemetry_log)(struct ocp_telemetry_parse_options *options); void (*c3_log)(struct nvme_transport_handle *hdl, struct ssd_latency_monitor_log *log_data); @@ -37,6 +38,9 @@ static inline struct ocp_print_ops *ocp_get_json_print_ops(nvme_print_flags_t fl void ocp_show_hwcomp_log(struct hwcomp_log *log, __u32 id, bool list, nvme_print_flags_t flags); void ocp_fw_act_history(const struct fw_activation_history *fw_history, nvme_print_flags_t flags); +void ocp_show_persistent_event_log(void *pevent_log_info, + __u8 action, __u32 size, const char *devname, + nvme_print_flags_t flags); void ocp_smart_extended_log(struct ocp_smart_extended_log *log, unsigned int version, nvme_print_flags_t flags); void ocp_show_telemetry_log(struct ocp_telemetry_parse_options *options, nvme_print_flags_t flags); diff --git a/plugins/ocp/ocp-utils.c b/plugins/ocp/ocp-utils.c index a8c09992bc..c9fad63be7 100644 --- a/plugins/ocp/ocp-utils.c +++ b/plugins/ocp/ocp-utils.c @@ -58,3 +58,16 @@ int ocp_get_log_simple(struct nvme_transport_handle *hdl, return nvme_get_log(hdl, &cmd, false, NVME_LOG_PAGE_PDU_SIZE); } + +bool ocp_is_tcg_activity_event(struct nvme_persistent_event_entry *pevent_entry_head, + __u16 el, __u16 vsil) +{ + struct nvme_vs_event_desc *vs_desc = + (struct nvme_vs_event_desc *)(pevent_entry_head + 1); + + return pevent_entry_head->etype == NVME_PEL_VENDOR_SPECIFIC_EVENT && + pevent_entry_head->ehl == 0x15 && vsil == 0x04 && el == 0x30 && + le16_to_cpu(vs_desc->vsec) == 0x01 && + le16_to_cpu(vs_desc->vsedl) == 0x26 && + vs_desc->vsedt == NVME_PEL_VSEDT_BINARY; +} diff --git a/plugins/ocp/ocp-utils.h b/plugins/ocp/ocp-utils.h index 58eef7b031..422ec64b85 100644 --- a/plugins/ocp/ocp-utils.h +++ b/plugins/ocp/ocp-utils.h @@ -31,3 +31,14 @@ int ocp_get_uuid_index(struct nvme_transport_handle *hdl, __u8 *index); int ocp_find_uuid_index(struct nvme_id_uuid_list *uuid_list, __u8 *index); int ocp_get_log_simple(struct nvme_transport_handle *hdl, enum ocp_dssd_log_id lid, __u32 len, void *log); + +/** + * ocp_is_tcg_activity_event() - Determine if persistent event is TCG activity event + * @pevent_entry_head: persistent event entry head pointer + * @el: Event Length + * @vsil: Vendor Specific Information Length + * + * Return: true if TCG activity event, false otherwise. + */ +bool ocp_is_tcg_activity_event(struct nvme_persistent_event_entry *pevent_entry_head, + __u16 el, __u16 vsil);