1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
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,
};
struct json_object *telemetry_header = NULL;
struct json_object *COD_offset = NULL;
struct 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;
}
struct 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);
}
}
}
|