1
0
Fork 0

Merging upstream version 2.5.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-16 12:24:13 +01:00
parent 3d70d3c76b
commit ee6621a5b2
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
507 changed files with 19440 additions and 17258 deletions

View file

@ -51,22 +51,20 @@ const char *oemDataMapDesc[] = {
"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
"Media Health Relocations" //Uid 0x2B = 43
};
static const char * getOemDataMapDescription(__u32 id)
static const char *getOemDataMapDescription(uint32_t id)
{
if (id < (sizeof(oemDataMapDesc) / sizeof(oemDataMapDesc[0]))) {
if (id < ARRAY_SIZE(oemDataMapDesc))
return oemDataMapDesc[id];
}
return "unknown";
}
#define OEMSIGNATURE 0x504D4443
#pragma pack(push, cod, 1)
struct cod_header
{
struct cod_header {
uint32_t versionMajor;
uint32_t versionMinor;
uint32_t Signature; //!Fixed signature value (0x504D4443) for identification and validation
@ -75,8 +73,7 @@ struct cod_header
uint8_t Reserved[12];
};
struct cod_item
{
struct cod_item {
uint32_t DataFieldMapUid; //!The data field unique identifier value
uint32_t reserved1 : 8;
uint32_t dataFieldType : 8;
@ -90,8 +87,7 @@ struct cod_item
uint8_t Reserved2[8];
};
struct cod_map
{
struct cod_map {
struct cod_header header;
struct cod_item items[];
};
@ -100,8 +96,7 @@ struct cod_map
void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl)
{
enum cod_field_type
{
enum cod_field_type {
INTEGER,
FLOAT,
STRING,
@ -118,77 +113,78 @@ void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl)
return;
if (!json_object_object_get_ex(telemetry_header, "reasonIdentifier", &reason_id))
return;
if (!json_object_object_get_ex(reason_id, "OemDataMapOffset", &COD_offset))
if (!json_object_object_get_ex(reason_id, "oemDataMapOffset", &COD_offset))
return;
__u64 offset = json_object_get_int(COD_offset);
uint64_t offset = json_object_get_int(COD_offset);
if (offset == 0) {
if (!offset)
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);
const struct cod_map *data = (struct cod_map *) (((uint8_t *)tl->log) + offset);
uint32_t signature = be32_to_cpu(data->header.Signature);
if ( signature != OEMSIGNATURE){
if (signature != OEMSIGNATURE) {
SOLIDIGM_LOG_WARNING("Warning: Unsupported COD data signature %x!", signature);
return;
}
if ((offset + data->header.MapSizeInBytes) > tl->log_size){
if ((offset + data->header.MapSizeInBytes) > tl->log_size) {
SOLIDIGM_LOG_WARNING("Warning: COD map data out of bounds.");
return;
}
struct json_object *cod = json_create_object();
json_object_object_add(tl->root, "cod", cod);
for (int i =0 ; i < data->header.EntryCount; i++) {
for (uint64_t 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);
tl->log_size) {
SOLIDIGM_LOG_WARNING("Warning: COD data out of bounds at item %"PRIu64"!",
i);
return;
}
struct cod_item item = data->items[i];
if (item.DataFieldOffset + item.DataFieldOffset > tl->log_size) {
if (item.DataFieldOffset + item.DataFieldOffset > tl->log_size)
continue;
}
if (item.dataInvalid) {
if (item.dataInvalid)
continue;
}
uint8_t *val = ((uint8_t *)tl->log )+ item.DataFieldOffset;
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):
switch (item.dataFieldType) {
case INTEGER:
if (item.issigned)
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);
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);
break;
}
}
}

View file

@ -4,13 +4,17 @@
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include <stdbool.h>
#include "util/json.h"
#include <stdio.h>
#include <string.h>
#include "config.h"
// max 16 bit unsigned integer nummber 65535
#define MAX_16BIT_NUM_AS_STRING_SIZE 6
#define OBJ_NAME_PREFIX "UID_"
#define NLOG_OBJ_PREFIX OBJ_NAME_PREFIX "NLOG_"
static bool config_get_by_version(const struct json_object *obj, int version_major,
int version_minor, struct json_object **value)
{
@ -28,17 +32,45 @@ static bool config_get_by_version(const struct json_object *obj, int version_maj
return value != NULL;
}
bool solidigm_config_get_by_token_version(const struct json_object *obj, int token_id,
bool solidigm_config_get_struct_by_token_version(const struct json_object *config, int token_id,
int version_major, int version_minor,
struct json_object **value)
{
struct json_object *token_obj = NULL;
struct json_object *token = NULL;
char str_key[MAX_16BIT_NUM_AS_STRING_SIZE];
snprintf(str_key, sizeof(str_key), "%d", token_id);
if (!json_object_object_get_ex(obj, str_key, &token_obj))
if (!json_object_object_get_ex(config, str_key, &token))
return false;
if (!config_get_by_version(token_obj, version_major, version_minor, value))
if (!config_get_by_version(token, version_major, version_minor, value))
return false;
return value != NULL;
}
const char *solidigm_config_get_nlog_obj_name(const struct json_object *config, uint32_t token)
{
struct json_object *nlog_names = NULL;
struct json_object *obj_name;
char hex_header[STR_HEX32_SIZE];
const char *name;
if (!json_object_object_get_ex(config, "TELEMETRY_OBJECT_UIDS", &nlog_names))
return NULL;
snprintf(hex_header, STR_HEX32_SIZE, "0x%08X", token);
if (!json_object_object_get_ex(nlog_names, hex_header, &obj_name))
return NULL;
name = json_object_get_string(obj_name);
if (strncmp(NLOG_OBJ_PREFIX, name, strlen(NLOG_OBJ_PREFIX)))
return NULL;
return &name[strlen(OBJ_NAME_PREFIX)];
}
struct json_object *solidigm_config_get_nlog_formats(const struct json_object *config)
{
struct json_object *nlog_formats = NULL;
json_object_object_get_ex(config, "NLOG_FORMATS", &nlog_formats);
return nlog_formats;
}

View file

@ -7,7 +7,13 @@
#include <stdbool.h>
#include "util/json.h"
bool solidigm_config_get_by_token_version(const struct json_object *obj,
#define STR_HEX32_SIZE sizeof("0x00000000")
bool solidigm_config_get_struct_by_token_version(const struct json_object *obj,
int key, int subkey,
int subsubkey,
struct json_object **value);
const char *solidigm_config_get_nlog_obj_name(const struct json_object *config, uint32_t token);
struct json_object *solidigm_config_get_nlog_formats(const struct json_object *config);

View file

@ -6,25 +6,29 @@
*/
#include "common.h"
#include "header.h"
#include "cod.h"
#include "data-area.h"
#include "config.h"
#include "nlog.h"
#include <ctype.h>
#define SIGNED_INT_PREFIX "int"
#define BITS_IN_BYTE 8
#define MAX_WARNING_SIZE 1024
#define MAX_ARRAY_RANK 16
static bool telemetry_log_get_value(const struct telemetry_log *tl,
uint32_t offset_bit, uint32_t size_bit,
uint64_t offset_bit, uint32_t size_bit,
bool is_signed, struct json_object **val_obj)
{
uint32_t offset_bit_from_byte;
uint32_t additional_size_byte;
uint32_t offset_byte;
uint32_t val;
uint64_t val;
if (size_bit == 0) {
if (!size_bit) {
char err_msg[MAX_WARNING_SIZE];
snprintf(err_msg, MAX_WARNING_SIZE,
@ -34,7 +38,7 @@ static bool telemetry_log_get_value(const struct telemetry_log *tl,
return false;
}
additional_size_byte = (size_bit - 1) ? (size_bit - 1) / BITS_IN_BYTE : 0;
offset_byte = offset_bit / BITS_IN_BYTE;
offset_byte = (uint32_t)offset_bit / BITS_IN_BYTE;
if (offset_byte > (tl->log_size - additional_size_byte)) {
char err_msg[MAX_WARNING_SIZE];
@ -47,15 +51,14 @@ static bool telemetry_log_get_value(const struct telemetry_log *tl,
return false;
}
offset_bit_from_byte = offset_bit - (offset_byte * BITS_IN_BYTE);
offset_bit_from_byte = (uint32_t) (offset_bit - ((uint64_t)offset_byte * BITS_IN_BYTE));
if ((size_bit + offset_bit_from_byte) > (sizeof(uint64_t) * BITS_IN_BYTE)) {
char err_msg[MAX_WARNING_SIZE];
snprintf(err_msg, MAX_WARNING_SIZE,
"Value crossing 64 bit, byte aligned bounday, "
"not supported. size_bit=%u, offset_bit_from_byte=%u.",
size_bit, offset_bit_from_byte);
"Value crossing 64 bit, byte aligned bounday, not supported. size_bit=%u, offset_bit_from_byte=%u.",
size_bit, offset_bit_from_byte);
*val_obj = json_object_new_string(err_msg);
return false;
@ -67,7 +70,7 @@ static bool telemetry_log_get_value(const struct telemetry_log *tl,
val &= (1ULL << size_bit) - 1;
if (is_signed) {
if (val >> (size_bit - 1))
val |= -1ULL << size_bit;
val |= (0ULL - 1) << size_bit;
*val_obj = json_object_new_int64(val);
} else {
*val_obj = json_object_new_uint64(val);
@ -78,23 +81,24 @@ static bool telemetry_log_get_value(const struct telemetry_log *tl,
static int telemetry_log_structure_parse(const struct telemetry_log *tl,
struct json_object *struct_def,
size_t parent_offset_bit,
uint64_t parent_offset_bit,
struct json_object *output,
struct json_object *metadata)
{
struct json_object *obj_arraySizeArray = NULL;
struct json_object *obj = NULL;
struct json_object *obj_memberList;
struct json_object *major_dimension;
struct json_object *major_dimension = NULL;
struct json_object *sub_output;
bool is_enumeration = false;
bool has_member_list;
const char *type = "";
const char *name;
size_t array_rank;
size_t offset_bit;
size_t size_bit;
uint32_t linear_array_pos_bit;
uint64_t offset_bit;
uint32_t size_bit;
uint64_t linear_array_pos_bit;
uint32_t array_size_dimension[MAX_ARRAY_RANK];
if (!json_object_object_get_ex(struct_def, "name", &obj)) {
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing property 'name': %s",
@ -113,22 +117,22 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
type = json_object_get_string(obj);
if (!json_object_object_get_ex(struct_def, "offsetBit", &obj)) {
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing "
"property 'offsetBit': %s",
json_object_to_json_string(struct_def));
SOLIDIGM_LOG_WARNING(
"Warning: Structure definition missing property 'offsetBit': %s",
json_object_to_json_string(struct_def));
return -1;
}
offset_bit = json_object_get_uint64(obj);
if (!json_object_object_get_ex(struct_def, "sizeBit", &obj)) {
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing "
"property 'sizeBit': %s",
json_object_to_json_string(struct_def));
SOLIDIGM_LOG_WARNING(
"Warning: Structure definition missing property 'sizeBit': %s",
json_object_to_json_string(struct_def));
return -1;
}
size_bit = json_object_get_uint64(obj);
size_bit = (uint32_t)json_object_get_uint64(obj);
if (json_object_object_get_ex(struct_def, "enum", &obj))
is_enumeration = json_object_get_boolean(obj);
@ -139,25 +143,30 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
if (!json_object_object_get_ex(struct_def, "arraySize",
&obj_arraySizeArray)) {
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing "
"property 'arraySize': %s",
json_object_to_json_string(struct_def));
SOLIDIGM_LOG_WARNING(
"Warning: Structure definition missing property 'arraySize': %s",
json_object_to_json_string(struct_def));
return -1;
}
array_rank = json_object_array_length(obj_arraySizeArray);
if (array_rank == 0) {
SOLIDIGM_LOG_WARNING("Warning: Structure property 'arraySize' "
"don't support flexible array: %s",
json_object_to_json_string(struct_def));
if (!array_rank) {
SOLIDIGM_LOG_WARNING(
"Warning: Structure property 'arraySize' don't support flexible array: %s",
json_object_to_json_string(struct_def));
return -1;
}
if (array_rank > MAX_ARRAY_RANK) {
SOLIDIGM_LOG_WARNING(
"Warning: Structure property 'arraySize' don't support more than %d dimensions: %s",
MAX_ARRAY_RANK, json_object_to_json_string(struct_def));
return -1;
}
uint32_t array_size_dimension[array_rank];
for (size_t i = 0; i < array_rank; i++) {
struct json_object *dimension = json_object_array_get_idx(obj_arraySizeArray, i);
array_size_dimension[i] = json_object_get_uint64(dimension);
array_size_dimension[i] = json_object_get_int(dimension);
major_dimension = dimension;
}
if (array_rank > 1) {
@ -165,7 +174,7 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
uint32_t prev_index_offset_bit = 0;
struct json_object *dimension_output;
for (int i = 1; i < (array_rank - 1); i++)
for (unsigned int i = 1; i < (array_rank - 1); i++)
linear_pos_per_index *= array_size_dimension[i];
dimension_output = json_create_array();
@ -181,9 +190,9 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
json_object_get(major_dimension);
json_object_array_del_idx(obj_arraySizeArray, array_rank - 1, 1);
for (int i = 0 ; i < array_size_dimension[0]; i++) {
for (unsigned int i = 0 ; i < array_size_dimension[0]; i++) {
struct json_object *sub_array = json_create_array();
size_t offset;
uint64_t offset;
offset = parent_offset_bit + prev_index_offset_bit;
@ -214,7 +223,7 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
if (is_enumeration || !has_member_list) {
bool is_signed = !strncmp(type, SIGNED_INT_PREFIX, sizeof(SIGNED_INT_PREFIX)-1);
struct json_object *val_obj;
size_t offset;
uint64_t offset;
offset = parent_offset_bit + offset_bit + linear_array_pos_bit;
if (telemetry_log_get_value(tl, offset, size_bit, is_signed, &val_obj)) {
@ -223,10 +232,10 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
else
json_object_object_add(sub_output, name, val_obj);
} else {
SOLIDIGM_LOG_WARNING("Warning: %s From property '%s', "
"array index %u, structure definition: %s",
json_object_get_string(val_obj),
name, j, json_object_to_json_string(struct_def));
SOLIDIGM_LOG_WARNING(
"Warning: %s From property '%s', array index %u, structure definition: %s",
json_object_get_string(val_obj), name, j,
json_object_to_json_string(struct_def));
json_free_object(val_obj);
}
} else {
@ -241,7 +250,7 @@ static int telemetry_log_structure_parse(const struct telemetry_log *tl,
num_members = json_object_array_length(obj_memberList);
for (int k = 0; k < num_members; k++) {
struct json_object *member = json_object_array_get_idx(obj_memberList, k);
size_t offset;
uint64_t offset;
offset = parent_offset_bit + offset_bit + linear_array_pos_bit;
telemetry_log_structure_parse(tl, member, offset,
@ -293,6 +302,27 @@ static int telemetry_log_data_area_get_offset(const struct telemetry_log *tl,
return 0;
}
static int telemetry_log_nlog_parse(const struct telemetry_log *tl, struct json_object *formats,
uint64_t nlog_file_offset, uint64_t nlog_size,
struct json_object *output, struct json_object *metadata)
{
/* boundary check */
if (tl->log_size < (nlog_file_offset + nlog_size)) {
const char *name = "";
int media_bank = -1;
struct json_object *jobj;
if (json_object_object_get_ex(metadata, "objName", &jobj))
name = json_object_get_string(jobj);
if (json_object_object_get_ex(metadata, "mediaBankId", &jobj))
media_bank = json_object_get_int(jobj);
SOLIDIGM_LOG_WARNING("%s:%d do not fit this log dump.", name, media_bank);
return -1;
}
return solidigm_nlog_parse(((char *) tl->log) + nlog_file_offset,
nlog_size, formats, metadata, output);
}
struct toc_item {
uint32_t OffsetBytes;
uint32_t ContentSizeBytes;
@ -319,7 +349,6 @@ struct telemetry_object_header {
uint8_t Reserved[3];
};
static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl,
enum nvme_telemetry_da da,
struct json_object *toc_array,
@ -331,30 +360,35 @@ static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl,
char *payload;
uint32_t da_offset;
uint32_t da_size;
struct json_object *nlog_formats;
if (telemetry_log_data_area_get_offset(tl, da, &da_offset, &da_size))
return;
toc = (struct table_of_contents *)(((char *)tl->log) + da_offset);
payload = (char *) tl->log;
nlog_formats = solidigm_config_get_nlog_formats(tl->configuration);
for (int i = 0; i < toc->header.TableOfContentsCount; i++) {
struct json_object *structure_definition = NULL;
struct json_object *toc_item;
uint32_t obj_offset;
bool has_struct;
const char *nlog_name = NULL;
uint32_t header_offset = sizeof(const struct telemetry_object_header);
if ((char *)&toc->items[i] > (((char *)toc) + da_size - sizeof(const struct toc_item))) {
SOLIDIGM_LOG_WARNING("Warning: Data Area %d, "
"Table of Contents item %d "
"crossed Data Area size.", da, i);
if ((char *)&toc->items[i] >
(((char *)toc) + da_size - sizeof(const struct toc_item))) {
SOLIDIGM_LOG_WARNING(
"Warning: Data Area %d, Table of Contents item %d crossed Data Area size.",
da, i);
return;
}
obj_offset = toc->items[i].OffsetBytes;
if ((obj_offset + sizeof(const struct telemetry_object_header)) > da_size) {
SOLIDIGM_LOG_WARNING("Warning: Data Area %d, item %d "
"data, crossed Data Area size.", da, i);
SOLIDIGM_LOG_WARNING(
"Warning: Data Area %d, item %d data, crossed Data Area size.", da, i);
continue;
}
@ -372,53 +406,67 @@ static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl,
json_object_add_value_uint(toc_item, "objectId", header->Token);
json_object_add_value_uint(toc_item, "mediaBankId", header->CoreId);
has_struct = solidigm_config_get_by_token_version(tl->configuration,
header->Token,
header->versionMajor,
header->versionMinor,
&structure_definition);
has_struct = solidigm_config_get_struct_by_token_version(tl->configuration,
header->Token,
header->versionMajor,
header->versionMinor,
&structure_definition);
if (!has_struct) {
if (!nlog_formats)
continue;
nlog_name = solidigm_config_get_nlog_obj_name(tl->configuration,
header->Token);
if (!nlog_name)
continue;
}
struct json_object *tele_obj_item = json_create_object();
json_object_array_add(tele_obj_array, tele_obj_item);
json_object_get(toc_item);
json_object_add_value_object(tele_obj_item, "metadata", toc_item);
struct json_object *parsed_struct = json_create_object();
json_object_add_value_object(tele_obj_item, "objectData", parsed_struct);
struct json_object *obj_hasTelemObjHdr = NULL;
uint64_t object_file_offset;
if (json_object_object_get_ex(structure_definition,
"hasTelemObjHdr",
&obj_hasTelemObjHdr)) {
bool hasHeader = json_object_get_boolean(obj_hasTelemObjHdr);
if (hasHeader)
header_offset = 0;
}
object_file_offset = ((uint64_t)da_offset) + obj_offset + header_offset;
if (has_struct) {
struct json_object *tele_obj_item = json_create_object();
json_object_array_add(tele_obj_array, tele_obj_item);
json_object_get(toc_item);
json_object_add_value_object(tele_obj_item, "metadata", toc_item);
struct json_object *parsed_struct = json_create_object();
json_object_add_value_object(tele_obj_item, "objectData", parsed_struct);
struct json_object *obj_hasTelemObjHdr = NULL;
uint32_t header_offset = sizeof(const struct telemetry_object_header);
uint32_t file_offset;
if (json_object_object_get_ex(structure_definition,
"hasTelemObjHdr",
&obj_hasTelemObjHdr)) {
bool hasHeader = json_object_get_boolean(obj_hasTelemObjHdr);
if (hasHeader)
header_offset = 0;
}
file_offset = da_offset + obj_offset + header_offset;
telemetry_log_structure_parse(tl, structure_definition,
BITS_IN_BYTE * file_offset,
parsed_struct, toc_item);
BITS_IN_BYTE * object_file_offset,
parsed_struct, toc_item);
} else if (nlog_formats) {
json_object_object_add(toc_item, "objName",
json_object_new_string(nlog_name));
telemetry_log_nlog_parse(tl, nlog_formats, object_file_offset,
toc->items[i].ContentSizeBytes - header_offset,
parsed_struct, toc_item);
}
}
}
int solidigm_telemetry_log_data_areas_parse(const struct telemetry_log *tl,
int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl,
enum nvme_telemetry_da last_da)
{
struct json_object *tele_obj_array = json_create_array();
struct json_object *toc_array = json_create_array();
json_object_add_value_array(tl->root, "tableOfContents", toc_array);
json_object_add_value_array(tl->root, "telemetryObjects", tele_obj_array);
for (enum nvme_telemetry_da da = NVME_TELEMETRY_DA_1; da <= last_da; da++)
telemetry_log_data_area_toc_parse(tl, da, toc_array, tele_obj_array);
solidigm_telemetry_log_header_parse(tl);
solidigm_telemetry_log_cod_parse(tl);
if (tl->configuration) {
json_object_add_value_array(tl->root, "tableOfContents", toc_array);
json_object_add_value_array(tl->root, "telemetryObjects", tele_obj_array);
for (enum nvme_telemetry_da da = NVME_TELEMETRY_DA_1; da <= last_da; da++)
telemetry_log_data_area_toc_parse(tl, da, toc_array, tele_obj_array);
}
return 0;
}

View file

@ -4,8 +4,7 @@
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include "common.h"
#include "telemetry-log.h"
int solidigm_telemetry_log_data_areas_parse(const struct telemetry_log *tl,
int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl,
enum nvme_telemetry_da last_da);

View file

@ -9,8 +9,7 @@
#include "header.h"
#pragma pack(push, reason_indentifier, 1)
struct reason_indentifier_1_0
{
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.
@ -24,8 +23,7 @@ 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
{
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.
@ -42,8 +40,7 @@ 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
{
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.
@ -69,14 +66,21 @@ static void telemetry_log_reason_id_parse1_0_ext(const struct telemetry_log *tl,
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)));
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++) {
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);
}
}
@ -88,17 +92,27 @@ static void telemetry_log_reason_id_parse1_1_ext(const struct telemetry_log *tl,
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));
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);
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);
}
}
@ -112,23 +126,30 @@ static void telemetry_log_reason_id_parse1_2_ext(const struct telemetry_log *tl,
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);
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);
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);
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);
}
}
@ -137,23 +158,26 @@ static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *t
{
const struct reason_indentifier_1_0 *ri1_0 =
(struct reason_indentifier_1_0 *) tl->log->rsnident;
__u16 version_major = le16_to_cpu(ri1_0->versionMajor);
__u16 version_minor = le16_to_cpu(ri1_0->versionMinor);
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)));
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);
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;
}
}
}

View file

@ -3,4 +3,5 @@ sources += [
'plugins/solidigm/solidigm-telemetry/header.c',
'plugins/solidigm/solidigm-telemetry/config.c',
'plugins/solidigm/solidigm-telemetry/data-area.c',
'plugins/solidigm/solidigm-telemetry/nlog.c',
]

View file

@ -0,0 +1,130 @@
// SPDX-License-Identifier: MIT
/*
* Copyright (c) 2023 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include "nlog.h"
#include "config.h"
#include <string.h>
#include <math.h>
#include <stdio.h>
#define LOG_ENTRY_HEADER_SIZE 1
#define LOG_ENTRY_TIMESTAMP_SIZE 2
#define LOG_ENTRY_NUM_ARGS_MAX 8
#define LOG_ENTRY_MAX_SIZE (LOG_ENTRY_HEADER_SIZE + LOG_ENTRY_TIMESTAMP_SIZE + \
LOG_ENTRY_NUM_ARGS_MAX)
#define NUM_ARGS_MASK ((1 << ((int)log2(LOG_ENTRY_NUM_ARGS_MAX)+1)) - 1)
#define MAX_HEADER_MISMATCH_TRACK 10
static int formats_find(struct json_object *formats, uint32_t val, struct json_object **format)
{
char hex_header[STR_HEX32_SIZE];
snprintf(hex_header, STR_HEX32_SIZE, "0x%08X", val);
return json_object_object_get_ex(formats, hex_header, format);
}
static uint32_t nlog_get_pos(const uint32_t *nlog, const uint32_t nlog_size, int pos)
{
return nlog[pos % nlog_size];
}
static uint32_t nlog_get_events(const uint32_t *nlog, const uint32_t nlog_size, int start_offset,
struct json_object *formats, struct json_object *events, uint32_t *tail_mismatches)
{
uint32_t event_count = 0;
int last_bad_header_pos = nlog_size + 1; // invalid nlog offset
uint32_t tail_count = 0;
for (int i = nlog_size - start_offset - 1; i >= -start_offset; i--) {
struct json_object *format;
uint32_t header = nlog_get_pos(nlog, nlog_size, i);
uint32_t num_data;
if (header == 0 || !formats_find(formats, header, &format)) {
if (event_count > 0) {
//check if fould circular buffer tail
if (i != (last_bad_header_pos - 1)) {
if (tail_mismatches &&
(tail_count < MAX_HEADER_MISMATCH_TRACK))
tail_mismatches[tail_count] = header;
tail_count++;
}
last_bad_header_pos = i;
}
continue;
}
num_data = header & NUM_ARGS_MASK;
if (events) {
struct json_object *event = json_object_new_array();
struct json_object *param = json_object_new_array();
uint32_t val = nlog_get_pos(nlog, nlog_size, i - 1);
json_object_array_add(events, event);
json_object_array_add(event, json_object_new_int64(val));
val = nlog_get_pos(nlog, nlog_size, i - 2);
json_object_array_add(event, json_object_new_int64(val));
json_object_array_add(event, json_object_new_int64(header));
json_object_array_add(event, param);
for (uint32_t j = 0; j < num_data; j++) {
val = nlog_get_pos(nlog, nlog_size, i - 3 - j);
json_object_array_add(param, json_object_new_int64(val));
}
json_object_get(format);
json_object_array_add(event, format);
}
i -= 2 + num_data;
event_count++;
}
return tail_count;
}
int solidigm_nlog_parse(const char *buffer, uint64_t buff_size, struct json_object *formats,
struct json_object *metadata, struct json_object *output)
{
uint32_t smaller_tail_count = UINT32_MAX;
int best_offset = 0;
uint32_t offset_tail_mismatches[LOG_ENTRY_MAX_SIZE][MAX_HEADER_MISMATCH_TRACK];
struct json_object *events = json_object_new_array();
const uint32_t *nlog = (uint32_t *)buffer;
const uint32_t nlog_size = buff_size / sizeof(uint32_t);
for (int i = 0; i < LOG_ENTRY_MAX_SIZE; i++) {
uint32_t tail_count = nlog_get_events(nlog, nlog_size, i, formats, NULL,
offset_tail_mismatches[i]);
if (tail_count < smaller_tail_count) {
best_offset = i;
smaller_tail_count = tail_count;
}
if (tail_count == 0)
break;
}
if (smaller_tail_count > 1) {
const char *name = "";
int media_bank = -1;
char str_mismatches[(STR_HEX32_SIZE + 1) * MAX_HEADER_MISMATCH_TRACK];
int pos = 0;
int show_mismatch_num = smaller_tail_count < MAX_HEADER_MISMATCH_TRACK ?
smaller_tail_count : MAX_HEADER_MISMATCH_TRACK;
struct json_object *jobj;
if (json_object_object_get_ex(metadata, "objName", &jobj))
name = json_object_get_string(jobj);
if (json_object_object_get_ex(metadata, "mediaBankId", &jobj))
media_bank = json_object_get_int(jobj);
for (int i = 0; i < show_mismatch_num; i++)
pos += snprintf(&str_mismatches[pos], STR_HEX32_SIZE + 1, "0x%08X ",
offset_tail_mismatches[best_offset][i]);
SOLIDIGM_LOG_WARNING("%s:%d with %d header mismatches ( %s). Configuration file may be missing format headers.",
name, media_bank, smaller_tail_count, str_mismatches);
}
nlog_get_events(nlog, nlog_size, best_offset, formats, events, NULL);
json_object_object_add(output, "events", events);
return 0;
}

View file

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright (c) 2023 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include "telemetry-log.h"
int solidigm_nlog_parse(const char *buffer, uint64_t bufer_size,
struct json_object *formats, struct json_object *metadata,
struct json_object *output);