diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-29 04:41:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-29 04:41:05 +0000 |
commit | 1cc8413aaf5f8fa6595aece1933462c096e88639 (patch) | |
tree | e97b4f25c511372d73bdd96c389c5f468d99138a /plugins/solidigm/solidigm-telemetry/cod.c | |
parent | Initial commit. (diff) | |
download | nvme-cli-upstream.tar.xz nvme-cli-upstream.zip |
Adding upstream version 2.4+really2.3.upstream/2.4+really2.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plugins/solidigm/solidigm-telemetry/cod.c')
-rw-r--r-- | plugins/solidigm/solidigm-telemetry/cod.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/plugins/solidigm/solidigm-telemetry/cod.c b/plugins/solidigm/solidigm-telemetry/cod.c new file mode 100644 index 0000000..be5685b --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/cod.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ +#include "common.h" +#include "cod.h" + +const char *oemDataMapDesc[] = { + "Media Read Count", //Uid 0x00 + "Host Read count", //Uid 0x01 + "Media Write Count", //Uid 0x02 + "Host Write Count", //Uid 0x03 + "Device Model", // 0x04 + "Serial Number", // 0x05 + "Firmware Revision", // 0x06 + "Drive Status", // 0x07 + "Minimum Temperature", // 0x08 + "Maximum Temperature", // 0x09 + "Power Loss Protection Status", // 0x0a + "Lifetime Unsafe Shutdown Count", // 0x0b + "Lifetime Power Cycle Count", // 0x0c + "Minimum Read Latency", // 0x0d + "Maximum Read Latency", // 0x0e + "Average Read Latency", // 0x0f + "Minimum Write Latency", // 0x10 + "Maximum Write Latency", // 0x11 + "Average Write Latency", // 0x12 + "Grown Defects Count", // 0x13 + "DQS Recovery Count", // 0x14 + "Program Fail Count", // 0x15 + "Erase Fail Count", // 0x16 + "Defrag Writes in Progress Count", // 0x17 + "Total Defrag Writes Count", // 0x18 + "Max Die Offline Number", // 0x19 + "Current Die Offline Number", // 0x1A + "XOR Enable Status", // 0x1B + "Media Life Used", // 0x1C + "Uncorrectable Error Count", // 0x1D + "Current Wear Range Delta", // 0x1E + "Read Errors Corrected by XOR", // 0x1F + "Background Data Refresh", // 0x20 + "Pmic Vin History Data 1 Min", // 0x21 + "Pmic Vin History Data 1 Max", // 0x22 + "Pmic Vin History Data 1 Avg", // 0x23 + "Pmic Vin History Data 2 Min", // 0x24 + "Pmic Vin History Data 2 Max", // 0x25 + "Pmic Vin History Data 2 Avg", // 0x26 + "Pmic Vin History Data Total Readings", // 0x27 + "All Time Current Max Wear Level", // 0x28 + "Media Wear Remaining", // 0x29 + "Total Non-Defrag Writes", // 0x2A + "Number of sectors relocated in reaction to an error" //Uid 0x2B = 43 +}; + +static const char * getOemDataMapDescription(__u32 id) +{ + if (id < (sizeof(oemDataMapDesc) / sizeof(oemDataMapDesc[0]))) { + return oemDataMapDesc[id]; + } + return "unknown"; +} + +#define OEMSIGNATURE 0x504D4443 + +#pragma pack(push, cod, 1) +struct cod_header +{ + uint32_t versionMajor; + uint32_t versionMinor; + uint32_t Signature; //!Fixed signature value (0x504D4443) for identification and validation + uint32_t MapSizeInBytes; //!Total size of the map data structure in bytes + uint32_t EntryCount; //!Total number of entries in the entry list + uint8_t Reserved[12]; +}; + +struct cod_item +{ + uint32_t DataFieldMapUid; //!The data field unique identifier value + uint32_t reserved1 : 8; + uint32_t dataFieldType : 8; + uint32_t issigned : 1; + uint32_t bigEndian : 1; + uint32_t dataInvalid : 1; + uint32_t reserved2 : 13; + uint32_t DataFieldSizeInBytes; + uint8_t Reserved1[4]; + uint64_t DataFieldOffset; + uint8_t Reserved2[8]; +}; + +struct cod_map +{ + struct cod_header header; + struct cod_item items[]; +}; + +#pragma pack(pop, cod) + +void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl) +{ + enum cod_field_type + { + INTEGER, + FLOAT, + STRING, + TWO_BYTE_ASCII, + FOUR_BYTE_ASCII, + + UNKNOWN = 0xFF, + }; + json_object *telemetry_header = NULL; + json_object *COD_offset = NULL; + json_object *reason_id = NULL; + + if (!json_object_object_get_ex(tl->root, "telemetryHeader", &telemetry_header)) + return; + if (!json_object_object_get_ex(telemetry_header, "reasonIdentifier", &reason_id)) + return; + if (!json_object_object_get_ex(reason_id, "OemDataMapOffset", &COD_offset)) + return; + + __u64 offset = json_object_get_int(COD_offset); + + if (offset == 0) { + return; + } + + if ((offset + sizeof(struct cod_header)) > tl->log_size) { + SOLIDIGM_LOG_WARNING("Warning: COD map header out of bounds."); + return; + } + + const struct cod_map *data = (struct cod_map *) (((__u8 *)tl->log ) + offset); + + uint32_t signature = be32_to_cpu(data->header.Signature); + if ( signature != OEMSIGNATURE){ + SOLIDIGM_LOG_WARNING("Warning: Unsupported COD data signature %x!", signature); + return; + } + if ((offset + data->header.MapSizeInBytes) > tl->log_size){ + SOLIDIGM_LOG_WARNING("Warning: COD map data out of bounds."); + return; + } + + json_object *cod = json_create_object(); + json_object_object_add(tl->root, "cod", cod); + + for (int i =0 ; i < data->header.EntryCount; i++) { + if ((offset + sizeof(struct cod_header) + (i + 1) * sizeof(struct cod_item)) > + tl->log_size){ + SOLIDIGM_LOG_WARNING("Warning: COD data out of bounds at item %d!", i); + return; + } + struct cod_item item = data->items[i]; + if (item.DataFieldOffset + item.DataFieldOffset > tl->log_size) { + continue; + } + if (item.dataInvalid) { + continue; + } + uint8_t *val = ((uint8_t *)tl->log )+ item.DataFieldOffset; + const char *key = getOemDataMapDescription(item.DataFieldMapUid); + switch(item.dataFieldType){ + case(INTEGER): + if (item.issigned) { + json_object_object_add(cod, key, + json_object_new_int64(le64_to_cpu(*(uint64_t *)val))); + } else { + json_object_add_value_uint64(cod, key, le64_to_cpu(*(uint64_t *)val)); + } + break; + case(FLOAT): + json_object_add_value_float(cod, key, *(float *) val); + break; + case(STRING): + json_object_object_add(cod, key, + json_object_new_string_len((const char *)val, item.DataFieldSizeInBytes)); + break; + case(TWO_BYTE_ASCII): + json_object_object_add(cod, key, + json_object_new_string_len((const char *)val,2)); + break; + case(FOUR_BYTE_ASCII): + json_object_object_add(cod, key, + json_object_new_string_len((const char *)val, 4)); + break; + default: + SOLIDIGM_LOG_WARNING("Warning: Unknown COD field type (%d)", item.DataFieldMapUid); + + } + } +} |