Merging upstream version 2.5.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
3d70d3c76b
commit
ee6621a5b2
507 changed files with 19440 additions and 17258 deletions
|
@ -1,8 +1,13 @@
|
|||
sources += [
|
||||
'plugins/solidigm/solidigm-id-ctrl.c',
|
||||
'plugins/solidigm/solidigm-util.c',
|
||||
'plugins/solidigm/solidigm-smart.c',
|
||||
'plugins/solidigm/solidigm-garbage-collection.c',
|
||||
'plugins/solidigm/solidigm-latency-tracking.c',
|
||||
'plugins/solidigm/solidigm-log-page-dir.c',
|
||||
'plugins/solidigm/solidigm-telemetry.c',
|
||||
'plugins/solidigm/solidigm-internal-logs.c',
|
||||
'plugins/solidigm/solidigm-market-log.c',
|
||||
]
|
||||
subdir('solidigm-telemetry')
|
||||
|
||||
|
|
|
@ -21,26 +21,27 @@
|
|||
#include "solidigm-garbage-collection.h"
|
||||
#include "solidigm-util.h"
|
||||
|
||||
typedef struct __attribute__((packed)) gc_item {
|
||||
struct __packed gc_item {
|
||||
__le32 timer_type;
|
||||
__le64 timestamp;
|
||||
} gc_item_t;
|
||||
};
|
||||
|
||||
#define VU_GC_MAX_ITEMS 100
|
||||
typedef struct garbage_control_collection_log {
|
||||
struct garbage_control_collection_log {
|
||||
__le16 version_major;
|
||||
__le16 version_minor;
|
||||
gc_item_t item[VU_GC_MAX_ITEMS];
|
||||
struct __packed gc_item item[VU_GC_MAX_ITEMS];
|
||||
__u8 reserved[2892];
|
||||
} garbage_control_collection_log_t;
|
||||
};
|
||||
|
||||
static void vu_gc_log_show_json(garbage_control_collection_log_t *payload, const char *devname)
|
||||
static void vu_gc_log_show_json(struct garbage_control_collection_log *payload, const char *devname)
|
||||
{
|
||||
struct json_object *gc_entries = json_create_array();
|
||||
|
||||
for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
|
||||
gc_item_t item = payload->item[i];
|
||||
struct __packed gc_item item = payload->item[i];
|
||||
struct json_object *entry = json_create_object();
|
||||
|
||||
json_object_add_value_int(entry, "timestamp", le64_to_cpu(item.timestamp));
|
||||
json_object_add_value_int(entry, "timer_type", le32_to_cpu(item.timer_type));
|
||||
json_array_add_value_object(gc_entries, entry);
|
||||
|
@ -50,7 +51,7 @@ static void vu_gc_log_show_json(garbage_control_collection_log_t *payload, const
|
|||
json_free_object(gc_entries);
|
||||
}
|
||||
|
||||
static void vu_gc_log_show(garbage_control_collection_log_t *payload, const char *devname,
|
||||
static void vu_gc_log_show(struct garbage_control_collection_log *payload, const char *devname,
|
||||
__u8 uuid_index)
|
||||
{
|
||||
printf("Solidigm Garbage Collection Log for NVME device:%s UUID-idx:%d\n", devname,
|
||||
|
@ -58,7 +59,8 @@ static void vu_gc_log_show(garbage_control_collection_log_t *payload, const char
|
|||
printf("Timestamp Timer Type\n");
|
||||
|
||||
for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
|
||||
gc_item_t item = payload->item[i];
|
||||
struct __packed gc_item item = payload->item[i];
|
||||
|
||||
printf("%-13" PRIu64 " %d\n", le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type));
|
||||
}
|
||||
}
|
||||
|
@ -88,15 +90,16 @@ int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *c
|
|||
return err;
|
||||
|
||||
enum nvme_print_flags flags = validate_output_format(cfg.output_format);
|
||||
|
||||
if (flags == -EINVAL) {
|
||||
fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
|
||||
dev_close(dev);
|
||||
return EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uuid_index = solidigm_get_vu_uuid_index(dev);
|
||||
|
||||
garbage_control_collection_log_t gc_log;
|
||||
struct garbage_control_collection_log gc_log;
|
||||
const int solidigm_vu_gc_log_id = 0xfd;
|
||||
struct nvme_get_log_args args = {
|
||||
.lpo = 0,
|
||||
|
@ -118,15 +121,13 @@ int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *c
|
|||
|
||||
err = nvme_get_log(&args);
|
||||
if (!err) {
|
||||
if (flags & BINARY) {
|
||||
if (flags & BINARY)
|
||||
d_raw((unsigned char *)&gc_log, sizeof(gc_log));
|
||||
} else if (flags & JSON) {
|
||||
else if (flags & JSON)
|
||||
vu_gc_log_show_json(&gc_log, dev->name);
|
||||
} else {
|
||||
else
|
||||
vu_gc_log_show(&gc_log, dev->name, uuid_index);
|
||||
}
|
||||
}
|
||||
else if (err > 0) {
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
}
|
||||
|
||||
|
|
73
plugins/solidigm/solidigm-id-ctrl.c
Normal file
73
plugins/solidigm/solidigm-id-ctrl.c
Normal file
|
@ -0,0 +1,73 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2023 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "common.h"
|
||||
#include "solidigm-id-ctrl.h"
|
||||
|
||||
struct __packed nvme_vu_id_ctrl_field { /* CDR MR5 */
|
||||
__u8 rsvd1[3];
|
||||
__u8 ss;
|
||||
char health[20];
|
||||
__u8 cls;
|
||||
__u8 nlw;
|
||||
__u8 scap;
|
||||
__u8 sstat;
|
||||
char bl[8];
|
||||
__u8 rsvd2[38];
|
||||
__le64 ww;
|
||||
char mic_bl[4];
|
||||
char mic_fw[4];
|
||||
};
|
||||
|
||||
void sldgm_id_ctrl(uint8_t *vs, struct json_object *root)
|
||||
{
|
||||
// text output aligns nicely with property name up to 10 chars
|
||||
const char *str_ss = "stripeSize";
|
||||
const char *str_health = "health";
|
||||
const char *str_cls = "linkSpeed";
|
||||
const char *str_nlw = "negLnkWdth";
|
||||
const char *str_scap = "secCapab";
|
||||
const char *str_sstat = "secStatus";
|
||||
const char *str_bl = "bootLoader";
|
||||
const char *str_ww = "wwid";
|
||||
const char *str_mic_bl = "bwLimGran";
|
||||
const char *str_mic_fw = "ioLimGran";
|
||||
|
||||
struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
|
||||
|
||||
const char str_heathy[sizeof(id->health)] = "healthy";
|
||||
const char *health = id->health[0] ? id->health : str_heathy;
|
||||
|
||||
if (root == NULL) {
|
||||
printf("%-10s: %u\n", str_ss, id->ss);
|
||||
printf("%-10s: %.*s\n", str_health, (int)sizeof(id->health), health);
|
||||
printf("%-10s: %u\n", str_cls, id->cls);
|
||||
printf("%-10s: %u\n", str_nlw, id->nlw);
|
||||
printf("%-10s: %u\n", str_scap, id->scap);
|
||||
printf("%-10s: %u\n", str_sstat, id->sstat);
|
||||
printf("%-10s: %.*s\n", str_bl, (int)sizeof(id->bl), id->bl);
|
||||
printf("%-10s: 0x%016"PRIx64"\n", str_ww, le64_to_cpu(id->ww));
|
||||
printf("%-10s: %.*s\n", str_mic_bl, (int)sizeof(id->mic_bl), id->mic_bl);
|
||||
printf("%-10s: %.*s\n", str_mic_fw, (int)sizeof(id->mic_fw), id->mic_fw);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object_add_value_uint(root, str_ss, id->ss);
|
||||
json_object_object_add(root, str_health,
|
||||
json_object_new_string_len(health, sizeof(id->health)));
|
||||
json_object_add_value_uint(root, str_cls, id->cls);
|
||||
json_object_add_value_uint(root, str_nlw, id->nlw);
|
||||
json_object_add_value_uint(root, str_scap, id->scap);
|
||||
json_object_add_value_uint(root, str_sstat, id->sstat);
|
||||
json_object_object_add(root, str_bl, json_object_new_string_len(id->bl, sizeof(id->bl)));
|
||||
json_object_add_value_uint64(root, str_ww, le64_to_cpu(id->ww));
|
||||
json_object_object_add(root, str_mic_bl,
|
||||
json_object_new_string_len(id->mic_bl, sizeof(id->mic_bl)));
|
||||
json_object_object_add(root, str_mic_fw,
|
||||
json_object_new_string_len(id->mic_fw, sizeof(id->mic_fw)));
|
||||
}
|
10
plugins/solidigm/solidigm-id-ctrl.h
Normal file
10
plugins/solidigm/solidigm-id-ctrl.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2023 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "util/json.h"
|
||||
void sldgm_id_ctrl(uint8_t *vs, struct json_object *root);
|
597
plugins/solidigm/solidigm-internal-logs.c
Normal file
597
plugins/solidigm/solidigm-internal-logs.c
Normal file
|
@ -0,0 +1,597 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2023 Solidigm.
|
||||
*
|
||||
* Authors: leonardo.da.cunha@solidigm.com
|
||||
* shankaralingegowda.singonahalli@solidigm.com
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "nvme.h"
|
||||
#include "libnvme.h"
|
||||
#include "plugin.h"
|
||||
#include "nvme-print.h"
|
||||
|
||||
#define DWORD_SIZE 4
|
||||
|
||||
enum log_type {
|
||||
NLOG = 0,
|
||||
EVENTLOG = 1,
|
||||
ASSERTLOG = 2,
|
||||
};
|
||||
|
||||
#pragma pack(push, internal_logs, 1)
|
||||
struct version {
|
||||
__u16 major;
|
||||
__u16 minor;
|
||||
};
|
||||
|
||||
struct event_dump_instance {
|
||||
__u32 numeventdumps;
|
||||
__u32 coresize;
|
||||
__u32 coreoffset;
|
||||
__u32 eventidoffset[16];
|
||||
__u8 eventIdValidity[16];
|
||||
};
|
||||
|
||||
struct commom_header {
|
||||
struct version ver;
|
||||
__u32 header_size;
|
||||
__u32 log_size;
|
||||
__u32 numcores;
|
||||
};
|
||||
|
||||
struct event_dump_header {
|
||||
struct commom_header header;
|
||||
__u32 eventidsize;
|
||||
struct event_dump_instance edumps[0];
|
||||
};
|
||||
|
||||
struct assert_dump_core {
|
||||
__u32 coreoffset;
|
||||
__u32 assertsize;
|
||||
__u8 assertdumptype;
|
||||
__u8 assertvalid;
|
||||
__u8 reserved[2];
|
||||
};
|
||||
|
||||
struct assert_dump_header {
|
||||
struct commom_header header;
|
||||
struct assert_dump_core core[];
|
||||
};
|
||||
|
||||
struct nlog_dump_header_common {
|
||||
struct version ver;
|
||||
__u32 logselect;
|
||||
__u32 totalnlogs;
|
||||
__u32 nlognum;
|
||||
char nlogname[4];
|
||||
__u32 nlogbytesize;
|
||||
__u32 nlogprimarybuffsize;
|
||||
__u32 tickspersecond;
|
||||
__u32 corecount;
|
||||
};
|
||||
|
||||
struct nlog_dump_header3_0 {
|
||||
struct nlog_dump_header_common common;
|
||||
__u32 nlogpausestatus;
|
||||
__u32 selectoffsetref;
|
||||
__u32 selectnlogpause;
|
||||
__u32 selectaddedoffset;
|
||||
__u32 nlogbufnum;
|
||||
__u32 nlogbufnummax;
|
||||
};
|
||||
|
||||
struct nlog_dump_header4_0 {
|
||||
struct nlog_dump_header_common common;
|
||||
__u64 nlogpausestatus;
|
||||
__u32 selectoffsetref;
|
||||
__u32 selectnlogpause;
|
||||
__u32 selectaddedoffset;
|
||||
__u32 nlogbufnum;
|
||||
__u32 nlogbufnummax;
|
||||
__u32 coreselected;
|
||||
__u32 reserved[2];
|
||||
};
|
||||
|
||||
struct nlog_dump_header4_1 {
|
||||
struct nlog_dump_header_common common;
|
||||
__u64 nlogpausestatus;
|
||||
__u32 selectoffsetref;
|
||||
__u32 selectnlogpause;
|
||||
__u32 selectaddedoffset;
|
||||
__u32 nlogbufnum;
|
||||
__u32 nlogbufnummax;
|
||||
__u32 coreselected;
|
||||
__u32 lpaPointer1High;
|
||||
__u32 lpaPointer1Low;
|
||||
__u32 lpaPointer2High;
|
||||
__u32 lpaPointer2Low;
|
||||
};
|
||||
|
||||
#pragma pack(pop, internal_logs)
|
||||
|
||||
struct config {
|
||||
__u32 namespace_id;
|
||||
char *file_prefix;
|
||||
char *type;
|
||||
bool verbose;
|
||||
};
|
||||
|
||||
static void print_nlog_header(__u8 *buffer)
|
||||
{
|
||||
struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *) buffer;
|
||||
|
||||
if (nlog_header->ver.major >= 3) {
|
||||
printf("Version Major %u\n", nlog_header->ver.major);
|
||||
printf("Version Minor %u\n", nlog_header->ver.minor);
|
||||
printf("Log_select %u\n", nlog_header->logselect);
|
||||
printf("totalnlogs %u\n", nlog_header->totalnlogs);
|
||||
printf("nlognum %u\n", nlog_header->nlognum);
|
||||
printf("nlogname %c%c%c%c\n", nlog_header->nlogname[3], nlog_header->nlogname[2],
|
||||
nlog_header->nlogname[1], nlog_header->nlogname[0]);
|
||||
printf("nlogbytesize %u\n", nlog_header->nlogbytesize);
|
||||
printf("nlogprimarybuffsize %u\n", nlog_header->nlogprimarybuffsize);
|
||||
printf("tickspersecond %u\n", nlog_header->tickspersecond);
|
||||
printf("corecount %u\n", nlog_header->corecount);
|
||||
}
|
||||
if (nlog_header->ver.major >= 4) {
|
||||
struct nlog_dump_header4_0 *nlog_header = (struct nlog_dump_header4_0 *) buffer;
|
||||
|
||||
printf("nlogpausestatus %"PRIu64"\n", (uint64_t)nlog_header->nlogpausestatus);
|
||||
printf("selectoffsetref %u\n", nlog_header->selectoffsetref);
|
||||
printf("selectnlogpause %u\n", nlog_header->selectnlogpause);
|
||||
printf("selectaddedoffset %u\n", nlog_header->selectaddedoffset);
|
||||
printf("nlogbufnum %u\n", nlog_header->nlogbufnum);
|
||||
printf("nlogbufnummax %u\n", nlog_header->nlogbufnummax);
|
||||
printf("coreselected %u\n\n", nlog_header->coreselected);
|
||||
}
|
||||
}
|
||||
|
||||
#define INTERNAL_LOG_MAX_BYTE_TRANSFER 4096
|
||||
#define INTERNAL_LOG_MAX_DWORD_TRANSFER (INTERNAL_LOG_MAX_BYTE_TRANSFER / 4)
|
||||
|
||||
static int cmd_dump_repeat(struct nvme_passthru_cmd *cmd, __u32 total_dw_size,
|
||||
int out_fd, int ioctl_fd, bool force_max_transfer)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
while (total_dw_size > 0) {
|
||||
size_t dword_tfer = min(INTERNAL_LOG_MAX_DWORD_TRANSFER, total_dw_size);
|
||||
|
||||
cmd->cdw10 = force_max_transfer ? INTERNAL_LOG_MAX_DWORD_TRANSFER : dword_tfer;
|
||||
cmd->data_len = dword_tfer * 4;
|
||||
err = nvme_submit_admin_passthru(ioctl_fd, cmd, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (out_fd > 0) {
|
||||
err = write(out_fd, (const void *)(uintptr_t)cmd->addr, cmd->data_len);
|
||||
if (err < 0) {
|
||||
perror("write failure");
|
||||
return err;
|
||||
}
|
||||
err = 0;
|
||||
}
|
||||
total_dw_size -= dword_tfer;
|
||||
cmd->cdw13 += dword_tfer;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int write_header(__u8 *buf, int fd, size_t amnt)
|
||||
{
|
||||
if (write(fd, buf, amnt) < 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_header(struct nvme_passthru_cmd *cmd, int ioctl_fd)
|
||||
{
|
||||
memset((void *)(uintptr_t)cmd->addr, 0, INTERNAL_LOG_MAX_BYTE_TRANSFER);
|
||||
return cmd_dump_repeat(cmd, INTERNAL_LOG_MAX_DWORD_TRANSFER, -1, ioctl_fd, false);
|
||||
}
|
||||
|
||||
static int get_serial_number(char *str, int fd)
|
||||
{
|
||||
struct nvme_id_ctrl ctrl = {0};
|
||||
int err;
|
||||
|
||||
err = nvme_identify_ctrl(fd, &ctrl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Remove trailing spaces */
|
||||
for (int i = sizeof(ctrl.sn) - 1; i && ctrl.sn[i] == ' '; i--)
|
||||
ctrl.sn[i] = '\0';
|
||||
sprintf(str, "%-.*s", (int)sizeof(ctrl.sn), ctrl.sn);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
|
||||
{
|
||||
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
__u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
char file_path[PATH_MAX];
|
||||
struct assert_dump_header *ad = (struct assert_dump_header *) head_buf;
|
||||
struct nvme_passthru_cmd cmd = {
|
||||
.opcode = 0xd2,
|
||||
.nsid = cfg.namespace_id,
|
||||
.addr = (unsigned long)(void *)head_buf,
|
||||
.cdw12 = ASSERTLOG,
|
||||
.cdw13 = 0,
|
||||
};
|
||||
int output, err;
|
||||
|
||||
err = read_header(&cmd, dev_fd(dev));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sprintf(file_path, "%s_AssertLog.bin", cfg.file_prefix);
|
||||
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (output < 0)
|
||||
return -errno;
|
||||
err = write_header((__u8 *)ad, output, ad->header.header_size * DWORD_SIZE);
|
||||
if (err) {
|
||||
perror("write failure");
|
||||
close(output);
|
||||
return err;
|
||||
}
|
||||
cmd.addr = (unsigned long)(void *)buf;
|
||||
|
||||
if (cfg.verbose) {
|
||||
printf("Assert Log, cores: %d log size: %d header size: %d\n", ad->header.numcores,
|
||||
ad->header.log_size * DWORD_SIZE, ad->header.header_size * DWORD_SIZE);
|
||||
for (__u32 i = 0; i < ad->header.numcores; i++)
|
||||
printf("core %d assert size: %d\n", i, ad->core[i].assertsize * DWORD_SIZE);
|
||||
}
|
||||
|
||||
for (__u32 i = 0; i < ad->header.numcores; i++) {
|
||||
if (!ad->core[i].assertvalid)
|
||||
continue;
|
||||
cmd.cdw13 = ad->core[i].coreoffset;
|
||||
err = cmd_dump_repeat(&cmd, ad->core[i].assertsize,
|
||||
output,
|
||||
dev_fd(dev), false);
|
||||
if (err) {
|
||||
close(output);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
close(output);
|
||||
printf("Successfully wrote log to %s\n", file_path);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dump_event_logs(struct nvme_dev *dev, struct config cfg)
|
||||
{
|
||||
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
__u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
char file_path[PATH_MAX];
|
||||
struct event_dump_header *ehdr = (struct event_dump_header *) head_buf;
|
||||
struct nvme_passthru_cmd cmd = {
|
||||
.opcode = 0xd2,
|
||||
.nsid = cfg.namespace_id,
|
||||
.addr = (unsigned long)(void *)head_buf,
|
||||
.cdw12 = EVENTLOG,
|
||||
.cdw13 = 0,
|
||||
};
|
||||
int output;
|
||||
int core_num, err;
|
||||
|
||||
err = read_header(&cmd, dev_fd(dev));
|
||||
if (err)
|
||||
return err;
|
||||
sprintf(file_path, "%s_EventLog.bin", cfg.file_prefix);
|
||||
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (output < 0)
|
||||
return -errno;
|
||||
err = write_header(head_buf, output, INTERNAL_LOG_MAX_BYTE_TRANSFER);
|
||||
|
||||
core_num = ehdr->header.numcores;
|
||||
|
||||
if (err) {
|
||||
close(output);
|
||||
return err;
|
||||
}
|
||||
cmd.addr = (unsigned long)(void *)buf;
|
||||
|
||||
if (cfg.verbose)
|
||||
printf("Event Log, cores: %d log size: %d\n", core_num, ehdr->header.log_size * 4);
|
||||
|
||||
for (__u32 j = 0; j < core_num; j++) {
|
||||
if (cfg.verbose) {
|
||||
for (int k = 0 ; k < 16; k++) {
|
||||
printf("core: %d event: %d ", j, k);
|
||||
printf("validity: %d ", ehdr->edumps[j].eventIdValidity[k]);
|
||||
printf("offset: %d\n", ehdr->edumps[j].eventidoffset[k]);
|
||||
}
|
||||
}
|
||||
cmd.cdw13 = ehdr->edumps[j].coreoffset;
|
||||
err = cmd_dump_repeat(&cmd, ehdr->edumps[j].coresize,
|
||||
output, dev_fd(dev), false);
|
||||
if (err) {
|
||||
close(output);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
close(output);
|
||||
printf("Successfully wrote log to %s\n", file_path);
|
||||
return err;
|
||||
}
|
||||
|
||||
static size_t get_nlog_header_size(struct nlog_dump_header_common *nlog_header)
|
||||
{
|
||||
switch (nlog_header->ver.major) {
|
||||
case 3:
|
||||
return sizeof(struct nlog_dump_header3_0);
|
||||
case 4:
|
||||
if (nlog_header->ver.minor == 0)
|
||||
return sizeof(struct nlog_dump_header4_0);
|
||||
return sizeof(struct nlog_dump_header4_1);
|
||||
default:
|
||||
return INTERNAL_LOG_MAX_BYTE_TRANSFER;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* dumps nlogs from specified core or all cores when core = -1 */
|
||||
static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
|
||||
{
|
||||
int err = 0;
|
||||
__u32 count, core_num;
|
||||
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
|
||||
char file_path[PATH_MAX];
|
||||
struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *)buf;
|
||||
struct nvme_passthru_cmd cmd = {
|
||||
.opcode = 0xd2,
|
||||
.nsid = cfg.namespace_id,
|
||||
.addr = (unsigned long)(void *)buf
|
||||
};
|
||||
|
||||
struct dump_select {
|
||||
union {
|
||||
struct {
|
||||
__u32 selectLog : 3;
|
||||
__u32 selectCore : 2;
|
||||
__u32 selectNlog : 8;
|
||||
};
|
||||
__u32 raw;
|
||||
};
|
||||
} log_select;
|
||||
int output;
|
||||
bool is_open = false;
|
||||
size_t header_size = 0;
|
||||
|
||||
log_select.selectCore = core < 0 ? 0 : core;
|
||||
do {
|
||||
log_select.selectNlog = 0;
|
||||
do {
|
||||
cmd.cdw13 = 0;
|
||||
cmd.cdw12 = log_select.raw;
|
||||
err = read_header(&cmd, dev_fd(dev));
|
||||
if (err) {
|
||||
if (is_open)
|
||||
close(output);
|
||||
return err;
|
||||
}
|
||||
count = nlog_header->totalnlogs;
|
||||
core_num = core < 0 ? nlog_header->corecount : 0;
|
||||
if (!header_size) {
|
||||
sprintf(file_path, "%s_NLog.bin", cfg.file_prefix);
|
||||
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (output < 0)
|
||||
return -errno;
|
||||
header_size = get_nlog_header_size(nlog_header);
|
||||
is_open = true;
|
||||
}
|
||||
err = write_header(buf, output, header_size);
|
||||
if (err)
|
||||
break;
|
||||
if (cfg.verbose)
|
||||
print_nlog_header(buf);
|
||||
cmd.cdw13 = 0x400;
|
||||
err = cmd_dump_repeat(&cmd, nlog_header->nlogbytesize / 4,
|
||||
output, dev_fd(dev), true);
|
||||
if (err)
|
||||
break;
|
||||
} while (++log_select.selectNlog < count);
|
||||
if (err)
|
||||
break;
|
||||
} while (++log_select.selectCore < core_num);
|
||||
if (is_open) {
|
||||
close(output);
|
||||
printf("Successfully wrote log to %s\n", file_path);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
enum telemetry_type {
|
||||
HOSTGENOLD,
|
||||
HOSTGENNEW,
|
||||
CONTROLLER
|
||||
};
|
||||
|
||||
static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetry_type ttype)
|
||||
{
|
||||
struct nvme_telemetry_log *log = NULL;
|
||||
size_t log_size = 0;
|
||||
int err = 0, output;
|
||||
__u8 *buffer = NULL;
|
||||
size_t bytes_remaining = 0;
|
||||
int data_area = NVME_TELEMETRY_DA_3;
|
||||
char file_path[PATH_MAX];
|
||||
char *log_name;
|
||||
|
||||
switch (ttype) {
|
||||
case HOSTGENNEW:
|
||||
log_name = "TelemetryHostGenNew";
|
||||
break;
|
||||
case HOSTGENOLD:
|
||||
log_name = "TelemetryHostGenOld";
|
||||
break;
|
||||
case CONTROLLER:
|
||||
log_name = "TelemetryController";
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sprintf(file_path, "%s_%s.bin", cfg.file_prefix, log_name);
|
||||
output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (output < 0)
|
||||
return -errno;
|
||||
|
||||
switch (ttype) {
|
||||
case HOSTGENNEW:
|
||||
err = nvme_get_new_host_telemetry(dev_fd(dev), &log,
|
||||
data_area, &log_size);
|
||||
break;
|
||||
case HOSTGENOLD:
|
||||
err = nvme_get_host_telemetry(dev_fd(dev), &log,
|
||||
data_area, &log_size);
|
||||
break;
|
||||
case CONTROLLER:
|
||||
err = nvme_get_ctrl_telemetry(dev_fd(dev), true, &log,
|
||||
data_area, &log_size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto tele_close_output;
|
||||
|
||||
bytes_remaining = log_size;
|
||||
buffer = (__u8 *)log;
|
||||
|
||||
while (bytes_remaining) {
|
||||
ssize_t bytes_written = write(output, buffer, bytes_remaining);
|
||||
|
||||
if (bytes_written < 0) {
|
||||
err = -errno;
|
||||
goto tele_close_output;
|
||||
}
|
||||
bytes_remaining -= bytes_written;
|
||||
buffer += bytes_written;
|
||||
}
|
||||
printf("Successfully wrote log to %s\n", file_path);
|
||||
|
||||
tele_close_output:
|
||||
free(log);
|
||||
close(output);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int solidigm_get_internal_log(int argc, char **argv, struct command *command,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
char sn_prefix[sizeof(((struct nvme_id_ctrl *)0)->sn)+1];
|
||||
int log_count = 0;
|
||||
int err;
|
||||
struct nvme_dev *dev;
|
||||
bool all = false;
|
||||
|
||||
const char *desc = "Get Debug Firmware Logs and save them.";
|
||||
const char *type =
|
||||
"Log type: ALL, CONTROLLERINITTELEMETRY, HOSTINITTELEMETRY, HOSTINITTELEMETRYNOGEN, NLOG, ASSERT, EVENT. Defaults to ALL.";
|
||||
const char *prefix = "Output file prefix; defaults to device serial number.";
|
||||
const char *verbose = "To print out verbose info.";
|
||||
const char *namespace_id = "Namespace to get logs from.";
|
||||
|
||||
|
||||
struct config cfg = {
|
||||
.namespace_id = NVME_NSID_ALL,
|
||||
.file_prefix = NULL,
|
||||
.type = NULL,
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_STR("type", 't', &cfg.type, type),
|
||||
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
|
||||
OPT_FILE("file-prefix", 'p', &cfg.file_prefix, prefix),
|
||||
OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!cfg.file_prefix) {
|
||||
err = get_serial_number(sn_prefix, dev_fd(dev));
|
||||
if (err)
|
||||
goto out_dev;
|
||||
cfg.file_prefix = sn_prefix;
|
||||
}
|
||||
|
||||
if (!cfg.type)
|
||||
cfg.type = "ALL";
|
||||
else {
|
||||
for (char *p = cfg.type; *p; ++p)
|
||||
*p = toupper(*p);
|
||||
}
|
||||
|
||||
if (!strcmp(cfg.type, "ALL"))
|
||||
all = true;
|
||||
if (all || !strcmp(cfg.type, "ASSERT")) {
|
||||
err = dump_assert_logs(dev, cfg);
|
||||
if (err == 0)
|
||||
log_count++;
|
||||
else if (err < 0)
|
||||
perror("Assert log");
|
||||
}
|
||||
if (all || !strcmp(cfg.type, "EVENT")) {
|
||||
err = dump_event_logs(dev, cfg);
|
||||
if (err == 0)
|
||||
log_count++;
|
||||
else if (err < 0)
|
||||
perror("Eventt log");
|
||||
}
|
||||
if (all || !strcmp(cfg.type, "NLOG")) {
|
||||
err = dump_nlogs(dev, cfg, -1);
|
||||
if (err == 0)
|
||||
log_count++;
|
||||
else if (err < 0)
|
||||
perror("Nlog");
|
||||
}
|
||||
if (all || !strcmp(cfg.type, "CONTROLLERINITTELEMETRY")) {
|
||||
err = dump_telemetry(dev, cfg, CONTROLLER);
|
||||
if (err == 0)
|
||||
log_count++;
|
||||
else if (err < 0)
|
||||
perror("Telemetry Controller Initated");
|
||||
}
|
||||
if (all || !strcmp(cfg.type, "HOSTINITTELEMETRYNOGEN")) {
|
||||
err = dump_telemetry(dev, cfg, HOSTGENOLD);
|
||||
if (err == 0)
|
||||
log_count++;
|
||||
else if (err < 0)
|
||||
perror("Previously existing Telemetry Host Initated");
|
||||
}
|
||||
if (all || !strcmp(cfg.type, "HOSTINITTELEMETRY")) {
|
||||
err = dump_telemetry(dev, cfg, HOSTGENNEW);
|
||||
if (err == 0)
|
||||
log_count++;
|
||||
else if (err < 0)
|
||||
perror("Telemetry Host Initated");
|
||||
}
|
||||
|
||||
if (log_count == 0) {
|
||||
if (err > 0)
|
||||
nvme_show_status(err);
|
||||
} else if ((log_count > 1) || cfg.verbose)
|
||||
printf("Total: %d log files with prefix: %s\n", log_count, cfg.file_prefix);
|
||||
out_dev:
|
||||
/* Redundant close() to make static code analysis happy */
|
||||
close(dev->direct.fd);
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
8
plugins/solidigm/solidigm-internal-logs.h
Normal file
8
plugins/solidigm/solidigm-internal-logs.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2023 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
int solidigm_get_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
|
|
@ -94,7 +94,6 @@ static void latency_tracker_bucket_parse(const struct latency_tracker *lt, int i
|
|||
__u32 bucket_data = le32_to_cpu(lt->stats.data[id]);
|
||||
|
||||
if (lt->print_flags == NORMAL) {
|
||||
|
||||
printf("%-*d", COL_WIDTH, id);
|
||||
|
||||
get_time_unit_label(buffer, lower_us, true);
|
||||
|
@ -137,12 +136,10 @@ static void latency_tracker_parse_linear(const struct latency_tracker *lt,
|
|||
__u32 bytes_per, __u32 us_step,
|
||||
bool nonzero_print)
|
||||
{
|
||||
for (int i = (start_offset / bytes_per) - 1;
|
||||
i < end_offset / bytes_per; i++) {
|
||||
if (nonzero_print && lt->stats.data[i] == 0)
|
||||
for (int i = (start_offset / bytes_per) - 1; i < end_offset / bytes_per; i++) {
|
||||
if (nonzero_print && !lt->stats.data[i])
|
||||
continue;
|
||||
latency_tracker_bucket_parse(lt, i, us_step * i,
|
||||
us_step * (i + 1), true);
|
||||
latency_tracker_bucket_parse(lt, i, us_step * i, us_step * (i + 1), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,6 +150,7 @@ static void latency_tracker_parse_linear(const struct latency_tracker *lt,
|
|||
static int latency_tracker_bucket_pos2us(const struct latency_tracker *lt, int i)
|
||||
{
|
||||
__u32 base_val = 1 << lt->base_range_bits;
|
||||
|
||||
if (i < (base_val << 1))
|
||||
return i;
|
||||
|
||||
|
@ -171,15 +169,15 @@ static int latency_tracker_bucket_pos2us(const struct latency_tracker *lt, int i
|
|||
* "values" : {
|
||||
*/
|
||||
static void latency_tracker_populate_json_root(const struct latency_tracker *lt,
|
||||
struct json_object *root)
|
||||
struct json_object *root)
|
||||
{
|
||||
struct json_object *subroot = json_create_object();
|
||||
|
||||
json_object_add_value_object(root, "latstats", subroot);
|
||||
json_object_add_value_string(subroot, "type", lt->cfg.write ? "write" : "read");
|
||||
if (lt->has_average_latency_field) {
|
||||
json_object_add_value_uint64(subroot, "average_latency", le64_to_cpu(lt->stats.average_latency));
|
||||
}
|
||||
if (lt->has_average_latency_field)
|
||||
json_object_add_value_uint64(subroot, "average_latency",
|
||||
le64_to_cpu(lt->stats.average_latency));
|
||||
json_object_add_value_object(subroot, "values", lt->bucket_list);
|
||||
}
|
||||
|
||||
|
@ -199,13 +197,12 @@ static void latency_tracker_parse_4_0(const struct latency_tracker *lt)
|
|||
int lower_us = latency_tracker_bucket_pos2us(lt, i);
|
||||
int upper_us = latency_tracker_bucket_pos2us(lt, i + 1);
|
||||
|
||||
latency_tracker_bucket_parse(lt, i, lower_us,
|
||||
upper_us,
|
||||
latency_tracker_bucket_parse(lt, i, lower_us, upper_us,
|
||||
i < (lt->bucket_list_size - 1));
|
||||
}
|
||||
}
|
||||
|
||||
static void print_dash_separator()
|
||||
static void print_dash_separator(void)
|
||||
{
|
||||
printf("--------------------------------------------------\n");
|
||||
}
|
||||
|
@ -218,16 +215,14 @@ static void latency_tracker_pre_parse(struct latency_tracker *lt)
|
|||
printf("UUID-idx: %d\n", lt->uuid_index);
|
||||
printf("Major Revision: %u\nMinor Revision: %u\n",
|
||||
le16_to_cpu(lt->stats.version_major), le16_to_cpu(lt->stats.version_minor));
|
||||
if (lt->has_average_latency_field) {
|
||||
if (lt->has_average_latency_field)
|
||||
printf("Average Latency: %" PRIu64 "\n", le64_to_cpu(lt->stats.average_latency));
|
||||
}
|
||||
print_dash_separator();
|
||||
printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value");
|
||||
print_dash_separator();
|
||||
}
|
||||
if (lt->print_flags == JSON) {
|
||||
if (lt->print_flags == JSON)
|
||||
lt->bucket_list = json_object_new_array();
|
||||
}
|
||||
}
|
||||
|
||||
static void latency_tracker_post_parse(struct latency_tracker *lt)
|
||||
|
@ -253,11 +248,10 @@ static void latency_tracker_parse(struct latency_tracker *lt)
|
|||
latency_tracker_parse_3_0(lt);
|
||||
break;
|
||||
case 4:
|
||||
if (version_minor >= 8){
|
||||
if (version_minor >= 8)
|
||||
lt->has_average_latency_field = true;
|
||||
}
|
||||
latency_tracker_pre_parse(lt);
|
||||
if (version_minor == 0){
|
||||
if (!version_minor) {
|
||||
lt->base_range_bits = BASE_RANGE_BITS_4_0;
|
||||
lt->bucket_list_size = BUCKET_LIST_SIZE_4_0;
|
||||
}
|
||||
|
@ -275,7 +269,7 @@ static void latency_tracker_parse(struct latency_tracker *lt)
|
|||
#define LATENCY_TRACKING_FID 0xe2
|
||||
#define LATENCY_TRACKING_FID_DATA_LEN 32
|
||||
|
||||
static int latency_tracking_is_enable(struct latency_tracker *lt, __u32 * enabled)
|
||||
static int latency_tracking_is_enable(struct latency_tracker *lt, __u32 *enabled)
|
||||
{
|
||||
struct nvme_get_features_args args_get = {
|
||||
.args_size = sizeof(args_get),
|
||||
|
@ -298,13 +292,12 @@ static int latency_tracking_enable(struct latency_tracker *lt)
|
|||
__u32 result;
|
||||
int err;
|
||||
|
||||
if (!(lt->cfg.enable || lt->cfg.disable)){
|
||||
if (!(lt->cfg.enable || lt->cfg.disable))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lt->cfg.enable && lt->cfg.disable){
|
||||
fprintf(stderr,"Cannot enable and disable simultaneously.\n");
|
||||
return EINVAL;
|
||||
if (lt->cfg.enable && lt->cfg.disable) {
|
||||
fprintf(stderr, "Cannot enable and disable simultaneously.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct nvme_set_features_args args_set = {
|
||||
|
@ -345,9 +338,9 @@ static int latency_tracker_get_log(struct latency_tracker *lt)
|
|||
{
|
||||
int err;
|
||||
|
||||
if (lt->cfg.read && lt->cfg.write){
|
||||
fprintf(stderr,"Cannot capture read and write logs simultaneously.\n");
|
||||
return EINVAL;
|
||||
if (lt->cfg.read && lt->cfg.write) {
|
||||
fprintf(stderr, "Cannot capture read and write logs simultaneously.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(lt->cfg.read || lt->cfg.write))
|
||||
|
@ -422,31 +415,31 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd
|
|||
if (lt.print_flags == -EINVAL) {
|
||||
fprintf(stderr, "Invalid output format '%s'\n", lt.cfg.output_format);
|
||||
dev_close(dev);
|
||||
return EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lt.cfg.type > 0xf) {
|
||||
fprintf(stderr, "Invalid Log type value '%d'\n", lt.cfg.type);
|
||||
dev_close(dev);
|
||||
return EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lt.cfg.type && !(lt.cfg.read || lt.cfg.write)) {
|
||||
fprintf(stderr, "Log type option valid only when retrieving statistics\n");
|
||||
dev_close(dev);
|
||||
return EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lt.uuid_index = solidigm_get_vu_uuid_index(dev);
|
||||
|
||||
err = latency_tracking_enable(<);
|
||||
if (err){
|
||||
if (err) {
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = latency_tracker_get_log(<);
|
||||
if (err){
|
||||
if (err) {
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
@ -460,16 +453,16 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd
|
|||
if (!err) {
|
||||
if (lt.print_flags == JSON) {
|
||||
struct json_object *root = json_create_object();
|
||||
json_object_add_value_int(root,"enabled", enabled);
|
||||
|
||||
json_object_add_value_int(root, "enabled", enabled);
|
||||
json_print_object(root, NULL);
|
||||
json_free_object(root);
|
||||
printf("\n");
|
||||
} else if (lt.print_flags == BINARY) {
|
||||
putchar(enabled);
|
||||
} else {
|
||||
printf(
|
||||
"Latency Statistics Tracking (UUID-idx:%d, FID:0x%X) is currently %i.\n",
|
||||
lt.uuid_index, LATENCY_TRACKING_FID, enabled);
|
||||
printf("Latency Statistics Tracking (UUID-idx:%d, FID:0x%X) is currently %i.\n",
|
||||
lt.uuid_index, LATENCY_TRACKING_FID, enabled);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Could not read feature id 0xE2.\n");
|
||||
|
|
300
plugins/solidigm/solidigm-log-page-dir.c
Normal file
300
plugins/solidigm/solidigm-log-page-dir.c
Normal file
|
@ -0,0 +1,300 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2023 Solidigm.
|
||||
*
|
||||
* Author: karl.dedow@solidigm.com
|
||||
*/
|
||||
|
||||
#include "solidigm-log-page-dir.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "nvme-print.h"
|
||||
|
||||
#include "plugins/ocp/ocp-utils.h"
|
||||
|
||||
#define MIN_VENDOR_LID 0xC0
|
||||
#define SOLIDIGM_MAX_UUID 2
|
||||
|
||||
static const char dash[100] = {[0 ... 99] = '-'};
|
||||
|
||||
struct lid_dir {
|
||||
struct __packed {
|
||||
bool supported;
|
||||
const char *str;
|
||||
} lid[NVME_LOG_SUPPORTED_LOG_PAGES_MAX];
|
||||
};
|
||||
|
||||
static void init_lid_dir(struct lid_dir *lid_dir)
|
||||
{
|
||||
static const char *unknown_str = "Unknown";
|
||||
|
||||
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
|
||||
lid_dir->lid[lid].supported = false;
|
||||
lid_dir->lid[lid].str = unknown_str;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_invalid_uuid(const struct nvme_id_uuid_list_entry entry)
|
||||
{
|
||||
static const unsigned char ALL_ZERO_UUID[NVME_UUID_LEN] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
return memcmp(ALL_ZERO_UUID, entry.uuid, NVME_UUID_LEN) == 0;
|
||||
}
|
||||
|
||||
static bool is_solidigm_uuid(const struct nvme_id_uuid_list_entry entry)
|
||||
{
|
||||
static const unsigned char SOLIDIGM_UUID[NVME_UUID_LEN] = {
|
||||
0x96, 0x19, 0x58, 0x6e, 0xc1, 0x1b, 0x43, 0xad,
|
||||
0xaa, 0xaa, 0x65, 0x41, 0x87, 0xf6, 0xbb, 0xb2
|
||||
};
|
||||
|
||||
return memcmp(SOLIDIGM_UUID, entry.uuid, NVME_UUID_LEN) == 0;
|
||||
}
|
||||
|
||||
static bool is_ocp_uuid(const struct nvme_id_uuid_list_entry entry)
|
||||
{
|
||||
static const unsigned char OCP_UUID[NVME_UUID_LEN] = {
|
||||
0xc1, 0x94, 0xd5, 0x5b, 0xe0, 0x94, 0x47, 0x94,
|
||||
0xa2, 0x1d, 0x29, 0x99, 0x8f, 0x56, 0xbe, 0x6f
|
||||
};
|
||||
|
||||
return memcmp(OCP_UUID, entry.uuid, NVME_UUID_LEN) == 0;
|
||||
}
|
||||
|
||||
static int get_supported_log_pages_log(struct nvme_dev *dev, int uuid_index,
|
||||
struct nvme_supported_log_pages *supported)
|
||||
{
|
||||
static const __u8 LID;
|
||||
|
||||
memset(supported, 0, sizeof(*supported));
|
||||
struct nvme_get_log_args args = {
|
||||
.lpo = 0,
|
||||
.result = NULL,
|
||||
.log = supported,
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.lid = LID,
|
||||
.len = sizeof(*supported),
|
||||
.nsid = NVME_NSID_ALL,
|
||||
.csi = NVME_CSI_NVM,
|
||||
.lsi = NVME_LOG_LSI_NONE,
|
||||
.lsp = 0,
|
||||
.uuidx = uuid_index,
|
||||
.rae = false,
|
||||
.ot = false,
|
||||
};
|
||||
|
||||
return nvme_get_log(&args);
|
||||
}
|
||||
|
||||
static struct lid_dir *get_standard_lids(struct nvme_supported_log_pages *supported)
|
||||
{
|
||||
static struct lid_dir standard_dir = { 0 };
|
||||
|
||||
init_lid_dir(&standard_dir);
|
||||
standard_dir.lid[0x00].str = "Supported Log Pages";
|
||||
standard_dir.lid[0x01].str = "Error Information";
|
||||
standard_dir.lid[0x02].str = "SMART / Health Information";
|
||||
standard_dir.lid[0x03].str = "Firmware Slot Information";
|
||||
standard_dir.lid[0x04].str = "Changed Namespace List";
|
||||
standard_dir.lid[0x05].str = "Commands Supported and Effects";
|
||||
standard_dir.lid[0x06].str = "Device Self Test";
|
||||
standard_dir.lid[0x07].str = "Telemetry Host-Initiated";
|
||||
standard_dir.lid[0x08].str = "Telemetry Controller-Initiated";
|
||||
standard_dir.lid[0x09].str = "Endurance Group Information";
|
||||
standard_dir.lid[0x0A].str = "Predictable Latency Per NVM Set";
|
||||
standard_dir.lid[0x0B].str = "Predictable Latency Event Aggregate";
|
||||
standard_dir.lid[0x0C].str = "Asymmetric Namespace Access";
|
||||
standard_dir.lid[0x0D].str = "Persistent Event Log";
|
||||
standard_dir.lid[0x0E].str = "Predictable Latency Event Aggregate";
|
||||
standard_dir.lid[0x0F].str = "Endurance Group Event Aggregate";
|
||||
standard_dir.lid[0x10].str = "Media Unit Status";
|
||||
standard_dir.lid[0x11].str = "Supported Capacity Configuration List";
|
||||
standard_dir.lid[0x12].str = "Feature Identifiers Supported and Effects";
|
||||
standard_dir.lid[0x13].str = "NVMe-MI Commands Supported and Effects";
|
||||
standard_dir.lid[0x14].str = "Command and Feature lockdown";
|
||||
standard_dir.lid[0x15].str = "Boot Partition";
|
||||
standard_dir.lid[0x16].str = "Rotational Media Information";
|
||||
standard_dir.lid[0x70].str = "Discovery";
|
||||
standard_dir.lid[0x80].str = "Reservation Notification";
|
||||
standard_dir.lid[0x81].str = "Sanitize Status";
|
||||
|
||||
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
|
||||
if (!supported->lid_support[lid] || lid >= MIN_VENDOR_LID)
|
||||
continue;
|
||||
|
||||
standard_dir.lid[lid].supported = true;
|
||||
}
|
||||
|
||||
return &standard_dir;
|
||||
}
|
||||
|
||||
static void update_vendor_lid_supported(struct nvme_supported_log_pages *supported,
|
||||
struct lid_dir *lid_dir)
|
||||
{
|
||||
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
|
||||
if (!supported->lid_support[lid] || lid < MIN_VENDOR_LID)
|
||||
continue;
|
||||
|
||||
lid_dir->lid[lid].supported = true;
|
||||
}
|
||||
}
|
||||
|
||||
static struct lid_dir *get_solidigm_lids(struct nvme_supported_log_pages *supported)
|
||||
{
|
||||
static struct lid_dir solidigm_dir = { 0 };
|
||||
|
||||
init_lid_dir(&solidigm_dir);
|
||||
solidigm_dir.lid[0xC1].str = "Read Commands Latency Statistics";
|
||||
solidigm_dir.lid[0xC2].str = "Write Commands Latency Statistics";
|
||||
solidigm_dir.lid[0xC4].str = "Endurance Manager Statistics";
|
||||
solidigm_dir.lid[0xC5].str = "Temperature Statistics";
|
||||
solidigm_dir.lid[0xCA].str = "SMART Attributes";
|
||||
|
||||
update_vendor_lid_supported(supported, &solidigm_dir);
|
||||
|
||||
return &solidigm_dir;
|
||||
}
|
||||
|
||||
static struct lid_dir *get_ocp_lids(struct nvme_supported_log_pages *supported)
|
||||
{
|
||||
static struct lid_dir ocp_dir = { 0 };
|
||||
|
||||
init_lid_dir(&ocp_dir);
|
||||
ocp_dir.lid[0xC0].str = "OCP SMART / Health Information Extended";
|
||||
ocp_dir.lid[0xC1].str = "OCP Error Recovery";
|
||||
ocp_dir.lid[0xC2].str = "OCP Firmware Activation History";
|
||||
ocp_dir.lid[0xC3].str = "OCP Latency Monitor";
|
||||
ocp_dir.lid[0xC4].str = "OCP Device Capabilities";
|
||||
ocp_dir.lid[0xC5].str = "OCP Unsupported Requirements";
|
||||
|
||||
update_vendor_lid_supported(supported, &ocp_dir);
|
||||
|
||||
return &ocp_dir;
|
||||
}
|
||||
|
||||
static void supported_log_pages_normal(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1])
|
||||
{
|
||||
printf("%-5s %-4s %-42s\n", "uuidx", "LID", "Description");
|
||||
printf("%-.5s %-.4s %-.42s\n", dash, dash, dash);
|
||||
|
||||
for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
|
||||
if (!lid_dir[uuid_index])
|
||||
continue;
|
||||
|
||||
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
|
||||
if (!lid_dir[uuid_index]->lid[lid].supported)
|
||||
continue;
|
||||
|
||||
printf("%-5d 0x%02x %s\n", le32_to_cpu(uuid_index), le32_to_cpu(lid),
|
||||
lid_dir[uuid_index]->lid[lid].str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void supported_log_pages_json(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1])
|
||||
{
|
||||
struct json_object *root = json_create_array();
|
||||
|
||||
for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
|
||||
if (!lid_dir[uuid_index])
|
||||
continue;
|
||||
|
||||
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
|
||||
if (!lid_dir[uuid_index]->lid[lid].supported)
|
||||
continue;
|
||||
|
||||
struct json_object *lid_obj = json_create_object();
|
||||
|
||||
json_object_add_value_uint(lid_obj, "uuidx", le32_to_cpu(uuid_index));
|
||||
json_object_add_value_uint(lid_obj, "lid", le32_to_cpu(lid));
|
||||
json_object_add_value_string(lid_obj, "description",
|
||||
lid_dir[uuid_index]->lid[lid].str);
|
||||
json_array_add_value_object(root, lid_obj);
|
||||
}
|
||||
}
|
||||
|
||||
json_print_object(root, NULL);
|
||||
json_free_object(root);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
const int NO_UUID_INDEX = 0;
|
||||
const char *description = "Retrieves list of supported log pages for each UUID index.";
|
||||
char *format = "normal";
|
||||
|
||||
OPT_ARGS(options) = {
|
||||
OPT_FMT("output-format", 'o', &format, "output format : normal | json"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
struct nvme_dev *dev = NULL;
|
||||
int err = parse_and_open(&dev, argc, argv, description, options);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
struct lid_dir *lid_dirs[SOLIDIGM_MAX_UUID + 1] = { 0 };
|
||||
struct nvme_id_uuid_list uuid_list = { 0 };
|
||||
struct nvme_supported_log_pages supported = { 0 };
|
||||
|
||||
err = get_supported_log_pages_log(dev, NO_UUID_INDEX, &supported);
|
||||
|
||||
if (!err) {
|
||||
lid_dirs[NO_UUID_INDEX] = get_standard_lids(&supported);
|
||||
|
||||
// Assume VU logs are the Solidigm log pages if UUID not supported.
|
||||
if (nvme_identify_uuid(dev_fd(dev), &uuid_list)) {
|
||||
struct lid_dir *solidigm_lid_dir = get_solidigm_lids(&supported);
|
||||
|
||||
// Transfer supported Solidigm lids to lid directory at UUID index 0
|
||||
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
|
||||
if (solidigm_lid_dir->lid[lid].supported)
|
||||
lid_dirs[NO_UUID_INDEX]->lid[lid] = solidigm_lid_dir->lid[lid];
|
||||
}
|
||||
} else {
|
||||
for (int uuid_index = 1; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
|
||||
if (is_invalid_uuid(uuid_list.entry[uuid_index - 1]))
|
||||
break;
|
||||
else if (get_supported_log_pages_log(dev, uuid_index, &supported))
|
||||
continue;
|
||||
|
||||
if (is_solidigm_uuid(uuid_list.entry[uuid_index - 1]))
|
||||
lid_dirs[uuid_index] = get_solidigm_lids(&supported);
|
||||
else if (is_ocp_uuid(uuid_list.entry[uuid_index - 1]))
|
||||
lid_dirs[uuid_index] = get_ocp_lids(&supported);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nvme_show_status(err);
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
const enum nvme_print_flags print_flag = validate_output_format(format);
|
||||
|
||||
if (print_flag == NORMAL) {
|
||||
supported_log_pages_normal(lid_dirs);
|
||||
} else if (print_flag == JSON) {
|
||||
supported_log_pages_json(lid_dirs);
|
||||
} else {
|
||||
fprintf(stderr, "Error: Invalid output format specified: %s.\n", format);
|
||||
err = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Redundant close() to make static code analysis happy */
|
||||
close(dev->direct.fd);
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
17
plugins/solidigm/solidigm-log-page-dir.h
Normal file
17
plugins/solidigm/solidigm-log-page-dir.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2023 Solidigm.
|
||||
*
|
||||
* Authors: karl.dedow@solidigm.com
|
||||
*/
|
||||
|
||||
#ifndef SOLIDIGM_LOG_PAGE_DIRECTORY_H
|
||||
#define SOLIDIGM_LOG_PAGE_DIRECTORY_H
|
||||
|
||||
struct command;
|
||||
struct plugin;
|
||||
|
||||
int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin);
|
||||
|
||||
#endif
|
63
plugins/solidigm/solidigm-market-log.c
Normal file
63
plugins/solidigm/solidigm-market-log.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2023 Solidigm.
|
||||
*
|
||||
* Authors: leonardo.da.cunha@solidigm.com
|
||||
* Hardeep.Dhillon@solidigm.com
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "nvme.h"
|
||||
#include "libnvme.h"
|
||||
#include "plugin.h"
|
||||
#include "nvme-print.h"
|
||||
|
||||
#define MARKET_LOG_MAX_SIZE 512
|
||||
|
||||
int sldgm_get_market_log(int argc, char **argv, struct command *command,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Get Solidigm Marketing Name log and show it.";
|
||||
const char *raw = "dump output in binary format";
|
||||
struct nvme_dev *dev;
|
||||
char log[MARKET_LOG_MAX_SIZE];
|
||||
int err;
|
||||
|
||||
struct config {
|
||||
bool raw_binary;
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = nvme_get_log_simple(dev_fd(dev), 0xdd, sizeof(log), log);
|
||||
if (!err) {
|
||||
if (!cfg.raw_binary)
|
||||
printf("Solidigm Marketing Name Log:\n%s\n", log);
|
||||
else
|
||||
d_raw((unsigned char *)&log, sizeof(log));
|
||||
} else if (err > 0)
|
||||
|
||||
nvme_show_status(err);
|
||||
/* Redundant close() to make static code analysis happy */
|
||||
close(dev->direct.fd);
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
8
plugins/solidigm/solidigm-market-log.h
Normal file
8
plugins/solidigm/solidigm-market-log.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2023 Solidigm.
|
||||
*
|
||||
* Author: hardeep.dhillon@solidigm.com
|
||||
*/
|
||||
|
||||
int sldgm_get_market_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
* Copyright (c) 2022-2023 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
@ -10,19 +10,34 @@
|
|||
#define CREATE_CMD
|
||||
#include "solidigm-nvme.h"
|
||||
|
||||
#include "solidigm-id-ctrl.h"
|
||||
#include "solidigm-smart.h"
|
||||
#include "solidigm-internal-logs.h"
|
||||
#include "solidigm-garbage-collection.h"
|
||||
#include "solidigm-latency-tracking.h"
|
||||
#include "solidigm-telemetry.h"
|
||||
#include "solidigm-log-page-dir.h"
|
||||
#include "solidigm-market-log.h"
|
||||
|
||||
#include "plugins/ocp/ocp-clear-fw-update-history.h"
|
||||
#include "plugins/ocp/ocp-smart-extended-log.h"
|
||||
#include "plugins/ocp/ocp-fw-activation-history.h"
|
||||
|
||||
static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
return __id_ctrl(argc, argv, cmd, plugin, sldgm_id_ctrl);
|
||||
}
|
||||
|
||||
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
return solidigm_get_additional_smart_log(argc, argv, cmd, plugin);
|
||||
}
|
||||
|
||||
static int get_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
return solidigm_get_internal_log(argc, argv, cmd, plugin);
|
||||
}
|
||||
|
||||
static int get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
return solidigm_get_garbage_collection_log(argc, argv, cmd, plugin);
|
||||
|
@ -49,3 +64,21 @@ static int smart_cloud(int argc, char **argv, struct command *cmd,
|
|||
{
|
||||
return ocp_smart_add_log(argc, argv, cmd, plugin);
|
||||
}
|
||||
|
||||
static int fw_activation_history(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
return ocp_fw_activation_history_log(argc, argv, cmd, plugin);
|
||||
}
|
||||
|
||||
static int get_log_page_directory_log(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
return solidigm_get_log_page_directory_log(argc, argv, cmd, plugin);
|
||||
}
|
||||
|
||||
static int get_market_log(int argc, char **argv, struct command *cmd,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
return sldgm_get_market_log(argc, argv, cmd, plugin);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
* Copyright (c) 2022-2023 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
@ -13,18 +13,21 @@
|
|||
|
||||
#include "cmd.h"
|
||||
|
||||
#define SOLIDIGM_PLUGIN_VERSION "0.8"
|
||||
#define SOLIDIGM_PLUGIN_VERSION "0.14"
|
||||
|
||||
PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
|
||||
COMMAND_LIST(
|
||||
ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
|
||||
ENTRY("smart-log-add", "Retrieve Solidigm SMART Log", get_additional_smart_log)
|
||||
ENTRY("vs-smart-add-log", "Get SMART / health extended log (redirects to ocp plug-in)", smart_cloud)
|
||||
ENTRY("vs-internal-log", "Retrieve Debug log binaries", get_internal_log)
|
||||
ENTRY("garbage-collect-log", "Retrieve Garbage Collection Log", get_garbage_collection_log)
|
||||
ENTRY("market-log", "Retrieve Market Log", get_market_log)
|
||||
ENTRY("latency-tracking-log", "Enable/Retrieve Latency tracking Log", get_latency_tracking_log)
|
||||
ENTRY("parse-telemetry-log", "Parse Telemetry Log binary", get_telemetry_log)
|
||||
ENTRY("clear-fw-activate-history",
|
||||
"Clear firmware update history log (redirects to ocp plug-in)",
|
||||
clear_fw_update_history)
|
||||
ENTRY("clear-fw-activate-history", "Clear firmware update history log (redirects to ocp plug-in)", clear_fw_update_history)
|
||||
ENTRY("vs-fw-activate-history", "Get firmware activation history log (redirects to ocp plug-in)", fw_activation_history)
|
||||
ENTRY("log-page-directory", "Retrieve log page directory", get_log_page_directory_log)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -21,32 +21,31 @@
|
|||
#include "solidigm-smart.h"
|
||||
#include "solidigm-util.h"
|
||||
|
||||
struct __attribute__((packed)) nvme_additional_smart_log_item {
|
||||
struct __packed nvme_additional_smart_log_item {
|
||||
__u8 id;
|
||||
__u8 _kp[2];
|
||||
__u8 normalized;
|
||||
__u8 _np;
|
||||
union __attribute__((packed)) {
|
||||
union __packed {
|
||||
__u8 raw[6];
|
||||
struct __attribute__((packed)) wear_level {
|
||||
struct __packed wear_level {
|
||||
__le16 min;
|
||||
__le16 max;
|
||||
__le16 avg;
|
||||
} wear_level;
|
||||
struct __attribute__((packed)) thermal_throttle {
|
||||
struct __packed thermal_throttle {
|
||||
__u8 pct;
|
||||
__u32 count;
|
||||
} thermal_throttle;
|
||||
} ;
|
||||
};
|
||||
__u8 _rp;
|
||||
} ;
|
||||
typedef struct nvme_additional_smart_log_item smart_log_item_t;
|
||||
};
|
||||
|
||||
#define VU_SMART_PAGE_SIZE 512
|
||||
#define VU_SMART_MAX_ITEMS VU_SMART_PAGE_SIZE / sizeof(smart_log_item_t)
|
||||
typedef struct vu_smart_log {
|
||||
smart_log_item_t item[VU_SMART_MAX_ITEMS];
|
||||
} vu_smart_log_t;
|
||||
#define VU_SMART_MAX_ITEMS (VU_SMART_PAGE_SIZE / sizeof(struct nvme_additional_smart_log_item))
|
||||
struct vu_smart_log {
|
||||
struct nvme_additional_smart_log_item item[VU_SMART_MAX_ITEMS];
|
||||
};
|
||||
|
||||
static char *id_to_name(__u8 id)
|
||||
{
|
||||
|
@ -110,11 +109,10 @@ static char *id_to_name(__u8 id)
|
|||
}
|
||||
}
|
||||
|
||||
static void smart_log_item_print(smart_log_item_t *item)
|
||||
static void smart_log_item_print(struct nvme_additional_smart_log_item *item)
|
||||
{
|
||||
if (!item->id) {
|
||||
if (!item->id)
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%#x %-45s %3d ",
|
||||
item->id, id_to_name(item->id), item->normalized);
|
||||
|
@ -136,13 +134,12 @@ static void smart_log_item_print(smart_log_item_t *item)
|
|||
}
|
||||
}
|
||||
|
||||
static void smart_log_item_add_json(smart_log_item_t *item, struct json_object *dev_stats)
|
||||
static void smart_log_item_add_json(struct nvme_additional_smart_log_item *item, struct json_object *dev_stats)
|
||||
{
|
||||
struct json_object *entry_stats = json_create_object();
|
||||
|
||||
if (!item->id) {
|
||||
if (!item->id)
|
||||
return;
|
||||
}
|
||||
|
||||
json_object_add_value_int(entry_stats, "normalized", item->normalized);
|
||||
|
||||
|
@ -162,15 +159,14 @@ static void smart_log_item_add_json(smart_log_item_t *item, struct json_object *
|
|||
json_object_add_value_object(dev_stats, id_to_name(item->id), entry_stats);
|
||||
}
|
||||
|
||||
static void vu_smart_log_show_json(vu_smart_log_t *payload, unsigned int nsid, const char *devname)
|
||||
static void vu_smart_log_show_json(struct vu_smart_log *payload, unsigned int nsid, const char *devname)
|
||||
{
|
||||
struct json_object *dev_stats = json_create_object();
|
||||
smart_log_item_t *item = payload->item;
|
||||
struct nvme_additional_smart_log_item *item = payload->item;
|
||||
struct json_object *root;
|
||||
|
||||
for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) {
|
||||
for (int i = 0; i < VU_SMART_MAX_ITEMS; i++)
|
||||
smart_log_item_add_json(&item[i], dev_stats);
|
||||
}
|
||||
|
||||
root = json_create_object();
|
||||
json_object_add_value_string(root, "Solidigm SMART log", devname);
|
||||
|
@ -180,26 +176,25 @@ static void vu_smart_log_show_json(vu_smart_log_t *payload, unsigned int nsid, c
|
|||
json_free_object(root);
|
||||
}
|
||||
|
||||
static void vu_smart_log_show(vu_smart_log_t *payload, unsigned int nsid, const char *devname,
|
||||
static void vu_smart_log_show(struct vu_smart_log *payload, unsigned int nsid, const char *devname,
|
||||
__u8 uuid_index)
|
||||
{
|
||||
smart_log_item_t *item = payload->item;
|
||||
struct nvme_additional_smart_log_item *item = payload->item;
|
||||
|
||||
printf("Additional Smart Log for NVMe device:%s namespace-id:%x UUID-idx:%d\n",
|
||||
devname, nsid, uuid_index);
|
||||
printf("ID KEY Normalized Raw\n");
|
||||
|
||||
for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) {
|
||||
for (int i = 0; i < VU_SMART_MAX_ITEMS; i++)
|
||||
smart_log_item_print(&item[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Get Solidigm vendor specific smart log (optionally, "\
|
||||
"for the specified namespace), and show it.";
|
||||
const char *desc =
|
||||
"Get Solidigm vendor specific smart log (optionally, for the specified namespace), and show it.";
|
||||
const int solidigm_vu_smart_log_id = 0xCA;
|
||||
vu_smart_log_t smart_log_payload;
|
||||
struct vu_smart_log smart_log_payload;
|
||||
enum nvme_print_flags flags;
|
||||
struct nvme_dev *dev;
|
||||
int err;
|
||||
|
@ -254,15 +249,14 @@ int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd
|
|||
|
||||
err = nvme_get_log(&args);
|
||||
if (!err) {
|
||||
if (flags & JSON) {
|
||||
if (flags & JSON)
|
||||
vu_smart_log_show_json(&smart_log_payload,
|
||||
cfg.namespace_id, dev->name);
|
||||
} else if (flags & BINARY) {
|
||||
else if (flags & BINARY)
|
||||
d_raw((unsigned char *)&smart_log_payload, sizeof(smart_log_payload));
|
||||
} else {
|
||||
else
|
||||
vu_smart_log_show(&smart_log_payload, cfg.namespace_id,
|
||||
dev->name, uuid_index);
|
||||
}
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struc
|
|||
}
|
||||
|
||||
if (cfg.cfg_file) {
|
||||
char *conf_str = 0;
|
||||
char *conf_str = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
err = read_file2buffer(cfg.cfg_file, &conf_str, &length);
|
||||
|
@ -121,9 +121,10 @@ int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struc
|
|||
cfg.cfg_file, strerror(err));
|
||||
goto close_fd;
|
||||
}
|
||||
struct json_tokener * jstok = json_tokener_new();
|
||||
struct json_tokener *jstok = json_tokener_new();
|
||||
|
||||
tl.configuration = json_tokener_parse_ex(jstok, conf_str, length);
|
||||
free(conf_str);
|
||||
if (jstok->err != json_tokener_success) {
|
||||
SOLIDIGM_LOG_WARNING("Parsing error on JSON configuration file %s: %s (at offset %d)",
|
||||
cfg.cfg_file,
|
||||
|
@ -160,11 +161,7 @@ int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struc
|
|||
goto close_fd;
|
||||
}
|
||||
}
|
||||
solidigm_telemetry_log_header_parse(&tl);
|
||||
if (cfg.cfg_file)
|
||||
solidigm_telemetry_log_data_areas_parse(&tl, cfg.data_area);
|
||||
else
|
||||
solidigm_telemetry_log_cod_parse(&tl);
|
||||
solidigm_telemetry_log_data_areas_parse(&tl, cfg.data_area);
|
||||
|
||||
json_print_object(tl.root, NULL);
|
||||
json_free_object(tl.root);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
]
|
||||
|
|
130
plugins/solidigm/solidigm-telemetry/nlog.c
Normal file
130
plugins/solidigm/solidigm-telemetry/nlog.c
Normal 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;
|
||||
}
|
11
plugins/solidigm/solidigm-telemetry/nlog.h
Normal file
11
plugins/solidigm/solidigm-telemetry/nlog.h
Normal 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);
|
Loading…
Add table
Add a link
Reference in a new issue