summaryrefslogtreecommitdiffstats
path: root/plugins/solidigm/solidigm-telemetry/header.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/solidigm/solidigm-telemetry/header.c')
-rw-r--r--plugins/solidigm/solidigm-telemetry/header.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/plugins/solidigm/solidigm-telemetry/header.c b/plugins/solidigm/solidigm-telemetry/header.c
new file mode 100644
index 0000000..866ebff
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/header.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "common.h"
+#include "header.h"
+
+#pragma pack(push, reason_indentifier, 1)
+struct reason_indentifier_1_0 {
+ uint16_t versionMajor;
+ uint16_t versionMinor;
+ uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
+ char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020")
+ char FirmwareVersion[12]; //! Similar to IdentifyController.FR
+ char BootloaderVersion[12]; //! Bootloader version string
+ char SerialNumber[20]; //! Device serial number
+ uint8_t Reserved[56]; //! Reserved for future usage
+};
+static_assert(sizeof(const struct reason_indentifier_1_0) ==
+ MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
+ "Size mismatch for reason_indentifier_1_0");
+
+struct reason_indentifier_1_1 {
+ uint16_t versionMajor;
+ uint16_t versionMinor;
+ uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
+ char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020")
+ char FirmwareVersion[12]; //! Similar to IdentifyController.FR
+ char BootloaderVersion[12]; //! Bootloader version string
+ char SerialNumber[20]; //! Device serial number
+ uint64_t OemDataMapOffset; //! Customer Data Map Object Log Offset
+ uint8_t TelemetryMajorVersion; //! Shadow of version in TOC
+ uint8_t TelemetryMinorVersion; //! Shadow of version in TOC
+ uint8_t Reserved[46]; //! Reserved for future usage
+};
+static_assert(sizeof(const struct reason_indentifier_1_1) ==
+ MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
+ "Size mismatch for reason_indentifier_1_1");
+
+struct reason_indentifier_1_2 {
+ uint16_t versionMajor;
+ uint16_t versionMinor;
+ uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
+ char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020")
+ uint8_t Reserved1[24]; //! pad over Fields removed from version 1.1
+ char SerialNumber[20]; //! Device serial number
+ uint64_t OemDataMapOffset; //! Customer Data Map Object Log Offset
+ uint8_t TelemetryMajorVersion; //! Shadow of version in TOC
+ uint8_t TelemetryMinorVersion; //! Shadow of version in TOC
+ uint8_t ProductFamilyId;
+ uint8_t Reserved2[5]; //! Reserved for future usage
+ uint8_t DualPortReserved[40]; //! Reserved for dual port
+};
+static_assert(sizeof(const struct reason_indentifier_1_2) ==
+ MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
+ "Size mismatch for reason_indentifier_1_2");
+#pragma pack(pop, reason_indentifier)
+
+static void telemetry_log_reason_id_parse1_0_ext(const struct telemetry_log *tl,
+ struct json_object *reason_id)
+{
+ const struct reason_indentifier_1_0 *ri;
+ struct json_object *reserved;
+
+ ri = (struct reason_indentifier_1_0 *) tl->log->rsnident;
+ json_object_object_add(reason_id, "firmwareVersion",
+ json_object_new_string_len(ri->FirmwareVersion,
+ sizeof(ri->FirmwareVersion)));
+ json_object_object_add(reason_id, "bootloaderVersion",
+ json_object_new_string_len(ri->BootloaderVersion,
+ sizeof(ri->BootloaderVersion)));
+ json_object_object_add(reason_id, "serialNumber",
+ json_object_new_string_len(ri->SerialNumber,
+ sizeof(ri->SerialNumber)));
+
+ reserved = json_create_array();
+ json_object_add_value_array(reason_id, "reserved", reserved);
+ for (int i = 0; i < sizeof(ri->Reserved); i++) {
+ struct json_object *val = json_object_new_int(ri->Reserved[i]);
+
+ json_object_array_add(reserved, val);
+ }
+}
+
+static void telemetry_log_reason_id_parse1_1_ext(const struct telemetry_log *tl,
+ struct json_object *reason_id)
+{
+ const struct reason_indentifier_1_1 *ri;
+ struct json_object *reserved;
+
+ ri = (struct reason_indentifier_1_1 *) tl->log->rsnident;
+ json_object_object_add(reason_id, "firmwareVersion",
+ json_object_new_string_len(ri->FirmwareVersion,
+ sizeof(ri->FirmwareVersion)));
+ json_object_object_add(reason_id, "bootloaderVersion",
+ json_object_new_string_len(ri->BootloaderVersion,
+ sizeof(ri->BootloaderVersion)));
+ json_object_object_add(reason_id, "serialNumber",
+ json_object_new_string_len(ri->SerialNumber,
+ sizeof(ri->SerialNumber)));
+ json_object_add_value_uint64(reason_id, "oemDataMapOffset",
+ le64_to_cpu(ri->OemDataMapOffset));
+ json_object_add_value_uint(reason_id, "telemetryMajorVersion",
+ le16_to_cpu(ri->TelemetryMajorVersion));
+ json_object_add_value_uint(reason_id, "telemetryMinorVersion",
+ le16_to_cpu(ri->TelemetryMinorVersion));
+
+ reserved = json_create_array();
+ json_object_add_value_array(reason_id, "reserved", reserved);
+ for (int i = 0; i < sizeof(ri->Reserved); i++) {
+ struct json_object *val = json_object_new_int(ri->Reserved[i]);
+
+ json_object_array_add(reserved, val);
+ }
+}
+
+static void telemetry_log_reason_id_parse1_2_ext(const struct telemetry_log *tl,
+ struct json_object *reason_id)
+{
+ const struct reason_indentifier_1_2 *ri;
+ struct json_object *dp_reserved;
+ struct json_object *reserved;
+
+ ri = (struct reason_indentifier_1_2 *) tl->log->rsnident;
+
+ json_object_object_add(reason_id, "serialNumber",
+ json_object_new_string_len(ri->SerialNumber,
+ sizeof(ri->SerialNumber)));
+ json_object_add_value_uint64(reason_id, "oemDataMapOffset",
+ le64_to_cpu(ri->OemDataMapOffset));
+ json_object_add_value_uint(reason_id, "telemetryMajorVersion",
+ le16_to_cpu(ri->TelemetryMajorVersion));
+ json_object_add_value_uint(reason_id, "telemetryMinorVersion",
+ le16_to_cpu(ri->TelemetryMinorVersion));
+ json_object_add_value_uint(reason_id, "productFamilyId", ri->ProductFamilyId);
+
+ reserved = json_create_array();
+ json_object_add_value_array(reason_id, "reserved2", reserved);
+ for (int i = 0; i < sizeof(ri->Reserved2); i++) {
+ struct json_object *val = json_object_new_int(ri->Reserved2[i]);
+
+ json_object_array_add(reserved, val);
+ }
+
+ dp_reserved = json_create_array();
+ json_object_add_value_array(reason_id, "dualPortReserved", dp_reserved);
+ for (int i = 0; i < sizeof(ri->DualPortReserved); i++) {
+ struct json_object *val = json_object_new_int(ri->DualPortReserved[i]);
+
+ json_object_array_add(dp_reserved, val);
+ }
+}
+
+static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *tl, struct json_object *reason_id)
+{
+ const struct reason_indentifier_1_0 *ri1_0 =
+ (struct reason_indentifier_1_0 *) tl->log->rsnident;
+ uint16_t version_major = le16_to_cpu(ri1_0->versionMajor);
+ uint16_t version_minor = le16_to_cpu(ri1_0->versionMinor);
+
+ json_object_add_value_uint(reason_id, "versionMajor", version_major);
+ json_object_add_value_uint(reason_id, "versionMinor", version_minor);
+ json_object_add_value_uint(reason_id, "reasonCode", le32_to_cpu(ri1_0->reasonCode));
+ json_object_add_value_object(reason_id, "driveStatus",
+ json_object_new_string_len(ri1_0->DriveStatus,
+ sizeof(ri1_0->DriveStatus)));
+ if (version_major == 1) {
+ switch (version_minor) {
+ case 0:
+ telemetry_log_reason_id_parse1_0_ext(tl, reason_id);
+ break;
+ case 1:
+ telemetry_log_reason_id_parse1_1_ext(tl, reason_id);
+ break;
+ default:
+ telemetry_log_reason_id_parse1_2_ext(tl, reason_id);
+ break;
+ }
+ }
+}
+
+bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl)
+{
+ const struct nvme_telemetry_log *log;
+ struct json_object *ieee_oui_id;
+ struct json_object *reason_id;
+ struct json_object *header;
+
+ if (tl->log_size < sizeof(const struct nvme_telemetry_log)) {
+ SOLIDIGM_LOG_WARNING("Telemetry log too short.");
+ return false;
+ }
+
+ header = json_create_object();
+
+ json_object_object_add(tl->root, "telemetryHeader", header);
+ log = tl->log;
+
+ json_object_add_value_uint(header, "logIdentifier", log->lpi);
+ ieee_oui_id = json_create_array();
+
+ json_object_object_add(header, "ieeeOuiIdentifier", ieee_oui_id);
+ for (int i = 0; i < sizeof(log->ieee); i++) {
+ struct json_object *val = json_object_new_int(log->ieee[i]);
+
+ json_object_array_add(ieee_oui_id, val);
+ }
+ json_object_add_value_uint(header, "dataArea1LastBlock", log->dalb1);
+ json_object_add_value_uint(header, "dataArea2LastBlock", log->dalb2);
+ json_object_add_value_uint(header, "dataArea3LastBlock", log->dalb3);
+ json_object_add_value_uint(header, "hostInitiatedDataGeneration", log->hostdgn);
+ json_object_add_value_uint(header, "controllerInitiatedDataAvailable", log->ctrlavail);
+ json_object_add_value_uint(header, "controllerInitiatedDataGeneration", log->ctrldgn);
+
+ reason_id = json_create_object();
+ json_object_add_value_object(header, "reasonIdentifier", reason_id);
+ solidigm_telemetry_log_reason_id_parse(tl, reason_id);
+
+ return true;
+}