summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plugins/fdp/fdp.c10
-rw-r--r--plugins/huawei/huawei-nvme.c2
-rw-r--r--plugins/innogrit/typedef.h6
-rw-r--r--plugins/memblaze/memblaze-nvme.c882
-rw-r--r--plugins/memblaze/memblaze-nvme.h42
-rw-r--r--plugins/meson.build3
-rw-r--r--plugins/micron/micron-nvme.c138
-rw-r--r--plugins/micron/micron-nvme.h9
-rw-r--r--plugins/nbft/nbft-plugin.c20
-rw-r--r--plugins/netapp/netapp-nvme.c43
-rw-r--r--plugins/ocp/meson.build1
-rw-r--r--plugins/ocp/ocp-clear-features.c2
-rw-r--r--plugins/ocp/ocp-fw-activation-history.c8
-rw-r--r--plugins/ocp/ocp-nvme.c3228
-rw-r--r--plugins/ocp/ocp-nvme.h12
-rw-r--r--plugins/ocp/ocp-smart-extended-log.c2
-rw-r--r--plugins/ocp/ocp-telemetry-decode.c1566
-rw-r--r--plugins/ocp/ocp-telemetry-decode.h1228
-rw-r--r--plugins/ocp/ocp-utils.c27
-rw-r--r--plugins/ocp/ocp-utils.h22
-rw-r--r--plugins/sed/sedopal_cmd.c59
-rw-r--r--plugins/solidigm/meson.build1
-rw-r--r--plugins/solidigm/solidigm-garbage-collection.c6
-rw-r--r--plugins/solidigm/solidigm-get-drive-info.c2
-rw-r--r--plugins/solidigm/solidigm-id-ctrl.c67
-rw-r--r--plugins/solidigm/solidigm-internal-logs.c671
-rw-r--r--plugins/solidigm/solidigm-latency-tracking.c6
-rw-r--r--plugins/solidigm/solidigm-log-page-dir.c76
-rw-r--r--plugins/solidigm/solidigm-market-log.c1
-rw-r--r--plugins/solidigm/solidigm-nvme.c7
-rw-r--r--plugins/solidigm/solidigm-nvme.h4
-rw-r--r--plugins/solidigm/solidigm-smart.c6
-rw-r--r--plugins/solidigm/solidigm-temp-stats.c34
-rw-r--r--plugins/solidigm/solidigm-util.c33
-rw-r--r--plugins/solidigm/solidigm-util.h5
-rw-r--r--plugins/solidigm/solidigm-workload-tracker.c536
-rw-r--r--plugins/solidigm/solidigm-workload-tracker.h8
-rw-r--r--plugins/ssstc/ssstc-nvme.c430
-rw-r--r--plugins/ssstc/ssstc-nvme.h16
-rw-r--r--plugins/virtium/virtium-nvme.c4
-rw-r--r--plugins/wdc/wdc-nvme.c1251
-rw-r--r--plugins/wdc/wdc-nvme.h2
-rw-r--r--plugins/wdc/wdc-utils.c2
-rw-r--r--plugins/zns/zns.c10
44 files changed, 8059 insertions, 2429 deletions
diff --git a/plugins/fdp/fdp.c b/plugins/fdp/fdp.c
index 2a221f8..1efdd76 100644
--- a/plugins/fdp/fdp.c
+++ b/plugins/fdp/fdp.c
@@ -25,7 +25,7 @@ static int fdp_configs(int argc, char **argv, struct command *cmd,
const char *human_readable = "show log in readable format";
const char *raw = "use binary output";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_dev *dev;
struct nvme_fdp_config_log hdr;
void *log = NULL;
@@ -107,7 +107,7 @@ static int fdp_usage(int argc, char **argv, struct command *cmd, struct plugin *
const char *egid = "Endurance group identifier";
const char *raw = "use binary output";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_dev *dev;
struct nvme_fdp_ruhu_log hdr;
size_t len;
@@ -180,7 +180,7 @@ static int fdp_stats(int argc, char **argv, struct command *cmd, struct plugin *
const char *egid = "Endurance group identifier";
const char *raw = "use binary output";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_dev *dev;
struct nvme_fdp_stats_log stats;
int err;
@@ -238,7 +238,7 @@ static int fdp_events(int argc, char **argv, struct command *cmd, struct plugin
const char *host_events = "Get host events";
const char *raw = "use binary output";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_dev *dev;
struct nvme_fdp_events_log events;
int err;
@@ -299,7 +299,7 @@ static int fdp_status(int argc, char **argv, struct command *cmd, struct plugin
const char *namespace_id = "Namespace identifier";
const char *raw = "use binary output";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_dev *dev;
struct nvme_fdp_ruh_status hdr;
size_t len;
diff --git a/plugins/huawei/huawei-nvme.c b/plugins/huawei/huawei-nvme.c
index 0272dea..c09d8d3 100644
--- a/plugins/huawei/huawei-nvme.c
+++ b/plugins/huawei/huawei-nvme.c
@@ -296,7 +296,7 @@ static int huawei_list(int argc, char **argv, struct command *command,
struct huawei_list_item *list_items;
unsigned int i, n, ret;
unsigned int huawei_num = 0;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
const char *desc = "Retrieve basic information for the given huawei device";
struct config {
char *output_format;
diff --git a/plugins/innogrit/typedef.h b/plugins/innogrit/typedef.h
index f2a59b4..7220d38 100644
--- a/plugins/innogrit/typedef.h
+++ b/plugins/innogrit/typedef.h
@@ -53,14 +53,14 @@ struct vsc_smart_log {
unsigned int low_pwr_cnt;
unsigned int wa;
unsigned int ps3_entry_cnt;
- u_char highest_temp[4];
+ unsigned char highest_temp[4];
unsigned int weight_ec;
unsigned int slc_cap_mb;
unsigned long long nand_page_write_cnt;
unsigned int program_error_cnt;
unsigned int erase_error_cnt;
- u_char flash_type;
- u_char reserved2[3];
+ unsigned char flash_type;
+ unsigned char reserved2[3];
unsigned int hs_crc_err_cnt;
unsigned int ddr_ecc_err_cnt;
unsigned int reserved3[44];
diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c
index b215125..c189f1b 100644
--- a/plugins/memblaze/memblaze-nvme.c
+++ b/plugins/memblaze/memblaze-nvme.c
@@ -65,7 +65,7 @@ static int compare_fw_version(const char *fw1, const char *fw2)
* 0: old memblaze format
* *******************************************************/
#define MEMBLAZE_FORMAT (0)
-#define INTEL_FORMAT (1)
+#define INTEL_FORMAT (1)
/* 2.13 = papaya */
#define IS_PAPAYA(str) (!strcmp(str, "2.13"))
@@ -107,14 +107,15 @@ static __u64 raw_2_u64(const __u8 *buf, size_t len)
return le64_to_cpu(val);
}
-static void get_memblaze_new_smart_info(struct nvme_p4_smart_log *smart, int index, __u8 *nm_val, __u8 *raw_val)
+static void get_memblaze_new_smart_info(struct nvme_p4_smart_log *smart, int index, __u8 *nm_val,
+ __u8 *raw_val)
{
memcpy(nm_val, smart->itemArr[index].nmVal, NM_SIZE);
memcpy(raw_val, smart->itemArr[index].rawVal, RAW_SIZE);
}
-static void show_memblaze_smart_log_new(struct nvme_memblaze_smart_log *s,
- unsigned int nsid, const char *devname)
+static void show_memblaze_smart_log_new(struct nvme_memblaze_smart_log *s, unsigned int nsid,
+ const char *devname)
{
struct nvme_p4_smart_log *smart = (struct nvme_p4_smart_log *)s;
__u8 *nm = malloc(NM_SIZE * sizeof(__u8));
@@ -130,7 +131,8 @@ static void show_memblaze_smart_log_new(struct nvme_memblaze_smart_log *s,
return;
}
- printf("%s:%s %s:%x\n", "Additional Smart Log for NVME device", devname, "namespace-id", nsid);
+ printf("%s:%s %s:%x\n", "Additional Smart Log for NVME device", devname, "namespace-id",
+ nsid);
printf("%-34s%-11s%s\n", "key", "normalized", "raw");
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PROGRAM_FAIL, nm, raw);
@@ -140,42 +142,51 @@ static void show_memblaze_smart_log_new(struct nvme_memblaze_smart_log *s,
printf("%-32s: %3d%% %"PRIu64"\n", "erase_fail_count", *nm, int48_to_long(raw));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_WEARLEVELING_COUNT, nm, raw);
- printf("%-31s : %3d%% %s%u%s%u%s%u\n", "wear_leveling", *nm,
- "min: ", *(__u16 *)raw, ", max: ", *(__u16 *)(raw+2), ", avg: ", *(__u16 *)(raw+4));
+ printf("%-31s : %3d%% %s%u%s%u%s%u\n", "wear_leveling", *nm, "min: ", *(__u16 *)raw,
+ ", max: ", *(__u16 *)(raw+2), ", avg: ", *(__u16 *)(raw+4));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_E2E_DECTECTION_COUNT, nm, raw);
- printf("%-31s: %3d%% %"PRIu64"\n", "end_to_end_error_detection_count", *nm, int48_to_long(raw));
+ printf("%-31s: %3d%% %"PRIu64"\n", "end_to_end_error_detection_count", *nm,
+ int48_to_long(raw));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PCIE_CRC_ERR_COUNT, nm, raw);
printf("%-32s: %3d%% %"PRIu64"\n", "crc_error_count", *nm, int48_to_long(raw));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR, nm, raw);
- printf("%-32s: %3d%% %.3f%%\n", "timed_workload_media_wear", *nm, ((float)int48_to_long(raw))/1000);
+ printf("%-32s: %3d%% %.3f%%\n", "timed_workload_media_wear", *nm,
+ ((float)int48_to_long(raw))/1000);
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ, nm, raw);
- printf("%-32s: %3d%% %"PRIu64"%%\n", "timed_workload_host_reads", *nm, int48_to_long(raw));
+ printf("%-32s: %3d%% %"PRIu64"%%\n", "timed_workload_host_reads", *nm,
+ int48_to_long(raw));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_TIMER, nm, raw);
- printf("%-32s: %3d%% %"PRIu64"%s\n", "timed_workload_timer", *nm, int48_to_long(raw), " min");
+ printf("%-32s: %3d%% %"PRIu64"%s\n", "timed_workload_timer", *nm,
+ int48_to_long(raw), " min");
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_THERMAL_THROTTLE_STATUS, nm, raw);
- printf("%-32s: %3d%% %u%%%s%"PRIu64"\n", "thermal_throttle_status", *nm,
- *raw, ", cnt: ", int48_to_long(raw+1));
+ printf("%-32s: %3d%% %u%%%s%"PRIu64"\n", "thermal_throttle_status", *nm, *raw,
+ ", cnt: ", int48_to_long(raw+1));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT, nm, raw);
- printf("%-32s: %3d%% %"PRIu64"\n", "retry_buffer_overflow_count", *nm, int48_to_long(raw));
+ printf("%-32s: %3d%% %"PRIu64"\n", "retry_buffer_overflow_count", *nm,
+ int48_to_long(raw));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT, nm, raw);
- printf("%-32s: %3d%% %"PRIu64"\n", "pll_lock_loss_count", *nm, int48_to_long(raw));
+ printf("%-32s: %3d%% %"PRIu64"\n", "pll_lock_loss_count", *nm,
+ int48_to_long(raw));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TOTAL_WRITE, nm, raw);
- printf("%-32s: %3d%% %s%"PRIu64"\n", "nand_bytes_written", *nm, "sectors: ", int48_to_long(raw));
+ printf("%-32s: %3d%% %s%"PRIu64"\n", "nand_bytes_written", *nm, "sectors: ",
+ int48_to_long(raw));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_HOST_WRITE, nm, raw);
- printf("%-32s: %3d%% %s%"PRIu64"\n", "host_bytes_written", *nm, "sectors: ", int48_to_long(raw));
+ printf("%-32s: %3d%% %s%"PRIu64"\n", "host_bytes_written", *nm, "sectors: ",
+ int48_to_long(raw));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT, nm, raw);
- printf("%-32s: %3d%% %"PRIu64"\n", "system_area_life_left", *nm, int48_to_long(raw));
+ printf("%-32s: %3d%% %"PRIu64"\n", "system_area_life_left", *nm,
+ int48_to_long(raw));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TOTAL_READ, nm, raw);
printf("%-32s: %3d%% %"PRIu64"\n", "total_read", *nm, int48_to_long(raw));
@@ -189,8 +200,8 @@ static void show_memblaze_smart_log_new(struct nvme_memblaze_smart_log *s,
"max: ", *(__u16 *)raw, ", min: ", *(__u16 *)(raw+2), ", curr: ", *(__u16 *)(raw+4));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TEMPT_SINCE_BOOTUP, nm, raw);
- printf("%-32s: %3d%% %s%u%s%u%s%u\n", "tempt_since_bootup", *nm, "max: ", *(__u16 *)raw,
- ", min: ", *(__u16 *)(raw+2), ", curr: ", *(__u16 *)(raw+4));
+ printf("%-32s: %3d%% %s%u%s%u%s%u\n", "tempt_since_bootup", *nm, "max: ",
+ *(__u16 *)raw, ", min: ", *(__u16 *)(raw+2), ", curr: ", *(__u16 *)(raw+4));
get_memblaze_new_smart_info(smart, RAISIN_SI_VD_READ_FAIL, nm, raw);
printf("%-32s: %3d%% %"PRIu64"\n", "read_fail_count", *nm, int48_to_long(raw));
@@ -319,23 +330,24 @@ static void show_memblaze_smart_log_old(struct nvme_memblaze_smart_log *smart,
}
get_memblaze_new_smart_info(s, PROGRAM_FAIL, nm, raw);
printf("%-32s : %3d%% %"PRIu64"\n",
- "program_fail_count", *nm, int48_to_long(raw));
+ "program_fail_count", *nm, int48_to_long(raw));
get_memblaze_new_smart_info(s, ERASE_FAIL, nm, raw);
printf("%-32s : %3d%% %"PRIu64"\n",
- "erase_fail_count", *nm, int48_to_long(raw));
+ "erase_fail_count", *nm, int48_to_long(raw));
get_memblaze_new_smart_info(s, WEARLEVELING_COUNT, nm, raw);
printf("%-31s : %3d%% %s%u%s%u%s%u\n",
- "wear_leveling", *nm, "min: ", *(__u16 *)raw, ", max: ", *(__u16 *)(raw+2), ", avg: ", *(__u16 *)(raw+4));
+ "wear_leveling", *nm, "min: ", *(__u16 *)raw, ", max: ", *(__u16 *)(raw+2),
+ ", avg: ", *(__u16 *)(raw+4));
get_memblaze_new_smart_info(s, TOTAL_WRITE, nm, raw);
printf("%-32s : %3d%% %"PRIu64"\n",
- "nand_bytes_written", *nm, 32*int48_to_long(raw));
+ "nand_bytes_written", *nm, 32*int48_to_long(raw));
get_memblaze_new_smart_info(s, HOST_WRITE, nm, raw);
printf("%-32s : %3d%% %"PRIu64"\n",
- "host_bytes_written", *nm, 32*int48_to_long(raw));
+ "host_bytes_written", *nm, 32*int48_to_long(raw));
free(nm);
free(raw);
@@ -402,14 +414,15 @@ int parse_params(char *str, int number, ...)
return 0;
}
-static int mb_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int mb_get_additional_smart_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
{
struct nvme_memblaze_smart_log smart_log;
char *desc =
- "Get Memblaze vendor specific additional smart log (optionally, for the specified namespace), and show it.";
+ "Get Memblaze vendor specific additional smart log, and show it.";
const char *namespace = "(optional) desired namespace";
const char *raw = "dump output in binary format";
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
struct config {
__u32 namespace_id;
bool raw_binary;
@@ -442,7 +455,6 @@ static int mb_get_additional_smart_log(int argc, char **argv, struct command *cm
if (err > 0)
nvme_show_status(err);
- dev_close(dev);
return err;
}
@@ -460,12 +472,13 @@ static char *mb_feature_to_string(int feature)
}
}
-static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
{
const char *desc = "Get Memblaze power management ststus\n (value 0 - 25w, 1 - 20w, 2 - 15w)";
__u32 result;
__u32 feature_id = MB_FEAT_POWER_MGMT;
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
int err;
OPT_ARGS(opts) = {
@@ -477,16 +490,16 @@ static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd
return err;
struct nvme_get_features_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
.fid = feature_id,
.nsid = 0,
.sel = 0,
.cdw11 = 0,
.uuidx = 0,
- .data_len = 0,
+ .data_len = 0,
.data = NULL,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = &result,
};
err = nvme_get_features(&args);
@@ -497,16 +510,16 @@ static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd
mb_feature_to_string(feature_id), nvme_select_to_string(0), result);
else if (err > 0)
nvme_show_status(err);
- dev_close(dev);
return err;
}
-static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
{
const char *desc = "Set Memblaze power management status\n (value 0 - 25w, 1 - 20w, 2 - 15w)";
const char *value = "new value of feature (required)";
const char *save = "specifies that the controller shall save the attribute";
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
__u32 result;
int err;
@@ -533,8 +546,8 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd
return err;
struct nvme_set_features_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
.fid = cfg.feature_id,
.nsid = 0,
.cdw11 = cfg.value,
@@ -542,9 +555,9 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd
.save = cfg.save,
.uuidx = 0,
.cdw15 = 0,
- .data_len = 0,
+ .data_len = 0,
.data = NULL,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = &result,
};
err = nvme_set_features(&args);
@@ -556,14 +569,14 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd
else if (err > 0)
nvme_show_status(err);
- dev_close(dev);
return err;
}
-#define P2MIN (1)
-#define P2MAX (5000)
-#define MB_FEAT_HIGH_LATENCY_VALUE_SHIFT (15)
-static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+#define P2MIN (1)
+#define P2MAX (5000)
+#define MB_FEAT_HIGH_LATENCY_VALUE_SHIFT (15)
+static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
{
const char *desc = "Set Memblaze high latency log\n"
" input parameter p1,p2\n"
@@ -571,7 +584,7 @@ static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, s
" p2 value: 1 .. 5000 ms";
const char *param = "input parameters";
int param1 = 0, param2 = 0;
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
__u32 result;
int err;
@@ -598,12 +611,10 @@ static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, s
if (parse_params(cfg.param, 2, &param1, &param2)) {
printf("setfeature: invalid formats %s\n", cfg.param);
- dev_close(dev);
return -EINVAL;
}
if ((param1 == 1) && (param2 < P2MIN || param2 > P2MAX)) {
printf("setfeature: invalid high io latency threshold %d\n", param2);
- dev_close(dev);
return -EINVAL;
}
cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2;
@@ -632,7 +643,6 @@ static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, s
else if (err > 0)
nvme_show_status(err);
- dev_close(dev);
return err;
}
@@ -672,7 +682,7 @@ static int find_deadbeef(char *buf)
return 0;
}
-#define TIME_STR_SIZE (44)
+#define TIME_STR_SIZE (44)
static int glp_high_latency(FILE *fdi, char *buf, int buflen, int print)
{
struct log_page_high_latency *logEntry;
@@ -723,11 +733,12 @@ static int glp_high_latency(FILE *fdi, char *buf, int buflen, int print)
return 1;
}
-static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
{
const char *desc = "Get Memblaze high latency log";
char buf[LOG_PAGE_SIZE];
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
FILE *fdi = NULL;
int err;
@@ -742,14 +753,13 @@ static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd,
fdi = fopen(FID_C3_LOG_FILENAME, "w+");
glp_high_latency_show_bar(fdi, DO_PRINT_FLAG);
- err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG,
- sizeof(buf), &buf);
+ err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG, sizeof(buf), &buf);
while (1) {
if (!glp_high_latency(fdi, buf, LOG_PAGE_SIZE, DO_PRINT_FLAG))
break;
- err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG,
- sizeof(buf), &buf);
+ err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG, sizeof(buf),
+ &buf);
if (err) {
nvme_show_status(err);
break;
@@ -758,7 +768,6 @@ static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd,
if (fdi)
fclose(fdi);
- dev_close(dev);
return err;
}
@@ -787,7 +796,7 @@ static int mb_selective_download(int argc, char **argv, struct command *cmd, str
int xfer = 4096;
void *fw_buf;
int selectNo, fw_fd, fw_size, err, offset = 0;
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
struct stat sb;
int i;
@@ -901,12 +910,11 @@ out_free:
out_close:
close(fw_fd);
out:
- dev_close(dev);
return err;
}
static void ioLatencyHistogramOutput(FILE *fd, int index, int start, int end, char *unit0,
- char *unit1, unsigned int *pHistogram, int print)
+ char *unit1, unsigned int *pHistogram, int print)
{
int len;
char string[64], subString0[12], subString1[12];
@@ -917,8 +925,7 @@ static void ioLatencyHistogramOutput(FILE *fd, int index, int start, int end, ch
else
snprintf(subString1, sizeof(subString1), "%s", "+INF");
len = snprintf(string, sizeof(string), "%-11d %-11s %-11s %-11u\n",
- index, subString0, subString1,
- pHistogram[index]);
+ index, subString0, subString1, pHistogram[index]);
fwrite(string, 1, len, fd);
if (print)
printf("%s", string);
@@ -960,7 +967,8 @@ int io_latency_histogram(char *file, char *buf, int print, int logid)
strcpy(unit[0], "ms");
strcpy(unit[1], "ms");
for (i = 1; i < 32; i++, index++)
- ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print);
+ ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1],
+ (unsigned int *)buf, print);
for (i = 1; i < 32; i++, index++) {
if (i == 31) {
@@ -976,9 +984,11 @@ int io_latency_histogram(char *file, char *buf, int print, int logid)
strcpy(unit[0], "s");
strcpy(unit[1], "s");
for (i = 1; i < 4; i++, index++)
- ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print);
+ ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1],
+ (unsigned int *)buf, print);
- ioLatencyHistogramOutput(fdi, index, i, 0x7FFFFFFF, unit[0], unit[1], (unsigned int *)buf, print);
+ ioLatencyHistogramOutput(fdi, index, i, 0x7FFFFFFF, unit[0], unit[1],
+ (unsigned int *)buf, print);
} else {
fPRINT_PARAM1("Unsupported io latency histogram revision\n");
}
@@ -993,7 +1003,7 @@ static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, st
char stats[LOG_PAGE_SIZE];
char f1[] = FID_C1_LOG_FILENAME;
char f2[] = FID_C2_LOG_FILENAME;
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
int err;
const char *desc = "Get Latency Statistics log and show it.";
@@ -1015,8 +1025,7 @@ static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, st
if (err)
return err;
- err = nvme_get_log_simple(dev_fd(dev), cfg.write ? 0xc2 : 0xc1,
- sizeof(stats), &stats);
+ err = nvme_get_log_simple(dev_fd(dev), cfg.write ? 0xc2 : 0xc1, sizeof(stats), &stats);
if (!err)
io_latency_histogram(cfg.write ? f2 : f1, stats, DO_PRINT_FLAG,
cfg.write ? GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM :
@@ -1024,14 +1033,14 @@ static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, st
else
nvme_show_status(err);
- dev_close(dev);
return err;
}
-static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
{
char *desc = "Clear Memblaze devices error log.";
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
int err;
__u32 result;
@@ -1043,9 +1052,9 @@ static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd,
};
struct config cfg = {
- .feature_id = 0xf7,
- .value = 0x534d0001,
- .save = 0,
+ .feature_id = 0xf7,
+ .value = 0x534d0001,
+ .save = 0,
};
OPT_ARGS(opts) = {
@@ -1075,16 +1084,15 @@ static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd,
if (err < 0)
perror("set-feature");
if (!err)
- printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, mb_feature_to_string(cfg.feature_id), cfg.value);
+ printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
+ mb_feature_to_string(cfg.feature_id), cfg.value);
else if (err > 0)
nvme_show_status(err);
- dev_close(dev);
return err;
}
-static int mb_set_lat_stats(int argc, char **argv,
- struct command *command, struct plugin *plugin)
+static int mb_set_lat_stats(int argc, char **argv, struct command *command, struct plugin *plugin)
{
const char *desc = (
"Enable/Disable Latency Statistics Tracking.\n"
@@ -1098,7 +1106,7 @@ static int mb_set_lat_stats(int argc, char **argv,
const __u32 cdw12 = 0x0;
const __u32 data_len = 32;
const __u32 save = 0;
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
void *buf = NULL;
__u32 result;
int err;
@@ -1168,12 +1176,10 @@ static int mb_set_lat_stats(int argc, char **argv,
case None:
err = nvme_get_features(&args_get);
if (!err) {
- printf(
- "Latency Statistics Tracking (FID 0x%X) is currently (%i).\n",
- fid, result);
+ printf("Latency Statistics Tracking (FID 0x%X) is currently (%i).\n", fid,
+ result);
} else {
printf("Could not read feature id 0xE2.\n");
- dev_close(dev);
return err;
}
break;
@@ -1186,15 +1192,13 @@ static int mb_set_lat_stats(int argc, char **argv,
perror("Enable latency tracking");
fprintf(stderr, "Command failed while parsing.\n");
} else {
- printf("Successfully set enable bit for FID (0x%X) to %i.\n",
- 0xe2, option);
+ printf("Successfully set enable bit for FID (0x%X) to %i.\n", 0xe2, option);
}
break;
default:
printf("%d not supported.\n", option);
err = EINVAL;
}
- dev_close(dev);
return err;
}
@@ -1238,17 +1242,17 @@ struct __packed smart_log_add_item_12 {
uint8_t rsvd1;
union {
struct wear_level wear_level; // 0xad
- struct temp_since_born { // 0xe7
+ struct __packed temp_since_born { // 0xe7
__le16 max;
__le16 min;
__le16 curr;
} temp_since_born;
- struct power_consumption { // 0xe8
+ struct __packed power_consumption { // 0xe8
__le16 max;
__le16 min;
__le16 curr;
} power_consumption;
- struct temp_since_power_on { // 0xaf
+ struct __packed temp_since_power_on { // 0xaf
__le16 max;
__le16 min;
__le16 curr;
@@ -1268,10 +1272,10 @@ struct __packed smart_log_add_item_10 {
uint8_t rsvd[2];
};
-struct smart_log_add {
+struct __packed smart_log_add {
union {
union {
- struct smart_log_add_v0 {
+ struct __packed smart_log_add_v0 {
struct smart_log_add_item_12 program_fail_count;
struct smart_log_add_item_12 erase_fail_count;
struct smart_log_add_item_12 wear_leveling_count;
@@ -1300,7 +1304,7 @@ struct smart_log_add {
};
union {
- struct smart_log_add_v2 {
+ struct __packed smart_log_add_v2 {
struct smart_log_add_item_12 program_fail_count;
struct smart_log_add_item_12 erase_fail_count;
struct smart_log_add_item_12 wear_leveling_count;
@@ -1322,7 +1326,7 @@ struct smart_log_add {
struct smart_log_add_item_12 xor_fail_count;
struct smart_log_add_item_12 xor_invoked_count;
struct smart_log_add_item_12 inflight_read_io_cmd;
- struct smart_log_add_item_12 flash_error_media_count;
+ struct smart_log_add_item_12 inflight_write_io_cmd;
struct smart_log_add_item_12 nand_bytes_read;
struct smart_log_add_item_12 temp_since_born;
struct smart_log_add_item_12 power_consumption;
@@ -1334,7 +1338,7 @@ struct smart_log_add {
};
union {
- struct smart_log_add_v3 {
+ struct __packed smart_log_add_v3 {
struct smart_log_add_item_10 program_fail_count;
struct smart_log_add_item_10 erase_fail_count;
struct smart_log_add_item_10 wear_leveling_count;
@@ -1401,33 +1405,33 @@ static void smart_log_add_v0_print(struct smart_log_add_item_12 *item, int item_
switch (item->id) {
case 0xad:
printf("min: %d, max: %d, avg: %d\n",
- le16_to_cpu(item->wear_level.min),
- le16_to_cpu(item->wear_level.max),
- le16_to_cpu(item->wear_level.avg));
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
break;
case 0xe7:
printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
- K2C(le16_to_cpu(item->temp_since_born.max)),
- le16_to_cpu(item->temp_since_born.max),
- K2C(le16_to_cpu(item->temp_since_born.min)),
- le16_to_cpu(item->temp_since_born.min),
- K2C(le16_to_cpu(item->temp_since_born.curr)),
- le16_to_cpu(item->temp_since_born.curr));
+ K2C(le16_to_cpu(item->temp_since_born.max)),
+ le16_to_cpu(item->temp_since_born.max),
+ K2C(le16_to_cpu(item->temp_since_born.min)),
+ le16_to_cpu(item->temp_since_born.min),
+ K2C(le16_to_cpu(item->temp_since_born.curr)),
+ le16_to_cpu(item->temp_since_born.curr));
break;
case 0xe8:
printf("max: %d, min: %d, curr: %d\n",
- le16_to_cpu(item->power_consumption.max),
- le16_to_cpu(item->power_consumption.min),
- le16_to_cpu(item->power_consumption.curr));
+ le16_to_cpu(item->power_consumption.max),
+ le16_to_cpu(item->power_consumption.min),
+ le16_to_cpu(item->power_consumption.curr));
break;
case 0xaf:
printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
- K2C(le16_to_cpu(item->temp_since_power_on.max)),
- le16_to_cpu(item->temp_since_power_on.max),
- K2C(le16_to_cpu(item->temp_since_power_on.min)),
- le16_to_cpu(item->temp_since_power_on.min),
- K2C(le16_to_cpu(item->temp_since_power_on.curr)),
- le16_to_cpu(item->temp_since_power_on.curr));
+ K2C(le16_to_cpu(item->temp_since_power_on.max)),
+ le16_to_cpu(item->temp_since_power_on.max),
+ K2C(le16_to_cpu(item->temp_since_power_on.min)),
+ le16_to_cpu(item->temp_since_power_on.min),
+ K2C(le16_to_cpu(item->temp_since_power_on.curr)),
+ le16_to_cpu(item->temp_since_power_on.curr));
break;
default:
printf("%" PRIu64 "\n", int48_to_long(item->raw));
@@ -1460,7 +1464,7 @@ static void smart_log_add_v2_print(struct smart_log_add_item_12 *item, int item_
[0xfd] = {18, "xor_fail_count" },
[0xfe] = {19, "xor_invoked_count" },
[0xe5] = {20, "inflight_read_io_cmd" },
- [0xe6] = {21, "flash_error_media_count" },
+ [0xe6] = {21, "inflight_write_io_cmd" },
[0xf8] = {22, "nand_bytes_read" },
[0xe7] = {23, "temp_since_born" },
[0xe8] = {24, "power_consumption" },
@@ -1476,33 +1480,33 @@ static void smart_log_add_v2_print(struct smart_log_add_item_12 *item, int item_
switch (item->id) {
case 0xad:
printf("min: %d, max: %d, avg: %d\n",
- le16_to_cpu(item->wear_level.min),
- le16_to_cpu(item->wear_level.max),
- le16_to_cpu(item->wear_level.avg));
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
break;
case 0xe7:
printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
- K2C(le16_to_cpu(item->temp_since_born.max)),
- le16_to_cpu(item->temp_since_born.max),
- K2C(le16_to_cpu(item->temp_since_born.min)),
- le16_to_cpu(item->temp_since_born.min),
- K2C(le16_to_cpu(item->temp_since_born.curr)),
- le16_to_cpu(item->temp_since_born.curr));
+ K2C(le16_to_cpu(item->temp_since_born.max)),
+ le16_to_cpu(item->temp_since_born.max),
+ K2C(le16_to_cpu(item->temp_since_born.min)),
+ le16_to_cpu(item->temp_since_born.min),
+ K2C(le16_to_cpu(item->temp_since_born.curr)),
+ le16_to_cpu(item->temp_since_born.curr));
break;
case 0xe8:
printf("max: %d, min: %d, curr: %d\n",
- le16_to_cpu(item->power_consumption.max),
- le16_to_cpu(item->power_consumption.min),
- le16_to_cpu(item->power_consumption.curr));
+ le16_to_cpu(item->power_consumption.max),
+ le16_to_cpu(item->power_consumption.min),
+ le16_to_cpu(item->power_consumption.curr));
break;
case 0xaf:
printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
- K2C(le16_to_cpu(item->temp_since_power_on.max)),
- le16_to_cpu(item->temp_since_power_on.max),
- K2C(le16_to_cpu(item->temp_since_power_on.min)),
- le16_to_cpu(item->temp_since_power_on.min),
- K2C(le16_to_cpu(item->temp_since_power_on.curr)),
- le16_to_cpu(item->temp_since_power_on.curr));
+ K2C(le16_to_cpu(item->temp_since_power_on.max)),
+ le16_to_cpu(item->temp_since_power_on.max),
+ K2C(le16_to_cpu(item->temp_since_power_on.min)),
+ le16_to_cpu(item->temp_since_power_on.min),
+ K2C(le16_to_cpu(item->temp_since_power_on.curr)),
+ le16_to_cpu(item->temp_since_power_on.curr));
break;
default:
printf("%" PRIu64 "\n", int48_to_long(item->raw));
@@ -1546,9 +1550,9 @@ static void smart_log_add_v3_print(struct smart_log_add_item_10 *item, int item_
switch (item->id) {
case 0xad:
printf("min: %d, max: %d, avg: %d\n",
- le16_to_cpu(item->wear_level.min),
- le16_to_cpu(item->wear_level.max),
- le16_to_cpu(item->wear_level.avg));
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
break;
default:
printf("%" PRIu64 "\n", int48_to_long(item->raw));
@@ -1571,13 +1575,13 @@ static void smart_log_add_print(struct smart_log_add *log, const char *devname)
switch (version) {
case 0:
return smart_log_add_v0_print(&log->v0_raw[0],
- sizeof(struct smart_log_add_v0) / sizeof(struct smart_log_add_item_12));
+ sizeof(struct smart_log_add_v0) / sizeof(struct smart_log_add_item_12));
case 2:
return smart_log_add_v2_print(&log->v2_raw[0],
- sizeof(struct smart_log_add_v2) / sizeof(struct smart_log_add_item_12));
+ sizeof(struct smart_log_add_v2) / sizeof(struct smart_log_add_item_12));
case 3:
return smart_log_add_v3_print(&log->v3_raw[0],
- sizeof(struct smart_log_add_v3) / sizeof(struct smart_log_add_item_10));
+ sizeof(struct smart_log_add_v3) / sizeof(struct smart_log_add_item_10));
case 1:
fprintf(stderr, "Version %d: N/A\n", version);
@@ -1604,9 +1608,7 @@ static int mb_get_smart_log_add(int argc, char **argv, struct command *cmd, stru
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, "dump the whole log buffer in binary format"),
OPT_END()};
- // Open device
-
- struct nvme_dev *dev = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
err = parse_and_open(&dev, argc, argv, cmd->help, opts);
if (err)
@@ -1616,7 +1618,8 @@ static int mb_get_smart_log_add(int argc, char **argv, struct command *cmd, stru
struct smart_log_add log = {0};
- err = nvme_get_log_simple(dev_fd(dev), LID_SMART_LOG_ADD, sizeof(struct smart_log_add), &log);
+ err = nvme_get_log_simple(dev_fd(dev), LID_SMART_LOG_ADD, sizeof(struct smart_log_add),
+ &log);
if (!err) {
if (!cfg.raw_binary)
smart_log_add_print(&log, dev->name);
@@ -1628,9 +1631,6 @@ static int mb_get_smart_log_add(int argc, char **argv, struct command *cmd, stru
nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
}
- // Close device
-
- dev_close(dev);
return err;
}
@@ -1643,7 +1643,7 @@ struct latency_stats_bucket {
struct __packed latency_stats {
union {
- struct latency_stats_v2_0 {
+ struct __packed latency_stats_v2_0 {
uint32_t minor_version;
uint32_t major_version;
uint32_t bucket_read_data[32];
@@ -1660,9 +1660,9 @@ struct __packed latency_stats {
struct __packed high_latency_log {
union {
- struct high_latency_log_v1 {
+ struct __packed high_latency_log_v1 {
uint32_t version;
- struct high_latency_log_entry {
+ struct __packed high_latency_log_entry {
uint64_t timestamp; // ms
uint32_t latency;
uint32_t qid;
@@ -1688,12 +1688,12 @@ struct __packed high_latency_log {
struct __packed performance_stats {
union {
- struct performance_stats_v1 {
+ struct __packed performance_stats_v1 {
uint8_t version;
uint8_t rsvd[3];
- struct performance_stats_timestamp {
+ struct __packed performance_stats_timestamp {
uint8_t timestamp[6];
- struct performance_stats_entry {
+ struct __packed performance_stats_entry {
uint16_t read_iops; // K IOPS
uint16_t read_bandwidth; // MiB
uint32_t read_latency; // us
@@ -1705,12 +1705,36 @@ struct __packed performance_stats {
} entries[3600];
} timestamps[24];
} v1;
+ struct __packed performance_stats_v2 {
+ uint8_t version;
+ uint8_t rsvd[3];
+ struct __packed performance_stats_timestamp_v2 {
+ uint8_t timestamp[6];
+ struct __packed performance_stats_entry_v2 {
+ uint16_t read_iops;
+ uint16_t read_bandwidth;
+ uint16_t read_latency_avg;
+ uint16_t read_latency_max;
+ uint8_t scale_of_read_iops;
+ uint8_t scale_of_read_bandwidth;
+ uint8_t scale_of_read_latency_avg;
+ uint8_t scale_of_read_latency_max;
+ uint16_t write_iops;
+ uint16_t write_bandwidth;
+ uint16_t write_latency_avg;
+ uint16_t write_latency_max;
+ uint8_t scale_of_write_iops;
+ uint8_t scale_of_write_bandwidth;
+ uint8_t scale_of_write_latency_avg;
+ uint8_t scale_of_write_latency_max;
+ } entries[3600];
+ } timestamps[24];
+ } v2;
uint8_t raw[4 + 24 * (6 + 3600 * 24)];
};
};
-static int mb_set_latency_feature(int argc, char **argv, struct command *cmd,
- struct plugin *plugin)
+static int mb_set_latency_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
int err = 0;
@@ -1728,26 +1752,24 @@ static int mb_set_latency_feature(int argc, char **argv, struct command *cmd,
OPT_ARGS(opts) = {
OPT_UINT("sel-perf-log", 's', &cfg.perf_monitor,
- "Select features to turn on, default: Disable\n"
- " bit 0: latency statistics\n"
- " bit 1: high latency log\n"
- " bit 2: Performance stat"),
+ "Select features to turn on, default: Disable\n"
+ " bit 0: latency statistics\n"
+ " bit 1: high latency log\n"
+ " bit 2: Performance stat"),
OPT_UINT("set-commands-mask", 'm', &cfg.cmd_mask,
- "Set Enable, default: Disable\n"
- " bit 0: Read commands\n"
- " bit 1: high Write commands\n"
- " bit 2: De-allocate/TRIM (this bit is not worked for Performance stat.)"),
+ "Set Enable, default: Disable\n"
+ " bit 0: Read commands\n"
+ " bit 1: high Write commands\n"
+ " bit 2: De-allocate/TRIM (this bit is not worked for Performance stat.)"),
OPT_UINT("set-read-threshold", 'r', &cfg.read_threshold,
- "set read high latency log threshold, it's a 0-based value and unit is 10ms"),
+ "set read high latency log threshold, it's a 0-based value and unit is 10ms"),
OPT_UINT("set-write-threshold", 'w', &cfg.write_threshold,
- "set write high latency log threshold, it's a 0-based value and unit is 10ms"),
+ "set write high latency log threshold, it's a 0-based value and unit is 10ms"),
OPT_UINT("set-trim-threshold", 't', &cfg.de_allocate_trim_threshold,
- "set trim high latency log threshold, it's a 0-based value and unit is 10ms"),
+ "set trim high latency log threshold, it's a 0-based value and unit is 10ms"),
OPT_END()};
- // Open device
-
- struct nvme_dev *dev = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
err = parse_and_open(&dev, argc, argv, cmd->help, opts);
if (err)
@@ -1766,9 +1788,9 @@ static int mb_set_latency_feature(int argc, char **argv, struct command *cmd,
.cdw11 = 0 | cfg.perf_monitor,
.cdw12 = 0 | cfg.cmd_mask,
.cdw13 = 0 |
- (cfg.read_threshold & 0xff) |
- ((cfg.write_threshold & 0xff) << 8) |
- ((cfg.de_allocate_trim_threshold & 0xff) << 16),
+ (cfg.read_threshold & 0xff) |
+ ((cfg.write_threshold & 0xff) << 8) |
+ ((cfg.de_allocate_trim_threshold & 0xff) << 16),
.cdw15 = 0,
.save = 0,
.uuidx = 0,
@@ -1786,14 +1808,10 @@ static int mb_set_latency_feature(int argc, char **argv, struct command *cmd,
else
nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
- // Close device
-
- dev_close(dev);
return err;
}
-static int mb_get_latency_feature(int argc, char **argv, struct command *cmd,
- struct plugin *plugin)
+static int mb_get_latency_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
int err = 0;
@@ -1802,9 +1820,7 @@ static int mb_get_latency_feature(int argc, char **argv, struct command *cmd,
OPT_ARGS(opts) = {
OPT_END()};
- // Open device
-
- struct nvme_dev *dev = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
err = parse_and_open(&dev, argc, argv, cmd->help, opts);
if (err)
@@ -1835,8 +1851,512 @@ static int mb_get_latency_feature(int argc, char **argv, struct command *cmd,
nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
}
- // Close device
+ return err;
+}
+
+static void latency_stats_v2_0_print(struct latency_stats *log, int size)
+{
+ static const struct latency_stats_bucket buckets[0xff] = {
+ [1] = {"0us", "50us" },
+ [2] = {"50us", "100us"},
+ [3] = {"100us", "150us"},
+ [4] = {"150us", "200us"},
+ [5] = {"200us", "300us"},
+ [6] = {"300us", "400us"},
+ [7] = {"400us", "500us"},
+ [8] = {"500us", "600us"},
+ [9] = {"600us", "700us"},
+ [10] = {"700us", "800us"},
+ [11] = {"800us", "900us"},
+ [12] = {"900us", "1ms" },
+ [13] = {"1ms", "5ms" },
+ [14] = {"5ms", "10ms" },
+ [15] = {"10ms", "20ms" },
+ [16] = {"20ms", "50ms" },
+ [17] = {"50ms", "100ms"},
+ [18] = {"100ms", "200ms"},
+ [19] = {"200ms", "300ms"},
+ [20] = {"300ms", "400ms"},
+ [21] = {"400ms", "500ms"},
+ [22] = {"500ms", "600ms"},
+ [23] = {"600ms", "700ms"},
+ [24] = {"700ms", "800ms"},
+ [25] = {"800ms", "900ms"},
+ [26] = {"900ms", "1s" },
+ [27] = {"1s", "2s" },
+ [28] = {"2s", "3s" },
+ [29] = {"3s", "4s" },
+ [30] = {"4s", "5s" },
+ [31] = {"5s", "8s" },
+ [32] = {"8s", "INF" },
+ };
+
+ printf("Bucket 1-32 IO Read Command Data\n");
+ printf("-------------------------------------------\n");
+ printf("%-12s%-12s%-12s%-12s\n", "Bucket", "Start(>=)", "End(<)", "Value");
+ int bucket_count = sizeof(log->v2_0.bucket_read_data) / sizeof(uint32_t);
+
+ for (int i = 0; i < bucket_count; i++) {
+ printf("%-12u%-12s%-12s%-12u\n", i + 1, buckets[i + 1].start_threshold,
+ buckets[i + 1].end_threshold, log->v2_0.bucket_read_data[i]);
+ }
+ printf("\n");
+
+ printf("Bucket 1-32 IO Write Command Data\n");
+ printf("-------------------------------------------\n");
+ printf("%-12s%-12s%-12s%-12s\n", "Bucket", "Start(>=)", "End(<)", "Value");
+ bucket_count = sizeof(log->v2_0.bucket_write_data) / sizeof(uint32_t);
+
+ for (int i = 0; i < bucket_count; i++) {
+ printf("%-12u%-12s%-12s%-12u\n", i + 1, buckets[i + 1].start_threshold,
+ buckets[i + 1].end_threshold, log->v2_0.bucket_write_data[i]);
+ }
+ printf("\n");
+
+ printf("Bucket 1-32 IO Trim Command Data\n");
+ printf("-------------------------------------------\n");
+ printf("%-12s%-12s%-12s%-12s\n", "Bucket", "Start(>=)", "End(<)", "Value");
+ bucket_count = sizeof(log->v2_0.bucket_trim_data) / sizeof(uint32_t);
+
+ for (int i = 0; i < bucket_count; i++) {
+ printf("%-12u%-12s%-12s%-12u\n", i + 1, buckets[i + 1].start_threshold,
+ buckets[i + 1].end_threshold, log->v2_0.bucket_trim_data[i]);
+ }
+ printf("\n");
+}
+
+static void latency_stats_print(struct latency_stats *log, const char *devname)
+{
+ uint32_t minor_version = *(uint32_t *)&log->raw[0];
+ uint32_t major_version = *(uint32_t *)&log->raw[4];
+
+ printf("Major Version: %u, Minor Version: %u\n", major_version, minor_version);
+ printf("\n");
+ printf("Latency Statistics Log for NVMe device: %s\n", devname);
+ printf("\n");
+
+ switch (major_version) {
+ case 2:
+ switch (minor_version) {
+ case 0:
+ latency_stats_v2_0_print(log, sizeof(struct latency_stats));
+ break;
+ default:
+ fprintf(stderr, "Major Version %u, Minor Version %u: Not supported yet\n",
+ major_version, minor_version);
+ break;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Major Version %u: Not supported yet\n", major_version);
+ break;
+ }
+}
+
+static int mb_get_latency_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ // Get the configuration
+
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {0};
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary",
+ 'b',
+ &cfg.raw_binary,
+ "dump the whole log buffer in binary format"),
+ OPT_END()};
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+
+ int err = parse_and_open(&dev, argc, argv, cmd->help, opts);
+
+ if (err)
+ return err;
+
+ // Get log
+
+ struct latency_stats log = {0};
+
+ err = nvme_get_log_simple(dev_fd(dev), LID_LATENCY_STATISTICS, sizeof(struct latency_stats),
+ &log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ latency_stats_print(&log, dev->name);
+ else
+ d_raw((unsigned char *)&log, sizeof(struct latency_stats));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
+ }
+
+ return err;
+}
+
+static void high_latency_log_v1_print(struct high_latency_log *log, int size)
+{
+ printf("%-24s%-12s%-12s%-6s%-6s%-6s%-6s%-12s%-24s%-6s%-6s%-6s%-6s%-6s\n",
+ "Timestamp", "Latency(us)", "QID", "OpC", "Fuse", "PSDT", "CID", "NSID", "SLBA",
+ "NLB", "DType", "PInfo", "FUA", "LR");
+
+ for (int i = 0; i < 1024; i++) {
+ if (log->v1.entries[i].timestamp == 0)
+ break;
+
+ // Get the timestamp
+
+ time_t timestamp_ms = log->v1.entries[i].timestamp;
+ time_t timestamp_s = timestamp_ms / 1000;
+ int time_ms = timestamp_ms % 1000;
+ char str_time_s[20] = {0};
+ char str_time_ms[32] = {0};
+
+ strftime(str_time_s, sizeof(str_time_s), "%Y-%m-%d %H:%M:%S",
+ localtime(&timestamp_s));
+ snprintf(str_time_ms, sizeof(str_time_ms), "%s.%03d", str_time_s, time_ms);
+ printf("%-24s", str_time_ms);
+
+ //
+ printf("%-12" PRIu32, log->v1.entries[i].latency);
+ printf("%-12" PRIu32, log->v1.entries[i].qid);
+ printf("%#-6" PRIx32, log->v1.entries[i].opcode);
+ printf("%-6" PRIu32, log->v1.entries[i].fuse);
+ printf("%-6" PRIu32, log->v1.entries[i].psdt);
+ printf("%-6" PRIu32, log->v1.entries[i].cid);
+ printf("%-12" PRIu32, log->v1.entries[i].nsid);
+ printf("%-24" PRIu64, log->v1.entries[i].slba);
+ printf("%-6" PRIu32, log->v1.entries[i].nlb);
+ printf("%-6" PRIu32, log->v1.entries[i].dtype);
+ printf("%-6" PRIu32, log->v1.entries[i].pinfo);
+ printf("%-6" PRIu32, log->v1.entries[i].fua);
+ printf("%-6" PRIu32, log->v1.entries[i].lr);
+ printf("\n");
+ }
+}
+
+static void high_latency_log_print(struct high_latency_log *log, const char *devname)
+{
+ uint32_t version = *(uint32_t *)&log->raw[0];
+
+ printf("Version: %u\n", version);
+ printf("\n");
+ printf("High Latency Log for NVMe device: %s\n", devname);
+ printf("\n");
+
+ switch (version) {
+ case 1:
+ high_latency_log_v1_print(log, sizeof(struct high_latency_log));
+ break;
+
+ default:
+ fprintf(stderr, "Version %u: Not supported yet\n", version);
+ break;
+ }
+}
+
+static int mb_get_high_latency_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ // Get the configuration
+
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {0};
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary",
+ 'b',
+ &cfg.raw_binary,
+ "dump the whole log buffer in binary format"),
+ OPT_END()};
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+
+ int err = parse_and_open(&dev, argc, argv, cmd->help, opts);
+
+ if (err)
+ return err;
+
+ // Get log
+
+ struct high_latency_log log = {0};
+
+ err = nvme_get_log_simple(dev_fd(dev), LID_HIGH_LATENCY_LOG,
+ sizeof(struct high_latency_log), &log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ high_latency_log_print(&log, dev->name);
+ else
+ d_raw((unsigned char *)&log, sizeof(struct high_latency_log));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
+ }
+
+ return err;
+}
+
+static void performance_stats_v1_print(struct performance_stats *log, int duration)
+{
+ for (int i = 0; i < duration; i++) {
+ // Print timestamp
+
+ time_t timestamp_ms = int48_to_long(log->v1.timestamps[i].timestamp);
+ time_t timestamp_s = timestamp_ms / 1000;
+ int time_ms = timestamp_ms % 1000;
+ char time_s[32] = {0};
+
+ strftime(time_s, sizeof(time_s), "%Y-%m-%d %H:%M:%S", localtime(&timestamp_s));
+ printf("Timestamp %2d: %s.%03d\n", i + 1, time_s, time_ms);
+
+ // Print entry title
+
+ printf("%-8s%-14s%-21s%-22s%-22s%-15s%-22s%-23s%-23s\n", "Entry", "Read-IOs(K)",
+ "Read-Bandwidth(MiB)", "Avg-Read-Latency(us)", "Max-Read-Latency(us)",
+ "Write-IOs(K)", "Write-Bandwidth(MiB)", "Avg-Write-Latency(us)",
+ "Max-Write-Latency(us)");
+
+ // Print all entries content
+
+ struct performance_stats_entry entry = {0};
+
+ for (int j = 0; j < 3600; j++) {
+ entry.read_iops =
+ log->v1.timestamps[i].entries[j].read_iops;
+ entry.read_bandwidth =
+ log->v1.timestamps[i].entries[j].read_bandwidth;
+ entry.read_latency =
+ log->v1.timestamps[i].entries[j].read_latency;
+ entry.read_latency_max =
+ log->v1.timestamps[i].entries[j].read_latency_max;
+ entry.write_iops =
+ log->v1.timestamps[i].entries[j].write_iops;
+ entry.write_bandwidth =
+ log->v1.timestamps[i].entries[j].write_bandwidth;
+ entry.write_latency =
+ log->v1.timestamps[i].entries[j].write_latency;
+ entry.write_latency_max =
+ log->v1.timestamps[i].entries[j].write_latency_max;
+
+ if (entry.read_iops == 0 && entry.write_iops == 0)
+ continue;
+
+ printf("%-8u%-14u%-21u%-22u%-22u%-15u%-22u%-23u%-23u\n",
+ j + 1,
+ entry.read_iops,
+ entry.read_bandwidth,
+ entry.read_iops == 0 ?
+ 0 : entry.read_latency / (1000 * entry.read_iops),
+ entry.read_latency_max,
+ entry.write_iops,
+ entry.write_bandwidth,
+ entry.write_iops == 0 ?
+ 0 : entry.write_latency / (1000 * entry.write_iops),
+ entry.write_latency_max);
+ usleep(100);
+ }
+ printf("\n");
+ }
+}
+
+static void performance_stats_v2_print(struct performance_stats *log, int duration)
+{
+ for (int i = 0; i < duration; i++) {
+ // Print timestamp
+
+ time_t timestamp_ms = int48_to_long(log->v2.timestamps[i].timestamp);
+ time_t timestamp_s = timestamp_ms / 1000;
+ int time_ms = timestamp_ms % 1000;
+ char time_s[32] = {0};
+
+ strftime(time_s, sizeof(time_s), "%Y-%m-%d %H:%M:%S", localtime(&timestamp_s));
+ printf("Timestamp %2d: %s.%03d\n", i + 1, time_s, time_ms);
+
+ // Print entry title
+
+ printf("%-8s%-23s%-23s%-23s%-23s%-23s%-23s%-23s%-23s\n",
+ "Entry",
+ "Read-IOs(IOPS)", "Read-Bandwidth(KiB)",
+ "Avg-Read-Latency(us)", "Max-Read-Latency(us)",
+ "Write-IOs(IOPS)", "Write-Bandwidth(KiB)",
+ "Avg-Write-Latency(us)", "Max-Write-Latency(us)");
+
+ // Print all entries content
+ for (int j = 0; j < 3600; j++) {
+ uint32_t read_iops =
+ log->v2.timestamps[i].entries[j].read_iops;
+ uint32_t read_bandwidth =
+ log->v2.timestamps[i].entries[j].read_bandwidth;
+ uint32_t read_latency_avg =
+ log->v2.timestamps[i].entries[j].read_latency_avg;
+ uint32_t read_latency_max =
+ log->v2.timestamps[i].entries[j].read_latency_max;
+ uint32_t scale_of_read_iops =
+ log->v2.timestamps[i].entries[j].scale_of_read_iops;
+ uint32_t scale_of_read_bandwidth =
+ log->v2.timestamps[i].entries[j].scale_of_read_bandwidth;
+ uint32_t scale_of_read_latency_avg =
+ log->v2.timestamps[i].entries[j].scale_of_read_latency_avg;
+ uint32_t scale_of_read_latency_max =
+ log->v2.timestamps[i].entries[j].scale_of_read_latency_max;
+
+ uint32_t write_iops =
+ log->v2.timestamps[i].entries[j].write_iops;
+ uint32_t write_bandwidth =
+ log->v2.timestamps[i].entries[j].write_bandwidth;
+ uint32_t write_latency_avg =
+ log->v2.timestamps[i].entries[j].write_latency_avg;
+ uint32_t write_latency_max =
+ log->v2.timestamps[i].entries[j].write_latency_max;
+ uint32_t scale_of_write_iops =
+ log->v2.timestamps[i].entries[j].scale_of_write_iops;
+ uint32_t scale_of_write_bandwidth =
+ log->v2.timestamps[i].entries[j].scale_of_write_bandwidth;
+ uint32_t scale_of_write_latency_avg =
+ log->v2.timestamps[i].entries[j].scale_of_write_latency_avg;
+ uint32_t scale_of_write_latency_max =
+ log->v2.timestamps[i].entries[j].scale_of_write_latency_max;
+
+ if (read_iops == 0 && write_iops == 0)
+ continue;
+
+ while (scale_of_read_iops < 4 && scale_of_read_iops) {
+ read_iops *= 10;
+ scale_of_read_iops--;
+ }
+ while (scale_of_read_bandwidth < 3 && scale_of_read_bandwidth) {
+ read_bandwidth *= 1024;
+ scale_of_read_bandwidth--;
+ }
+ while (scale_of_read_latency_avg < 3 && scale_of_read_latency_avg) {
+ read_latency_avg *= 1000;
+ scale_of_read_latency_avg--;
+ }
+ while (scale_of_read_latency_max < 3 && scale_of_read_latency_max) {
+ read_latency_max *= 1000;
+ scale_of_read_latency_max--;
+ }
+
+ while (scale_of_write_iops < 4 && scale_of_write_iops) {
+ write_iops *= 10;
+ scale_of_write_iops--;
+ }
+ while (scale_of_write_bandwidth < 3 && scale_of_write_bandwidth) {
+ write_bandwidth *= 1024;
+ scale_of_write_bandwidth--;
+ }
+ while (scale_of_write_latency_avg < 3 && scale_of_write_latency_avg) {
+ write_latency_avg *= 1000;
+ scale_of_write_latency_avg--;
+ }
+ while (scale_of_write_latency_max < 3 && scale_of_write_latency_max) {
+ write_latency_max *= 1000;
+ scale_of_write_latency_max--;
+ }
+
+ printf("%-8u%-23u%-23u%-23u%-23u%-23u%-23u%-23u%-23u\n",
+ j + 1,
+ read_iops,
+ read_bandwidth,
+ read_latency_avg,
+ read_latency_max,
+ write_iops,
+ write_bandwidth,
+ write_latency_avg,
+ write_latency_max);
+ usleep(100);
+ }
+ printf("\n");
+ }
+}
+
+static void performance_stats_print(struct performance_stats *log, const char *devname,
+ int duration)
+{
+ uint8_t version = *(uint8_t *)&log->raw[0];
+
+ printf("Version: %u\n", version);
+ printf("\n");
+ printf("Performance Stat log for NVMe device: %s\n", devname);
+ printf("\n");
+
+ switch (version) {
+ case 1:
+ performance_stats_v1_print(log, duration);
+ break;
+ case 2:
+ performance_stats_v2_print(log, duration);
+ break;
+ default:
+ fprintf(stderr, "Version %u: Not supported yet\n", version);
+ break;
+ }
+}
+
+static int mb_get_performance_stats(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ // Get the configuration
+
+ struct config {
+ int duration;
+ bool raw_binary;
+ };
+
+ struct config cfg = {.duration = 1, .raw_binary = false};
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("duration",
+ 'd',
+ &cfg.duration,
+ "[1-24] hours: duration of the log to be printed, default is 1 hour"),
+ OPT_FLAG("raw-binary",
+ 'b',
+ &cfg.raw_binary,
+ "dump the whole log buffer in binary format"),
+ OPT_END()};
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+
+ int err = parse_and_open(&dev, argc, argv, cmd->help, opts);
+
+ if (err)
+ return err;
+
+ // Check parameters
+ if (cfg.duration < 1 || cfg.duration > 24) {
+ fprintf(stderr, "duration must be between 1 and 24.\n");
+ exit(1);
+ }
+
+ // Get log
+
+ struct performance_stats log = {0};
+
+ int log_size = 4 + cfg.duration * sizeof(struct performance_stats_timestamp);
+ // Get one more timestamp if duration is odd number to avoid non-dw alignment issues
+ int xfer_size = (cfg.duration % 2) > 0 ?
+ (4 + (cfg.duration + 1) * sizeof(struct performance_stats_timestamp)) : log_size;
+
+ err = nvme_get_log_simple(dev_fd(dev), LID_PERFORMANCE_STATISTICS, xfer_size, &log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ performance_stats_print(&log, dev->name, cfg.duration);
+ else
+ d_raw((unsigned char *)&log, log_size);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
+ }
- dev_close(dev);
return err;
}
diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h
index e25267b..6c7462f 100644
--- a/plugins/memblaze/memblaze-nvme.h
+++ b/plugins/memblaze/memblaze-nvme.h
@@ -9,18 +9,36 @@
PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions", NVME_VERSION),
COMMAND_LIST(
- ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", mb_get_additional_smart_log)
- ENTRY("get-pm-status", "Get Memblaze Power Manager Status", mb_get_powermanager_status)
- ENTRY("set-pm-status", "Set Memblaze Power Manager Status", mb_set_powermanager_status)
- ENTRY("select-download", "Selective Firmware Download", mb_selective_download)
- ENTRY("lat-stats", "Enable and disable Latency Statistics logging", mb_set_lat_stats)
- ENTRY("lat-stats-print", "Retrieve IO Latency Statistics log, show it", mb_lat_stats_log_print)
- ENTRY("lat-log", "Set Memblaze High Latency Log", mb_set_high_latency_log)
- ENTRY("lat-log-print", "Output Memblaze High Latency Log", mb_high_latency_log_print)
- ENTRY("clear-error-log", "Clear error log", memblaze_clear_error_log)
- ENTRY("smart-log-add-x", "Retrieve Memblaze SMART Log, show it", mb_get_smart_log_add)
- ENTRY("lat-set-feature-x", "Set Enable/Disable for Latency Monitor feature", mb_set_latency_feature)
- ENTRY("lat-get-feature-x", "Get Enabled/Disabled of Latency Monitor feature", mb_get_latency_feature)
+ ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it",
+ mb_get_additional_smart_log)
+ ENTRY("get-pm-status", "Get Memblaze Power Manager Status",
+ mb_get_powermanager_status)
+ ENTRY("set-pm-status", "Set Memblaze Power Manager Status",
+ mb_set_powermanager_status)
+ ENTRY("select-download", "Selective Firmware Download",
+ mb_selective_download)
+ ENTRY("lat-stats", "Enable and disable Latency Statistics logging",
+ mb_set_lat_stats)
+ ENTRY("lat-stats-print", "Retrieve IO Latency Statistics log, show it",
+ mb_lat_stats_log_print)
+ ENTRY("lat-log", "Set Memblaze High Latency Log",
+ mb_set_high_latency_log)
+ ENTRY("lat-log-print", "Output Memblaze High Latency Log",
+ mb_high_latency_log_print)
+ ENTRY("clear-error-log", "Clear error log",
+ memblaze_clear_error_log)
+ ENTRY("smart-log-add-x", "Retrieve Memblaze SMART Log, show it",
+ mb_get_smart_log_add)
+ ENTRY("lat-set-feature-x", "Set Enable/Disable for Latency Monitor feature",
+ mb_set_latency_feature)
+ ENTRY("lat-get-feature-x", "Get Enabled/Disabled of Latency Monitor feature",
+ mb_get_latency_feature)
+ ENTRY("lat-stats-print-x", "Get Latency Statistics log and show it.",
+ mb_get_latency_stats)
+ ENTRY("lat-log-print-x", "Get High Latency log and show it.",
+ mb_get_high_latency_log)
+ ENTRY("perf-stats-print-x", "Get Performance Stat log and show it.",
+ mb_get_performance_stats)
)
);
diff --git a/plugins/meson.build b/plugins/meson.build
index bb4c9ad..146fa2a 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -26,10 +26,11 @@ if json_c_dep.found()
'plugins/wdc/wdc-utils.c',
'plugins/ymtc/ymtc-nvme.c',
'plugins/zns/zns.c',
+ 'plugins/ssstc/ssstc-nvme.c',
]
subdir('solidigm')
subdir('ocp')
- if conf.has('HAVE_SED_OPAL')
+ if conf.get('HAVE_SED_OPAL') != 0
subdir('sed')
endif
endif
diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c
index 63a7a79..2782595 100644
--- a/plugins/micron/micron-nvme.c
+++ b/plugins/micron/micron-nvme.c
@@ -1,4 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) Micron, Inc 2024.
+ *
+ * @file: micron-nvme.c
+ * @brief: This module contains all the constructs needed for micron nvme-cli plugin.
+ * @authors:Chaithanya Shoba <ashoba@micron.com>,
+ */
+
#include <stdio.h>
#include <string.h>
#include <ctype.h>
@@ -9,6 +17,8 @@
#include <time.h>
#include <string.h>
#include <libgen.h>
+#include <stddef.h>
+#include <sys/types.h>
#include <sys/stat.h>
#include "common.h"
#include "nvme.h"
@@ -17,6 +27,7 @@
#include "linux/types.h"
#include "nvme-print.h"
#include "util/cleanup.h"
+#include "util/utils.h"
#define CREATE_CMD
#include "micron-nvme.h"
@@ -132,34 +143,24 @@ static enum eDriveModel GetDriveModel(int idx)
if (vendor_id == MICRON_VENDOR_ID) {
switch (device_id) {
case 0x5196:
- fallthrough;
case 0x51A0:
- fallthrough;
case 0x51A1:
- fallthrough;
case 0x51A2:
eModel = M51AX;
break;
case 0x51B0:
- fallthrough;
case 0x51B1:
- fallthrough;
case 0x51B2:
eModel = M51BX;
break;
case 0x51C0:
- fallthrough;
case 0x51C1:
- fallthrough;
case 0x51C2:
- fallthrough;
case 0x51C3:
eModel = M51CX;
break;
case 0x5405:
- fallthrough;
case 0x5406:
- fallthrough;
case 0x5407:
eModel = M5407;
break;
@@ -226,7 +227,6 @@ static int SetupDebugDataDirectories(char *strSN, char *strFilePath,
int length = 0;
int nIndex = 0;
char *strTemp = NULL;
- struct stat dirStat;
int j;
int k = 0;
int i = 0;
@@ -304,18 +304,17 @@ static int SetupDebugDataDirectories(char *strSN, char *strFilePath,
strMainDirName[nIndex] = '\0';
j = 1;
- while (!stat(strMainDirName, &dirStat)) {
+ while (mkdir(strMainDirName, 0777) < 0) {
+ if (errno != EEXIST) {
+ err = -1;
+ goto exit_status;
+ }
strMainDirName[nIndex] = '\0';
sprintf(strAppend, "-%d", j);
strcat(strMainDirName, strAppend);
j++;
}
- if (mkdir(strMainDirName, 0777) < 0) {
- err = -1;
- goto exit_status;
- }
-
if (strOSDirName) {
sprintf(strOSDirName, "%s/%s", strMainDirName, "OS");
if (mkdir(strOSDirName, 0777) < 0) {
@@ -331,7 +330,7 @@ static int SetupDebugDataDirectories(char *strSN, char *strFilePath,
rmdir(strOSDirName);
rmdir(strMainDirName);
err = -1;
- }
+ }
}
exit_status:
@@ -1203,14 +1202,8 @@ static void init_d0_log_page(__u8 *buf, __u8 nsze)
sprintf(d0_log_page[6].datastr, "0x%x", logD0[1]);
}
-/* OCP and Vendor specific log data format */
-struct micron_vs_logpage {
- char *field;
- int size; /* FB client spec version 1.0 sizes - M5410 models */
- int size2; /* FB client spec version 0.7 sizes - M5407 models */
-}
/* Smart Health Log information as per OCP spec M51CX models */
-ocp_c0_log_page[] = {
+struct request_data ocp_c0_log_page[] = {
{ "Physical Media Units Written", 16},
{ "Physical Media Units Read", 16 },
{ "Raw Bad User NAND Block Count", 6},
@@ -1329,82 +1322,6 @@ fb_log_page[] = {
{ "Log Page GUID", 0, 16},
};
-/*
- * Common function to print Micron VS log pages
- * - buf: raw log data
- * - log_page: format of the data
- * - field_count: log field count
- * - stats: json object to add fields
- * - spec: ocp spec index
- */
-static void print_micron_vs_logs(__u8 *buf, struct micron_vs_logpage *log_page, int field_count,
- struct json_object *stats, __u8 spec)
-{
- __u64 lval_lo, lval_hi;
- __u32 ival;
- __u16 sval;
- __u8 cval, lval[8] = { 0 };
- int field;
- int offset = 0;
-
- for (field = 0; field < field_count; field++) {
- char datastr[1024] = { 0 };
- char *sfield = NULL;
- int size = !spec ? log_page[field].size : log_page[field].size2;
-
- if (!size)
- continue;
- sfield = log_page[field].field;
- if (size == 16) {
- if (strstr(sfield, "GUID")) {
- sprintf(datastr, "0x%"PRIx64"%"PRIx64"",
- (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset + 8])),
- (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset])));
- } else {
- lval_lo = *((__u64 *)(&buf[offset]));
- lval_hi = *((__u64 *)(&buf[offset + 8]));
- if (lval_hi)
- sprintf(datastr, "0x%"PRIx64"%016"PRIx64"",
- le64_to_cpu(lval_hi), le64_to_cpu(lval_lo));
- else
- sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo));
- }
- } else if (size == 8) {
- lval_lo = *((__u64 *)(&buf[offset]));
- sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo));
- } else if (size == 7) {
- /* 7 bytes will be in little-endian format, with last byte as MSB */
- memcpy(&lval[0], &buf[offset], 7);
- memcpy((void *)&lval_lo, lval, 8);
- sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo));
- } else if (size == 6) {
- ival = *((__u32 *)(&buf[offset]));
- sval = *((__u16 *)(&buf[offset + 4]));
- lval_lo = (((__u64)sval << 32) | ival);
- sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo));
- } else if (size == 4) {
- ival = *((__u32 *)(&buf[offset]));
- sprintf(datastr, "0x%x", le32_to_cpu(ival));
- } else if (size == 2) {
- sval = *((__u16 *)(&buf[offset]));
- sprintf(datastr, "0x%04x", le16_to_cpu(sval));
- } else if (size == 1) {
- cval = buf[offset];
- sprintf(datastr, "0x%02x", cval);
- } else {
- sprintf(datastr, "0");
- }
- offset += size;
- /* do not print reserved values */
- if (strstr(sfield, "Reserved"))
- continue;
- if (stats)
- json_object_add_value_string(stats, sfield, datastr);
- else
- printf("%-40s : %-4s\n", sfield, datastr);
- }
-}
-
static void print_smart_cloud_health_log(__u8 *buf, bool is_json)
{
struct json_object *root;
@@ -1420,7 +1337,7 @@ static void print_smart_cloud_health_log(__u8 *buf, bool is_json)
logPages);
}
- print_micron_vs_logs(buf, ocp_c0_log_page, field_count, stats, 0);
+ generic_structure_parser(buf, ocp_c0_log_page, field_count, stats, 0, NULL);
if (is_json) {
json_array_add_value_object(logPages, stats);
@@ -1445,7 +1362,7 @@ static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json,
logPages);
}
- print_micron_vs_logs(buf, fb_log_page, field_count, stats, spec);
+ generic_structure_parser(buf, fb_log_page, field_count, stats, spec, NULL);
/* print last three entries from D0 log page */
if (buf2) {
@@ -1599,7 +1516,7 @@ static void print_ext_smart_logs_e1(__u8 *buf, bool is_json)
printf("SMART Extended Log:0xE1\n");
}
- print_micron_vs_logs(buf, e1_log_page, field_count, stats, 0);
+ generic_structure_parser(buf, e1_log_page, field_count, stats, 0, NULL);
if (is_json) {
json_array_add_value_object(logPages, stats);
@@ -1768,6 +1685,7 @@ static void GetGenericLogs(int fd, const char *dir)
struct nvme_firmware_slot fw_log;
struct nvme_cmd_effects_log effects;
struct nvme_persistent_event_log pevent_log;
+
_cleanup_huge_ struct nvme_mem_huge mh = { 0, };
void *pevent_log_info = NULL;
__u32 log_len = 0;
@@ -3217,28 +3135,20 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
err = -1;
switch (aVendorLogs[i].ucLogPage) {
case 0xE1:
- fallthrough;
case 0xE5:
- fallthrough;
case 0xE9:
err = 1;
break;
case 0xE2:
- fallthrough;
case 0xE3:
- fallthrough;
case 0xE4:
- fallthrough;
case 0xE8:
- fallthrough;
case 0xEA:
err = get_common_log(dev_fd(dev), aVendorLogs[i].ucLogPage,
&dataBuffer, &bSize);
break;
case 0xC1:
- fallthrough;
case 0xC2:
- fallthrough;
case 0xC4:
err = GetLogPageSize(dev_fd(dev), aVendorLogs[i].ucLogPage,
&bSize);
@@ -3247,7 +3157,6 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
&dataBuffer, bSize);
break;
case 0xE6:
- fallthrough;
case 0xE7:
puiIDDBuf = (unsigned int *)&ctrl;
uiMask = puiIDDBuf[1015];
@@ -3273,11 +3182,8 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd,
}
break;
case 0xF7:
- fallthrough;
case 0xF9:
- fallthrough;
case 0xFC:
- fallthrough;
case 0xFD:
if (eModel == M51BX)
(void)NVMEResetLog(dev_fd(dev), aVendorLogs[i].ucLogPage,
diff --git a/plugins/micron/micron-nvme.h b/plugins/micron/micron-nvme.h
index 4f7b892..c9e3ca7 100644
--- a/plugins/micron/micron-nvme.h
+++ b/plugins/micron/micron-nvme.h
@@ -1,4 +1,11 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) Micron, Inc 2024.
+ *
+ * @file: micron-nvme.h
+ * @brief: This module contains all the constructs needed for micron nvme-cli plugin.
+ * @authors:Chaithanya Shoba <ashoba@micron.com>,
+ */
#undef CMD_INC_FILE
#define CMD_INC_FILE plugins/micron/micron-nvme
diff --git a/plugins/nbft/nbft-plugin.c b/plugins/nbft/nbft-plugin.c
index 2193ffb..f25941a 100644
--- a/plugins/nbft/nbft-plugin.c
+++ b/plugins/nbft/nbft-plugin.c
@@ -4,11 +4,12 @@
#include <stdio.h>
#include <fnmatch.h>
+#include <libnvme.h>
#include "nvme-print.h"
#include "nvme.h"
#include "nbft.h"
-#include "libnvme.h"
#include "fabrics.h"
+#include "util/logging.h"
#define CREATE_CMD
#include "nbft-plugin.h"
@@ -168,7 +169,11 @@ static json_object *ssns_to_json(struct nbft_info_subsystem_ns *ss)
|| json_object_add_value_int(ss_json, "pdu_header_digest_required",
ss->pdu_header_digest_required)
|| json_object_add_value_int(ss_json, "data_digest_required",
- ss->data_digest_required))
+ ss->data_digest_required)
+ || json_object_add_value_int(ss_json, "discovered",
+ ss->discovered)
+ || json_object_add_value_int(ss_json, "unavailable",
+ ss->unavailable))
goto fail;
return ss_json;
@@ -319,7 +324,7 @@ static int json_show_nbfts(struct list_head *nbft_list, bool show_subsys,
bool show_hfi, bool show_discovery)
{
struct json_object *nbft_json_array, *nbft_json;
- struct nbft_file_entry *entry;
+ struct nbft_file_entry *entry = NULL;
nbft_json_array = json_create_array();
if (!nbft_json_array)
@@ -510,7 +515,7 @@ static void normal_show_nbfts(struct list_head *nbft_list, bool show_subsys,
bool show_hfi, bool show_discovery)
{
bool not_first = false;
- struct nbft_file_entry *entry;
+ struct nbft_file_entry *entry = NULL;
list_for_each(nbft_list, entry, node) {
if (not_first)
@@ -526,9 +531,10 @@ int show_nbft(int argc, char **argv, struct command *cmd, struct plugin *plugin)
struct list_head nbft_list;
char *format = "normal";
char *nbft_path = NBFT_SYSFS_PATH;
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
int ret;
bool show_subsys = false, show_hfi = false, show_discovery = false;
+ unsigned int verbose = 0;
OPT_ARGS(opts) = {
OPT_FMT("output-format", 'o', &format, "Output format: normal|json"),
@@ -536,6 +542,7 @@ int show_nbft(int argc, char **argv, struct command *cmd, struct plugin *plugin)
OPT_FLAG("hfi", 'H', &show_hfi, "show NBFT HFIs"),
OPT_FLAG("discovery", 'd', &show_discovery, "show NBFT discovery controllers"),
OPT_STRING("nbft-path", 0, "STR", &nbft_path, "user-defined path for NBFT tables"),
+ OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"),
OPT_END()
};
@@ -543,6 +550,9 @@ int show_nbft(int argc, char **argv, struct command *cmd, struct plugin *plugin)
if (ret)
return ret;
+ log_level = map_log_level(verbose, false /* quiet */);
+ nvme_init_default_logging(stderr, log_level, false, false);
+
ret = validate_output_format(format, &flags);
if (ret < 0)
return ret;
diff --git a/plugins/netapp/netapp-nvme.c b/plugins/netapp/netapp-nvme.c
index 2ecdcc5..99f0a20 100644
--- a/plugins/netapp/netapp-nvme.c
+++ b/plugins/netapp/netapp-nvme.c
@@ -46,12 +46,14 @@ enum {
enum {
ONTAP_C2_LOG_SUPPORTED_LSP = 0x0,
ONTAP_C2_LOG_NSINFO_LSP = 0x1,
+ ONTAP_C2_LOG_PLATFORM_LSP = 0x2,
};
enum {
- ONTAP_VSERVER_TLV = 0x11,
- ONTAP_VOLUME_TLV = 0x12,
- ONTAP_NS_TLV = 0x13,
+ ONTAP_VSERVER_NAME_TLV = 0x11,
+ ONTAP_VOLUME_NAME_TLV = 0x12,
+ ONTAP_NS_NAME_TLV = 0x13,
+ ONTAP_NS_PATH_TLV = 0x14,
};
static const char *dev_path = "/dev/";
@@ -134,8 +136,10 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath,
unsigned char *log_data)
{
int lsp, tlv, label_len;
- char *vserver_name, *volume_name, *namespace_name;
+ char *vserver_name, *volume_name, *namespace_name, *namespace_path;
char vol_name[ONTAP_LABEL_LEN], ns_name[ONTAP_LABEL_LEN];
+ char ns_path[ONTAP_LABEL_LEN];
+ bool nspath_tlv_available = false;
const char *ontap_vol = "/vol/";
int i, j;
@@ -145,9 +149,9 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath,
/* lsp not related to nsinfo */
return;
- /* get the vserver tlv and name */
+ /* get the vserver name tlv */
tlv = *(__u8 *)&log_data[32];
- if (tlv == ONTAP_VSERVER_TLV) {
+ if (tlv == ONTAP_VSERVER_NAME_TLV) {
label_len = (*(__u16 *)&log_data[34]) * 4;
vserver_name = (char *)&log_data[36];
ontap_labels_to_str(vsname, vserver_name, label_len);
@@ -159,9 +163,9 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath,
i = 36 + label_len;
j = i + 2;
- /* get the volume tlv and name */
+ /* get the volume name tlv */
tlv = *(__u8 *)&log_data[i];
- if (tlv == ONTAP_VOLUME_TLV) {
+ if (tlv == ONTAP_VOLUME_NAME_TLV) {
label_len = (*(__u16 *)&log_data[j]) * 4;
volume_name = (char *)&log_data[j + 2];
ontap_labels_to_str(vol_name, volume_name, label_len);
@@ -173,9 +177,9 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath,
i += 4 + label_len;
j += 4 + label_len;
- /* get the namespace tlv and name */
+ /* get the namespace name tlv */
tlv = *(__u8 *)&log_data[i];
- if (tlv == ONTAP_NS_TLV) {
+ if (tlv == ONTAP_NS_NAME_TLV) {
label_len = (*(__u16 *)&log_data[j]) * 4;
namespace_name = (char *)&log_data[j + 2];
ontap_labels_to_str(ns_name, namespace_name, label_len);
@@ -185,8 +189,25 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath,
return;
}
- snprintf(nspath, ONTAP_NS_PATHLEN, "%s%s%s%s", ontap_vol,
+ i += 4 + label_len;
+ j += 4 + label_len;
+ /* get the namespace path tlv if available */
+ tlv = *(__u8 *)&log_data[i];
+ if (tlv == ONTAP_NS_PATH_TLV) {
+ nspath_tlv_available = true;
+ label_len = (*(__u16 *)&log_data[j]) * 4;
+ namespace_path = (char *)&log_data[j + 2];
+ ontap_labels_to_str(ns_path, namespace_path, label_len);
+ }
+
+ if (nspath_tlv_available) {
+ /* set nspath from the corresponding ns_path string */
+ snprintf(nspath, ONTAP_NS_PATHLEN, "%s", ns_path);
+ } else {
+ /* set nspath by concatenating ontap_vol with ns_name */
+ snprintf(nspath, ONTAP_NS_PATHLEN, "%s%s%s%s", ontap_vol,
vol_name, "/", ns_name);
+ }
}
static void netapp_smdevice_json(struct json_object *devices, char *devname,
diff --git a/plugins/ocp/meson.build b/plugins/ocp/meson.build
index 64447ff..7835444 100644
--- a/plugins/ocp/meson.build
+++ b/plugins/ocp/meson.build
@@ -4,5 +4,6 @@ sources += [
'plugins/ocp/ocp-clear-features.c',
'plugins/ocp/ocp-smart-extended-log.c',
'plugins/ocp/ocp-fw-activation-history.c',
+ 'plugins/ocp/ocp-telemetry-decode.c',
]
diff --git a/plugins/ocp/ocp-clear-features.c b/plugins/ocp/ocp-clear-features.c
index 0f49584..731dfea 100644
--- a/plugins/ocp/ocp-clear-features.c
+++ b/plugins/ocp/ocp-clear-features.c
@@ -18,7 +18,7 @@ static int ocp_clear_feature(int argc, char **argv, const char *desc, const __u8
__u32 result = 0;
__u32 clear = 1 << 31;
struct nvme_dev *dev;
- int uuid_index = 0;
+ __u8 uuid_index = 0;
bool uuid = true;
int err;
diff --git a/plugins/ocp/ocp-fw-activation-history.c b/plugins/ocp/ocp-fw-activation-history.c
index ad96c6b..543042f 100644
--- a/plugins/ocp/ocp-fw-activation-history.c
+++ b/plugins/ocp/ocp-fw-activation-history.c
@@ -66,7 +66,7 @@ static void ocp_fw_activation_history_normal(const struct fw_activation_history
printf(" %-22s%d\n", "activation count:",
le16_to_cpu(entry->activation_count));
printf(" %-22s%"PRIu64"\n", "timestamp:",
- le64_to_cpu(entry->timestamp));
+ (0x0000FFFFFFFFFFFF & le64_to_cpu(entry->timestamp)));
printf(" %-22s%"PRIu64"\n", "power cycle count:",
le64_to_cpu(entry->power_cycle_count));
printf(" %-22s%.*s\n", "previous firmware:", (int)sizeof(entry->previous_fw),
@@ -106,7 +106,7 @@ static void ocp_fw_activation_history_json(const struct fw_activation_history *f
json_object_add_value_uint(entry_obj, "activation count",
le16_to_cpu(entry->activation_count));
json_object_add_value_uint64(entry_obj, "timestamp",
- le64_to_cpu(entry->timestamp));
+ (0x0000FFFFFFFFFFFF & le64_to_cpu(entry->timestamp)));
json_object_add_value_uint(entry_obj, "power cycle count",
le64_to_cpu(entry->power_cycle_count));
@@ -162,7 +162,7 @@ int ocp_fw_activation_history_log(int argc, char **argv, struct command *cmd,
if (err)
return err;
- int uuid_index = 0;
+ __u8 uuid_index = 0;
/*
* Best effort attempt at uuid. Otherwise, assume no index (i.e. 0)
@@ -207,7 +207,7 @@ int ocp_fw_activation_history_log(int argc, char **argv, struct command *cmd,
}
if (!err) {
- enum nvme_print_flags print_flag;
+ nvme_print_flags_t print_flag;
err = validate_output_format(format, &print_flag);
if (err < 0) {
diff --git a/plugins/ocp/ocp-nvme.c b/plugins/ocp/ocp-nvme.c
index 53ae0f4..91f4083 100644
--- a/plugins/ocp/ocp-nvme.c
+++ b/plugins/ocp/ocp-nvme.c
@@ -23,10 +23,12 @@
#include "linux/types.h"
#include "util/types.h"
#include "nvme-print.h"
+#include "nvme-wrap.h"
#include "ocp-smart-extended-log.h"
#include "ocp-clear-features.h"
#include "ocp-fw-activation-history.h"
+#include "ocp-telemetry-decode.h"
#define CREATE_CMD
#include "ocp-nvme.h"
@@ -112,6 +114,93 @@ struct __packed feature_latency_monitor {
__u8 reserved[4083];
};
+struct erri_entry {
+ union {
+ __u8 flags;
+ struct {
+ __u8 enable:1;
+ __u8 single:1;
+ __u8 rsvd2:6;
+ };
+ };
+ __u8 rsvd1;
+ __le16 type;
+ union {
+ __u8 specific[28];
+ struct {
+ __le16 nrtdp;
+ __u8 rsvd4[26];
+ };
+ };
+};
+
+#define ERRI_ENTRIES_MAX 127
+
+enum erri_type {
+ ERRI_TYPE_CPU_CTRL_HANG = 1,
+ ERRI_TYPE_NAND_HANG,
+ ERRI_TYPE_PLP_DEFECT,
+ ERRI_TYPE_LOGICAL_FIRMWARE_ERROR,
+ ERRI_TYPE_DRAM_CORRUPT_CRIT,
+ ERRI_TYPE_DRAM_CORRUPT_NON_CRIT,
+ ERRI_TYPE_NAND_CORRUPT,
+ ERRI_TYPE_SRAM_CORRUPT,
+ ERRI_TYPE_HW_MALFUNCTION,
+ ERRI_TYPE_NO_MORE_NAND_SPARES,
+ ERRI_TYPE_INCOMPLETE_SHUTDOWN,
+};
+
+const char *erri_type_to_string(__le16 type)
+{
+ switch (type) {
+ case ERRI_TYPE_CPU_CTRL_HANG:
+ return "CPU/controller hang";
+ case ERRI_TYPE_NAND_HANG:
+ return "NAND hang";
+ case ERRI_TYPE_PLP_DEFECT:
+ return "PLP defect";
+ case ERRI_TYPE_LOGICAL_FIRMWARE_ERROR:
+ return "logical firmware error";
+ case ERRI_TYPE_DRAM_CORRUPT_CRIT:
+ return "DRAM corruption critical path";
+ case ERRI_TYPE_DRAM_CORRUPT_NON_CRIT:
+ return "DRAM corruption non-critical path";
+ case ERRI_TYPE_NAND_CORRUPT:
+ return "NAND corruption";
+ case ERRI_TYPE_SRAM_CORRUPT:
+ return "SRAM corruption";
+ case ERRI_TYPE_HW_MALFUNCTION:
+ return "HW malfunction";
+ case ERRI_TYPE_NO_MORE_NAND_SPARES:
+ return "no more NAND spares available";
+ case ERRI_TYPE_INCOMPLETE_SHUTDOWN:
+ return "incomplete shutdown";
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
+struct erri_get_cq_entry {
+ __u32 nume:7;
+ __u32 rsvd7:25;
+};
+
+struct erri_config {
+ char *file;
+ __u8 number;
+ __u16 type;
+ __u16 nrtdp;
+};
+
+static const char *sel = "[0-3]: current/default/saved/supported";
+static const char *no_uuid = "Skip UUID index search (UUID index not required for OCP 1.0)";
+const char *data = "Error injection data structure entries";
+const char *number = "Number of valid error injection data entries";
+static const char *type = "Error injection type";
+static const char *nrtdp = "Number of reads to trigger device panic";
+
static int ocp_print_C3_log_normal(struct nvme_dev *dev,
struct ssd_latency_monitor_log *log_data)
{
@@ -140,7 +229,7 @@ static int ocp_print_C3_log_normal(struct nvme_dev *dev,
printf(" Active Threshold D %d ms\n",
C3_ACTIVE_THRESHOLD_INCREMENT *
le16_to_cpu(log_data->active_threshold_d+1));
- printf(" Active Latency Configuration 0x%x \n",
+ printf(" Active Latency Configuration 0x%x\n",
le16_to_cpu(log_data->active_latency_config));
printf(" Active Latency Minimum Window %d ms\n",
C3_MINIMUM_WINDOW_INCREMENT *
@@ -397,7 +486,7 @@ static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data)
static int get_c3_log_page(struct nvme_dev *dev, char *format)
{
struct ssd_latency_monitor_log *log_data;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
int ret;
__u8 *data;
int i;
@@ -664,8 +753,8 @@ static const char *eol_plp_failure_mode_to_string(__u8 mode)
return "Reserved";
}
-static int eol_plp_failure_mode_get(struct nvme_dev *dev, const __u32 nsid,
- const __u8 fid, __u8 sel)
+static int eol_plp_failure_mode_get(struct nvme_dev *dev, const __u32 nsid, const __u8 fid,
+ __u8 sel, bool uuid)
{
__u32 result;
int err;
@@ -684,6 +773,15 @@ static int eol_plp_failure_mode_get(struct nvme_dev *dev, const __u32 nsid,
.result = &result,
};
+ if (uuid) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &args.uuidx);
+ if (err || !args.uuidx) {
+ nvme_show_error("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
err = nvme_get_features(&args);
if (!err) {
nvme_show_result("End of Life Behavior (feature: %#0*x): %#0*x (%s: %s)",
@@ -705,7 +803,7 @@ static int eol_plp_failure_mode_set(struct nvme_dev *dev, const __u32 nsid,
{
__u32 result;
int err;
- int uuid_index = 0;
+ __u8 uuid_index = 0;
if (uuid) {
/* OCP 2.0 requires UUID index support */
@@ -716,7 +814,6 @@ static int eol_plp_failure_mode_set(struct nvme_dev *dev, const __u32 nsid,
}
}
-
struct nvme_set_features_args args = {
.args_size = sizeof(args),
.fd = dev_fd(dev),
@@ -756,7 +853,7 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd,
"No argument prints current mode.";
const char *mode = "[0-3]: default/rom/wtm/normal";
const char *save = "Specifies that the controller shall save the attribute";
- const char *sel = "[0-3,8]: current/default/saved/supported/changed";
+ const char *sel = "[0-3]: current/default/saved/supported";
const __u32 nsid = 0;
const __u8 fid = 0xc2;
struct nvme_dev *dev;
@@ -774,14 +871,12 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd,
.sel = 0,
};
- OPT_ARGS(opts) = {
- OPT_BYTE("mode", 'm', &cfg.mode, mode),
- OPT_FLAG("save", 's', &cfg.save, save),
- OPT_BYTE("sel", 'S', &cfg.sel, sel),
- OPT_FLAG("no-uuid", 'n', NULL,
- "Skip UUID index search (UUID index not required for OCP 1.0)"),
- OPT_END()
- };
+ NVME_ARGS(opts,
+ OPT_BYTE("mode", 'm', &cfg.mode, mode),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_BYTE("sel", 'S', &cfg.sel, sel),
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"));
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
@@ -792,7 +887,8 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd,
cfg.save,
!argconfig_parse_seen(opts, "no-uuid"));
else
- err = eol_plp_failure_mode_get(dev, nsid, fid, cfg.sel);
+ err = eol_plp_failure_mode_get(dev, nsid, fid, cfg.sel,
+ !argconfig_parse_seen(opts, "no-uuid"));
dev_close(dev);
@@ -804,58 +900,15 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd,
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Telemetry Log
+//global buffers
+static __le64 total_log_page_sz;
+static __u8 *header_data;
+static struct telemetry_str_log_format *log_data;
-#define TELEMETRY_HEADER_SIZE 512
-#define TELEMETRY_BYTE_PER_BLOCK 512
-#define TELEMETRY_TRANSFER_SIZE 1024
-#define FILE_NAME_SIZE 2048
-
-enum TELEMETRY_TYPE {
- TELEMETRY_TYPE_NONE = 0,
- TELEMETRY_TYPE_HOST = 7,
- TELEMETRY_TYPE_CONTROLLER = 8,
- TELEMETRY_TYPE_HOST_0 = 9,
- TELEMETRY_TYPE_HOST_1 = 10,
-};
+__u8 *ptelemetry_buffer;
+__u8 *pstring_buffer;
+__u8 *pC9_string_buffer;
-struct telemetry_initiated_log {
- __u8 LogIdentifier;
- __u8 Reserved1[4];
- __u8 IEEE[3];
- __le16 DataArea1LastBlock;
- __le16 DataArea2LastBlock;
- __le16 DataArea3LastBlock;
- __u8 Reserved2[368];
- __u8 DataAvailable;
- __u8 DataGenerationNumber;
- __u8 ReasonIdentifier[128];
-};
-
-struct telemetry_data_area_1 {
- __le16 major_version;
- __le16 minor_version;
- __u8 reserved1[4];
- __le64 timestamp;
- __u8 log_page_guid[16];
- __u8 no_of_tps_supp;
- __u8 tps;
- __u8 reserved2[6];
- __le16 sls;
- __u8 reserved3[8];
- __le16 fw_revision;
- __u8 reserved4[32];
- __le16 da1_stat_start;
- __le16 da1_stat_size;
- __le16 da2_stat_start;
- __le16 da2_stat_size;
- __u8 reserved5[32];
- __u8 event_fifo_da[16];
- __le64 event_fifo_start[16];
- __le64 event_fifo_size[16];
- __u8 reserved6[80];
- __u8 smart_health_info[512];
- __u8 smart_health_info_extended[512];
-};
static void get_serial_number(struct nvme_id_ctrl *ctrl, char *sn)
{
int i;
@@ -867,39 +920,20 @@ static void get_serial_number(struct nvme_id_ctrl *ctrl, char *sn)
}
}
-static int get_telemetry_header(struct nvme_dev *dev, __u32 ns, __u8 tele_type,
- __u32 data_len, void *data, __u8 nLSP, __u8 nRAE)
-{
- struct nvme_passthru_cmd cmd = {
- .opcode = nvme_admin_get_log_page,
- .nsid = ns,
- .addr = (__u64)(uintptr_t) data,
- .data_len = data_len,
- };
-
- __u32 numd = (data_len >> 2) - 1;
- __u16 numdu = numd >> 16;
- __u16 numdl = numd & 0xffff;
-
- cmd.cdw10 = tele_type | (nLSP & 0x0F) << 8 | (nRAE & 0x01) << 15 | (numdl & 0xFFFF) << 16;
- cmd.cdw11 = numdu;
- cmd.cdw12 = 0;
- cmd.cdw13 = 0;
- cmd.cdw14 = 0;
-
- return nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL);
-}
-
static void print_telemetry_header(struct telemetry_initiated_log *logheader,
int tele_type)
{
if (logheader) {
unsigned int i = 0, j = 0;
+ __u8 dataGenNum;
- if (tele_type == TELEMETRY_TYPE_HOST)
+ if (tele_type == TELEMETRY_TYPE_HOST) {
printf("============ Telemetry Host Header ============\n");
- else
+ dataGenNum = logheader->DataHostGenerationNumber;
+ } else {
printf("========= Telemetry Controller Header =========\n");
+ dataGenNum = logheader->DataCtlrGenerationNumber;
+ }
printf("Log Identifier : 0x%02X\n", logheader->LogIdentifier);
printf("IEEE : 0x%02X%02X%02X\n",
@@ -910,8 +944,10 @@ static void print_telemetry_header(struct telemetry_initiated_log *logheader,
le16_to_cpu(logheader->DataArea2LastBlock));
printf("Data Area 3 Last Block : 0x%04X\n",
le16_to_cpu(logheader->DataArea3LastBlock));
- printf("Data Available : 0x%02X\n", logheader->DataAvailable);
- printf("Data Generation Number : 0x%02X\n", logheader->DataGenerationNumber);
+ printf("Data Available : 0x%02X\n",
+ logheader->CtlrDataAvailable);
+ printf("Data Generation Number : 0x%02X\n",
+ dataGenNum);
printf("Reason Identifier :\n");
for (i = 0; i < 8; i++) {
@@ -922,6 +958,7 @@ static void print_telemetry_header(struct telemetry_initiated_log *logheader,
printf("===============================================\n\n");
}
}
+
static int get_telemetry_data(struct nvme_dev *dev, __u32 ns, __u8 tele_type,
__u32 data_len, void *data, __u8 nLSP, __u8 nRAE,
__u64 offset)
@@ -935,10 +972,14 @@ static int get_telemetry_data(struct nvme_dev *dev, __u32 ns, __u8 tele_type,
__u32 numd = (data_len >> 2) - 1;
__u16 numdu = numd >> 16;
__u16 numdl = numd & 0xffff;
- cmd.cdw10 = tele_type | (nLSP & 0x0F) << 8 | (nRAE & 0x01) << 15 | (numdl & 0xFFFF) << 16;
+
+ cmd.cdw10 = tele_type |
+ (nLSP & 0x0F) << 8 |
+ (nRAE & 0x01) << 15 |
+ (numdl & 0xFFFF) << 16;
cmd.cdw11 = numdu;
- cmd.cdw12 = offset;
- cmd.cdw13 = 0;
+ cmd.cdw12 = (__u32)(0x00000000FFFFFFFF & offset);
+ cmd.cdw13 = (__u32)((0xFFFFFFFF00000000 & offset) >> 8);
cmd.cdw14 = 0;
return nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL);
}
@@ -946,121 +987,117 @@ static void print_telemetry_data_area_1(struct telemetry_data_area_1 *da1,
int tele_type)
{
if (da1) {
- unsigned int i = 0;
+ int i = 0;
+
if (tele_type == TELEMETRY_TYPE_HOST)
printf("============ Telemetry Host Data area 1 ============\n");
else
printf("========= Telemetry Controller Data area 1 =========\n");
- printf("Major Version : 0x%x\n", le16_to_cpu(da1->major_version));
- printf("Minor Version : 0x%x\n", le16_to_cpu(da1->minor_version));
- for (i = 0; i < 4; i++)
- printf("reserved1 : 0x%x\n", da1->reserved1[i]);
+ printf("Major Version : 0x%x\n", le16_to_cpu(da1->major_version));
+ printf("Minor Version : 0x%x\n", le16_to_cpu(da1->minor_version));
printf("Timestamp : %"PRIu64"\n", le64_to_cpu(da1->timestamp));
- for (i = 15; i >= 0; i--)
- printf("%x", da1->log_page_guid[i]);
- printf("Number Telemetry Profiles Supported : 0x%x\n", da1->no_of_tps_supp);
- printf("Telemetry Profile Selected (TPS) : 0x%x\n", da1->tps);
- for (i = 0; i < 6; i++)
- printf("reserved2 : 0x%x\n", da1->reserved2[i]);
- printf("Telemetry String Log Size (SLS) : 0x%x\n", le16_to_cpu(da1->sls));
+ printf("Log Page GUID : 0x");
+ for (int j = 15; j >= 0; j--)
+ printf("%02x", da1->log_page_guid[j]);
+ printf("\n");
+ printf("Number Telemetry Profiles Supported : 0x%x\n",
+ da1->no_of_tps_supp);
+ printf("Telemetry Profile Selected (TPS) : 0x%x\n",
+ da1->tps);
+ printf("Telemetry String Log Size (SLS) : 0x%lx\n",
+ le64_to_cpu(da1->sls));
+ printf("Firmware Revision : ");
for (i = 0; i < 8; i++)
- printf("reserved3 : 0x%x\n", da1->reserved3[i]);
- printf("Firmware Revision : 0x%x\n", le16_to_cpu(da1->fw_revision));
- for (i = 0; i < 32; i++)
- printf("reserved4 : 0x%x\n", da1->reserved4[i]);
- printf("Data Area 1 Statistic Start : 0x%x\n", le16_to_cpu(da1->da1_stat_start));
- printf("Data Area 1 Statistic Size : 0x%x\n", le16_to_cpu(da1->da1_stat_size));
- printf("Data Area 2 Statistic Start : 0x%x\n", le16_to_cpu(da1->da2_stat_start));
- printf("Data Area 2 Statistic Size : 0x%x\n", le16_to_cpu(da1->da2_stat_size));
- for (i = 0; i < 32; i++)
- printf("reserved5 : 0x%x\n", da1->reserved5[i]);
- for (i = 0; i < 17; i++){
- printf("Event FIFO %d Data Area : 0x%x\n", i, da1->event_fifo_da[i]);
- printf("Event FIFO %d Start : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_start[i]));
- printf("Event FIFO %d Size : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_size[i]));
- }
- for (i = 0; i < 80; i++)
- printf("reserved6 : 0x%x\n", da1->reserved6[i]);
- for (i = 0; i < 512; i++){
- printf("SMART / Health Information : 0x%x\n", da1->smart_health_info[i]);
- printf("SMART / Health Information Extended : 0x%x\n", da1->smart_health_info_extended[i]);
- }
- printf("===============================================\n\n");
- }
-}
-static void print_telemetry_da1_stat(__u8 *da1_stat, int tele_type, __u16 buf_size)
-{
- if (da1_stat) {
- unsigned int i = 0;
- if (tele_type == TELEMETRY_TYPE_HOST)
- printf("============ Telemetry Host Data area 1 Statistics ============\n");
- else
- printf("========= Telemetry Controller Data area 1 Statistics =========\n");
- while((i + 8) < buf_size) {
- printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8));
- printf("Statistics info : 0x%x\n", da1_stat[i+2]);
- printf("NS info : 0x%x\n", da1_stat[i+3]);
- printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8));
- printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8));
- i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4);
- }
- printf("===============================================\n\n");
- }
-}
-static void print_telemetry_da1_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size)
-{
- if (da1_fifo) {
- unsigned int i = 0;
- if (tele_type == TELEMETRY_TYPE_HOST)
- printf("============ Telemetry Host Data area 1 FIFO ============\n");
- else
- printf("========= Telemetry Controller Data area 1 FIFO =========\n");
- while((i + 4) < buf_size) {
- printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]);
- printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8));
- printf("Event Data Size : 0x%x\n", da1_fifo[3]);
- i = 4 + ((da1_fifo[3]) * 4);
+ printf("%c", (char)da1->fw_revision[i]);
+ printf("\n");
+ printf("Data Area 1 Statistic Start : 0x%lx\n",
+ le64_to_cpu(da1->da1_stat_start));
+ printf("Data Area 1 Statistic Size : 0x%lx\n",
+ le64_to_cpu(da1->da1_stat_size));
+ printf("Data Area 2 Statistic Start : 0x%lx\n",
+ le64_to_cpu(da1->da2_stat_start));
+ printf("Data Area 2 Statistic Size : 0x%lx\n",
+ le64_to_cpu(da1->da2_stat_size));
+ for (i = 0; i < 16; i++) {
+ printf("Event FIFO %d Data Area : 0x%x\n",
+ i, da1->event_fifo_da[i]);
+ printf("Event FIFO %d Start : 0x%"PRIx64"\n",
+ i, le64_to_cpu(da1->event_fifos[i].start));
+ printf("Event FIFO %d Size : 0x%"PRIx64"\n",
+ i, le64_to_cpu(da1->event_fifos[i].size));
}
+ printf("SMART / Health Information :\n");
+ printf("0x");
+ for (i = 0; i < 512; i++)
+ printf("%02x", da1->smart_health_info[i]);
+ printf("\n");
+
+ printf("SMART / Health Information Extended :\n");
+ printf("0x");
+ for (i = 0; i < 512; i++)
+ printf("%02x", da1->smart_health_info_extended[i]);
+ printf("\n");
+
printf("===============================================\n\n");
}
}
-static void print_telemetry_da2_stat(__u8 *da1_stat, int tele_type, __u16 buf_size)
+static void print_telemetry_da_stat(struct telemetry_stats_desc *da_stat,
+ int tele_type,
+ __u16 buf_size,
+ __u8 data_area)
{
- if (da1_stat) {
+ if (da_stat) {
unsigned int i = 0;
+ struct telemetry_stats_desc *next_da_stat = da_stat;
+
if (tele_type == TELEMETRY_TYPE_HOST)
- printf("============ Telemetry Host Data area 1 Statistics ============\n");
+ printf("============ Telemetry Host Data Area %d Statistics ============\n",
+ data_area);
else
- printf("========= Telemetry Controller Data area 1 Statistics =========\n");
- while((i + 8) < buf_size) {
- printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8));
- printf("Statistics info : 0x%x\n", da1_stat[i+2]);
- printf("NS info : 0x%x\n", da1_stat[i+3]);
- printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8));
- printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8));
- i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4);
+ printf("========= Telemetry Controller Data Area %d Statistics =========\n",
+ data_area);
+ while ((i + 8) < buf_size) {
+ print_stats_desc(next_da_stat);
+ i += 8 + ((next_da_stat->size) * 4);
+ next_da_stat = (struct telemetry_stats_desc *)((__u64)da_stat + i);
+
+ if ((next_da_stat->id == 0) && (next_da_stat->size == 0))
+ break;
}
printf("===============================================\n\n");
}
}
-static void print_telemetry_da2_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size)
+static void print_telemetry_da_fifo(struct telemetry_event_desc *da_fifo,
+ __le64 buf_size,
+ int tele_type,
+ int da,
+ int index)
{
- if (da1_fifo) {
+ if (da_fifo) {
unsigned int i = 0;
+ struct telemetry_event_desc *next_da_fifo = da_fifo;
+
if (tele_type == TELEMETRY_TYPE_HOST)
- printf("============ Telemetry Host Data area 1 Statistics ============\n");
+ printf("========= Telemetry Host Data area %d Event FIFO %d =========\n",
+ da, index);
else
- printf("========= Telemetry Controller Data area 1 Statistics =========\n");
- while((i + 4) < buf_size) {
- printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]);
- printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8));
- printf("Event Data Size : 0x%x\n", da1_fifo[3]);
- i = 4 + ((da1_fifo[3]) * 4);
+ printf("====== Telemetry Controller Data area %d Event FIFO %d ======\n",
+ da, index);
+
+
+ while ((i + 4) < buf_size) {
+ /* Print Event Data */
+ print_telemetry_fifo_event(next_da_fifo->class, /* Event class type */
+ next_da_fifo->id, /* Event ID */
+ next_da_fifo->size, /* Event data size */
+ (__u8 *)&next_da_fifo->data); /* Event data */
+
+ i += (4 + (next_da_fifo->size * 4));
+ next_da_fifo = (struct telemetry_event_desc *)((__u64)da_fifo + i);
}
printf("===============================================\n\n");
}
}
-
static int extract_dump_get_log(struct nvme_dev *dev, char *featurename, char *filename, char *sn,
int dumpsize, int transfersize, __u32 nsid, __u8 log_id,
__u8 lsp, __u64 offset, bool rae)
@@ -1146,10 +1183,12 @@ static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn,
enum TELEMETRY_TYPE tele_type, int data_area, bool header_print)
{
__u32 err = 0, nsid = 0;
- __u8 lsp = 0, rae = 0;
+ __le64 da1_sz = 512, m_512_sz = 0, da1_off = 0, m_512_off = 0, diff = 0,
+ temp_sz = 0, temp_ofst = 0;
+ __u8 lsp = 0, rae = 0, flag = 0;
+ __u8 data[TELEMETRY_HEADER_SIZE] = { 0 };
unsigned int i = 0;
- char data[TELEMETRY_TRANSFER_SIZE] = { 0 };
- char data1[1536] = { 0 };
+ char data1[TELEMETRY_DATA_SIZE] = { 0 };
char *featurename = 0;
struct telemetry_initiated_log *logheader = (struct telemetry_initiated_log *)data;
struct telemetry_data_area_1 *da1 = (struct telemetry_data_area_1 *)data1;
@@ -1172,51 +1211,245 @@ static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn,
rae = 1;
}
- err = get_telemetry_header(dev, nsid, tele_type, TELEMETRY_HEADER_SIZE,
- (void *)data, lsp, rae);
- if (err)
+ /* Get the telemetry header */
+ err = get_telemetry_data(dev, nsid, tele_type, TELEMETRY_HEADER_SIZE,
+ (void *)data, lsp, rae, 0);
+ if (err) {
+ printf("get_telemetry_header failed, err: %d.\n", err);
return err;
+ }
if (header_print)
print_telemetry_header(logheader, tele_type);
- err = get_telemetry_data(dev, nsid, tele_type, 1536,
+
+ /* Get the telemetry data */
+ err = get_telemetry_data(dev, nsid, tele_type, TELEMETRY_DATA_SIZE,
(void *)data1, lsp, rae, 512);
- if (err)
+ if (err) {
+ printf("get_telemetry_data failed for type: 0x%x, err: %d.\n", tele_type, err);
return err;
+ }
+
print_telemetry_data_area_1(da1, tele_type);
- char *da1_stat = calloc((da1->da1_stat_size * 4), sizeof(char));
- err = get_telemetry_data(dev, nsid, tele_type, (da1->da1_stat_size) * 4,
- (void *)da1_stat, lsp, rae, (da1->da1_stat_start) * 4);
- if (err)
- return err;
- print_telemetry_da1_stat((void *)da1_stat, tele_type, (da1->da1_stat_size) * 4);
- for (i = 0; i < 17 ; i++){
- if (da1->event_fifo_da[i] == 1){
- char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char));
- err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4,
- (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4);
- if (err)
+
+ /* Print the Data Area 1 Stats */
+ if (da1->da1_stat_size != 0) {
+ diff = 0;
+ da1_sz = (da1->da1_stat_size) * 4;
+ m_512_sz = (da1->da1_stat_size) * 4;
+ da1_off = (da1->da1_stat_start) * 4;
+ m_512_off = (da1->da1_stat_start) * 4;
+ temp_sz = (da1->da1_stat_size) * 4;
+ temp_ofst = (da1->da1_stat_start) * 4;
+ flag = 0;
+
+ if ((da1_off % 512) > 0) {
+ m_512_off = (__le64) ((da1_off / 512));
+ da1_off = m_512_off * 512;
+ diff = temp_ofst - da1_off;
+ flag = 1;
+ }
+
+ if (da1_sz < 512)
+ da1_sz = 512;
+ else if ((da1_sz % 512) > 0) {
+ if (flag == 0) {
+ m_512_sz = (__le64) ((da1_sz / 512) + 1);
+ da1_sz = m_512_sz * 512;
+ } else {
+ if (diff < 512)
+ diff = 1;
+ else
+ diff = (diff / 512) * 512;
+
+ m_512_sz = (__le64) ((da1_sz / 512) + 1 + diff + 1);
+ da1_sz = m_512_sz * 512;
+ }
+ }
+
+ char *da1_stat = calloc(da1_sz, sizeof(char));
+
+ err = get_telemetry_data(dev, nsid, tele_type, da1_sz,
+ (void *)da1_stat, lsp, rae, da1_off);
+ if (err) {
+ printf("get_telemetry_data da1 stats failed, err: %d.\n", err);
+ return err;
+ }
+
+ print_telemetry_da_stat((void *)(da1_stat + (temp_ofst - da1_off)),
+ tele_type, (da1->da1_stat_size) * 4, 1);
+ }
+
+ /* Print the Data Area 1 Event FIFO's */
+ for (i = 0; i < 16 ; i++) {
+ if ((da1->event_fifo_da[i] == 1) && (da1->event_fifos[i].size != 0)) {
+ diff = 0;
+ da1_sz = da1->event_fifos[i].size * 4;
+ m_512_sz = da1->event_fifos[i].size * 4;
+ da1_off = da1->event_fifos[i].start * 4;
+ m_512_off = da1->event_fifos[i].start * 4;
+ temp_sz = da1->event_fifos[i].size * 4;
+ temp_ofst = da1->event_fifos[i].start * 4;
+ flag = 0;
+
+ if ((da1_off % 512) > 0) {
+ m_512_off = (__le64) ((da1_off / 512));
+ da1_off = m_512_off * 512;
+ diff = temp_ofst - da1_off;
+ flag = 1;
+ }
+
+ if (da1_sz < 512)
+ da1_sz = 512;
+ else if ((da1_sz % 512) > 0) {
+ if (flag == 0) {
+ m_512_sz = (__le64) ((da1_sz / 512) + 1);
+ da1_sz = m_512_sz * 512;
+ } else {
+ if (diff < 512)
+ diff = 1;
+ else
+ diff = (diff / 512) * 512;
+
+ m_512_sz = (__le64) ((da1_sz / 512) + 1 + diff + 1);
+ da1_sz = m_512_sz * 512;
+ }
+ }
+
+ char *da1_fifo = calloc(da1_sz, sizeof(char));
+
+ err = get_telemetry_data(dev, nsid, tele_type,
+ (da1->event_fifos[i].size) * 4,
+ (void *)da1_fifo, lsp, rae, da1_off);
+ if (err) {
+ printf("get_telemetry_data da1 event fifos failed, err: %d.\n",
+ err);
return err;
- print_telemetry_da1_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4);
+ }
+ print_telemetry_da_fifo((void *)(da1_fifo + (temp_ofst - da1_off)),
+ temp_sz,
+ tele_type,
+ da1->event_fifo_da[i],
+ i);
}
}
- char *da2_stat = calloc((da1->da2_stat_size * 4), sizeof(char));
- err = get_telemetry_data(dev, nsid, tele_type, (da1->da2_stat_size) * 4,
- (void *)da2_stat, lsp, rae, (da1->da2_stat_start) * 4);
- if (err)
- return err;
- print_telemetry_da2_stat((void *)da2_stat, tele_type, (da1->da2_stat_size) * 4);
- for (i = 0; i < 17 ; i++){
- if (da1->event_fifo_da[i] == 2){
- char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char));
- err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4,
- (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4);
- if (err)
+
+ /* Print the Data Area 2 Stats */
+ if (da1->da2_stat_size != 0) {
+ da1_off = (da1->da2_stat_start) * 4;
+ temp_ofst = (da1->da2_stat_start) * 4;
+ da1_sz = (da1->da2_stat_size) * 4;
+ diff = 0;
+ flag = 0;
+
+ if (da1->da2_stat_start == 0) {
+ da1_off = 512 + (logheader->DataArea1LastBlock * 512);
+ temp_ofst = 512 + (le16_to_cpu(logheader->DataArea1LastBlock) * 512);
+ if ((da1_off % 512) == 0) {
+ m_512_off = (__le64) (((da1_off) / 512));
+ da1_off = m_512_off * 512;
+ diff = temp_ofst - da1_off;
+ flag = 1;
+ }
+ } else {
+
+ if (((da1_off * 4) % 512) > 0) {
+ m_512_off = (__le64) ((((da1->da2_stat_start) * 4) / 512));
+ da1_off = m_512_off * 512;
+ diff = ((da1->da2_stat_start) * 4) - da1_off;
+ flag = 1;
+ }
+ }
+
+ if (da1_sz < 512)
+ da1_sz = 512;
+ else if ((da1_sz % 512) > 0) {
+ if (flag == 0) {
+ m_512_sz = (__le64) ((da1->da2_stat_size / 512) + 1);
+ da1_sz = m_512_sz * 512;
+ } else {
+ if (diff < 512)
+ diff = 1;
+ else
+ diff = (diff / 512) * 512;
+ m_512_sz = (__le64) ((da1->da2_stat_size / 512) + 1 + diff + 1);
+ da1_sz = m_512_sz * 512;
+ }
+ }
+
+ char *da2_stat = calloc(da1_sz, sizeof(char));
+
+ err = get_telemetry_data(dev, nsid, tele_type, da1_sz,
+ (void *)da2_stat, lsp, rae, da1_off);
+ if (err) {
+ printf("get_telemetry_data da2 stats failed, err: %d.\n", err);
+ return err;
+ }
+
+ print_telemetry_da_stat((void *)(da2_stat + (temp_ofst - da1_off)),
+ tele_type,
+ (da1->da2_stat_size) * 4,
+ 2);
+ }
+
+ /* Print the Data Area 2 Event FIFO's */
+ for (i = 0; i < 16 ; i++) {
+ if ((da1->event_fifo_da[i] == 2) && (da1->event_fifos[i].size != 0)) {
+ diff = 0;
+ da1_sz = da1->event_fifos[i].size * 4;
+ m_512_sz = da1->event_fifos[i].size * 4;
+ da1_off = da1->event_fifos[i].start * 4;
+ m_512_off = da1->event_fifos[i].start * 4;
+ temp_sz = da1->event_fifos[i].size * 4;
+ temp_ofst = da1->event_fifos[i].start * 4;
+ flag = 0;
+
+ if ((da1_off % 512) > 0) {
+ m_512_off = (__le64) ((da1_off / 512));
+ da1_off = m_512_off * 512;
+ diff = temp_ofst - da1_off;
+ flag = 1;
+ }
+
+ if (da1_sz < 512)
+ da1_sz = 512;
+ else if ((da1_sz % 512) > 0) {
+ if (flag == 0) {
+ m_512_sz = (__le64) ((da1_sz / 512) + 1);
+ da1_sz = m_512_sz * 512;
+ }
+
+ else {
+ if (diff < 512)
+ diff = 1;
+ else
+ diff = (diff / 512) * 512;
+
+ m_512_sz = (__le64) ((da1_sz / 512) + 1 + diff + 1);
+ da1_sz = m_512_sz * 512;
+ }
+ }
+
+ char *da1_fifo = calloc(da1_sz, sizeof(char));
+
+ err = get_telemetry_data(dev, nsid, tele_type,
+ (da1->event_fifos[i].size) * 4,
+ (void *)da1_fifo, lsp, rae, da1_off);
+ if (err) {
+ printf("get_telemetry_data da2 event fifos failed, err: %d.\n",
+ err);
return err;
- print_telemetry_da2_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4);
+ }
+ print_telemetry_da_fifo((void *)(da1_fifo + (temp_ofst - da1_off)),
+ temp_sz,
+ tele_type,
+ da1->event_fifo_da[i],
+ i);
}
}
+ printf("------------------------------FIFO End---------------------------\n");
+
switch (data_area) {
case 1:
offset = TELEMETRY_HEADER_SIZE;
@@ -1252,43 +1485,283 @@ static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn,
return err;
}
+static int get_telemetry_log_page_data(struct nvme_dev *dev, int tele_type)
+{
+ char file_path[PATH_MAX];
+ void *telemetry_log;
+ const size_t bs = 512;
+ struct nvme_telemetry_log *hdr;
+ size_t full_size, offset = bs;
+ int err, fd;
+
+ if ((tele_type == TELEMETRY_TYPE_HOST_0) || (tele_type == TELEMETRY_TYPE_HOST_1))
+ tele_type = TELEMETRY_TYPE_HOST;
+
+ int log_id = (tele_type == TELEMETRY_TYPE_HOST ? NVME_LOG_LID_TELEMETRY_HOST :
+ NVME_LOG_LID_TELEMETRY_CTRL);
+
+ hdr = malloc(bs);
+ telemetry_log = malloc(bs);
+ if (!hdr || !telemetry_log) {
+ fprintf(stderr, "Failed to allocate %zu bytes for log: %s\n",
+ bs, strerror(errno));
+ err = -ENOMEM;
+ goto exit_status;
+ }
+ memset(hdr, 0, bs);
+
+ sprintf(file_path, DEFAULT_TELEMETRY_BIN);
+ fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open output file %s: %s!\n",
+ file_path, strerror(errno));
+ err = fd;
+ goto exit_status;
+ }
+
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = hdr,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = log_id,
+ .len = bs,
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_TELEM_HOST_LSP_CREATE,
+ .uuidx = NVME_UUID_NONE,
+ .rae = true,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (err < 0)
+ nvme_show_error("Failed to fetch the log from drive.\n");
+ else if (err > 0) {
+ nvme_show_status(err);
+ nvme_show_error("Failed to fetch telemetry-header. Error:%d.\n", err);
+ goto close_fd;
+ }
+
+ err = write(fd, (void *)hdr, bs);
+ if (err != bs) {
+ nvme_show_error("Failed to write data to file.\n");
+ goto close_fd;
+ }
+
+ full_size = (le16_to_cpu(hdr->dalb3) * bs) + offset;
+
+ while (offset != full_size) {
+ args.log = telemetry_log;
+ args.lpo = offset;
+ args.lsp = NVME_LOG_LSP_NONE;
+ err = nvme_get_log(&args);
+ if (err < 0) {
+ nvme_show_error("Failed to fetch the log from drive.\n");
+ break;
+ } else if (err > 0) {
+ nvme_show_error("Failed to fetch telemetry-log.\n");
+ nvme_show_status(err);
+ break;
+ }
+
+ err = write(fd, (void *)telemetry_log, bs);
+ if (err != bs) {
+ nvme_show_error("Failed to write data to file.\n");
+ break;
+ }
+ err = 0;
+ offset += bs;
+ }
+
+close_fd:
+ close(fd);
+exit_status:
+ free(hdr);
+ free(telemetry_log);
+
+ return err;
+}
+
+static int get_c9_log_page_data(struct nvme_dev *dev, int print_data, int save_bin)
+{
+ int ret = 0, fd;
+ __le64 stat_id_str_table_ofst = 0;
+ __le64 event_str_table_ofst = 0;
+ __le64 vu_event_str_table_ofst = 0;
+ __le64 ascii_table_ofst = 0;
+ char file_path[PATH_MAX];
+
+ header_data = (__u8 *)malloc(sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN);
+ if (!header_data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(header_data, 0, sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE,
+ C9_TELEMETRY_STR_LOG_LEN, header_data);
+
+ if (!ret) {
+ log_data = (struct telemetry_str_log_format *)header_data;
+ if (print_data) {
+ printf("Statistics Identifier String Table Size = %lld\n",
+ log_data->sitsz);
+ printf("Event String Table Size = %lld\n", log_data->estsz);
+ printf("VU Event String Table Size = %lld\n", log_data->vu_eve_st_sz);
+ printf("ASCII Table Size = %lld\n", log_data->asctsz);
+ }
+
+ //Calculating the offset for dynamic fields.
+
+ stat_id_str_table_ofst = log_data->sits * 4;
+ event_str_table_ofst = log_data->ests * 4;
+ vu_event_str_table_ofst = log_data->vu_eve_sts * 4;
+ ascii_table_ofst = log_data->ascts * 4;
+ total_log_page_sz = C9_TELEMETRY_STR_LOG_LEN +
+ (log_data->sitsz * 4) + (log_data->estsz * 4) +
+ (log_data->vu_eve_st_sz * 4) + (log_data->asctsz * 4);
+
+ if (print_data) {
+ printf("stat_id_str_table_ofst = %lld\n", stat_id_str_table_ofst);
+ printf("event_str_table_ofst = %lld\n", event_str_table_ofst);
+ printf("vu_event_str_table_ofst = %lld\n", vu_event_str_table_ofst);
+ printf("ascii_table_ofst = %lld\n", ascii_table_ofst);
+ printf("total_log_page_sz = %lld\n", total_log_page_sz);
+ }
+
+ pC9_string_buffer = (__u8 *)malloc(sizeof(__u8) * total_log_page_sz);
+ if (!pC9_string_buffer) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(pC9_string_buffer, 0, sizeof(__u8) * total_log_page_sz);
+
+ ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE,
+ total_log_page_sz, pC9_string_buffer);
+ } else
+ fprintf(stderr, "ERROR : OCP : Unable to read C9 data.\n");
+
+ if (save_bin) {
+ sprintf(file_path, DEFAULT_STRING_BIN);
+ fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open output file %s: %s!\n",
+ file_path, strerror(errno));
+ goto exit_status;
+ }
+
+ ret = write(fd, (void *)pC9_string_buffer, total_log_page_sz);
+ if (ret != total_log_page_sz)
+ fprintf(stderr, "Failed to flush all data to file!\n");
+
+ close(fd);
+ }
+
+exit_status:
+ return 0;
+}
+
+int parse_ocp_telemetry_log(struct ocp_telemetry_parse_options *options)
+{
+ int status = 0;
+ long telemetry_buffer_size = 0;
+ long string_buffer_size = 0;
+ enum nvme_print_flags fmt;
+ unsigned char log_id;
+
+ if (options->telemetry_log) {
+ if (strstr((const char *)options->telemetry_log, "bin")) {
+ // Read the data from the telemetry binary file
+ ptelemetry_buffer =
+ read_binary_file(NULL, (const char *)options->telemetry_log,
+ &telemetry_buffer_size, 1);
+ if (ptelemetry_buffer == NULL) {
+ nvme_show_error("Failed to read telemetry-log.\n");
+ return -1;
+ }
+ }
+ } else {
+ nvme_show_error("telemetry-log is empty.\n");
+ return -1;
+ }
+
+ log_id = ptelemetry_buffer[0];
+ if ((log_id != NVME_LOG_LID_TELEMETRY_HOST) && (log_id != NVME_LOG_LID_TELEMETRY_CTRL)) {
+ nvme_show_error("Invalid LogPageId [0x%02X]\n", log_id);
+ return -1;
+ }
+
+ if (options->string_log) {
+ // Read the data from the string binary file
+ if (strstr((const char *)options->string_log, "bin")) {
+ pstring_buffer = read_binary_file(NULL, (const char *)options->string_log,
+ &string_buffer_size, 1);
+ if (pstring_buffer == NULL) {
+ nvme_show_error("Failed to read string-log.\n");
+ return -1;
+ }
+ }
+ } else {
+ nvme_show_error("string-log is empty.\n");
+ return -1;
+ }
+
+ status = validate_output_format(options->output_format, &fmt);
+ if (status < 0) {
+ nvme_show_error("Invalid output format\n");
+ return status;
+ }
+
+ switch (fmt) {
+ case NORMAL:
+ print_ocp_telemetry_normal(options);
+ break;
+ case JSON:
+ print_ocp_telemetry_json(options);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int ocp_telemetry_log(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
- struct nvme_dev *dev;
- int err = 0;
- const char *desc = "Retrieve and save telemetry log.";
- const char *type = "Telemetry Type; 'host[Create bit]' or 'controller'";
- const char *area = "Telemetry Data Area; 1 or 3";
- const char *file = "Output file name with path;\n"
+ const char *desc = "Retrieve and parse OCP Telemetry log.";
+ const char *telemetry_log = "Telemetry log binary;\n 'host.bin' or 'controller.bin'";
+ const char *string_log = "String log binary; 'C9.bin'";
+ const char *output_file = "Output file name with path;\n"
"e.g. '-o ./path/name'\n'-o ./path1/path2/';\n"
"If requested path does not exist, the directory will be newly created.";
+ const char *output_format = "output format normal|json";
+ const char *data_area = "Telemetry Data Area; 1 or 2;\n"
+ "e.g. '-a 1 for Data Area 1.'\n'-a 2 for Data Areas 1 and 2.';\n";
+ const char *telemetry_type = "Telemetry Type; 'host' or 'controller'";
+ struct nvme_dev *dev;
+ int err = 0;
__u32 nsid = NVME_NSID_ALL;
struct stat nvme_stat;
char sn[21] = {0,};
struct nvme_id_ctrl ctrl;
bool is_support_telemetry_controller;
-
+ struct ocp_telemetry_parse_options opt;
int tele_type = 0;
int tele_area = 0;
- struct config {
- char *type;
- int area;
- char *file;
- };
-
- struct config cfg = {
- .type = NULL,
- .area = 0,
- .file = NULL,
- };
-
OPT_ARGS(opts) = {
- OPT_STR("telemetry_type", 't', &cfg.type, type),
- OPT_INT("telemetry_data_area", 'a', &cfg.area, area),
- OPT_FILE("output-file", 'o', &cfg.file, file),
+ OPT_STR("telemetry-log", 'l', &opt.telemetry_log, telemetry_log),
+ OPT_STR("string-log", 's', &opt.string_log, string_log),
+ OPT_FILE("output-file", 'o', &opt.output_file, output_file),
+ OPT_FMT("output-format", 'f', &opt.output_format, output_format),
+ OPT_INT("data-area", 'a', &opt.data_area, data_area),
+ OPT_STR("telemetry-type", 't', &opt.telemetry_type, telemetry_type),
OPT_END()
};
@@ -1314,36 +1787,84 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd,
is_support_telemetry_controller = ((ctrl.lpa & 0x8) >> 3);
- if (!cfg.type && !cfg.area) {
- tele_type = TELEMETRY_TYPE_NONE;
- tele_area = 0;
- } else if (cfg.type && cfg.area) {
- if (!strcmp(cfg.type, "host0"))
+ if (!opt.data_area) {
+ nvme_show_result("Missing data-area. Using default data area 1.\n");
+ opt.data_area = DATA_AREA_1;//Default data area 1
+ } else if (opt.data_area != 1 && opt.data_area != 2) {
+ nvme_show_result("Invalid data-area specified. Please specify 1 or 2.\n");
+ goto out;
+ }
+
+ tele_area = opt.data_area;
+
+ if (opt.telemetry_type) {
+ if (!strcmp(opt.telemetry_type, "host0"))
tele_type = TELEMETRY_TYPE_HOST_0;
- else if (!strcmp(cfg.type, "host1"))
+ else if (!strcmp(opt.telemetry_type, "host1"))
tele_type = TELEMETRY_TYPE_HOST_1;
- else if (!strcmp(cfg.type, "controller"))
+ else if (!strcmp(opt.telemetry_type, "host"))
+ tele_type = TELEMETRY_TYPE_HOST;
+ else if (!strcmp(opt.telemetry_type, "controller"))
tele_type = TELEMETRY_TYPE_CONTROLLER;
+ else {
+ nvme_show_error("telemetry-type should be host or controller.\n");
+ goto out;
+ }
+ } else {
+ tele_type = TELEMETRY_TYPE_HOST; //Default Type - Host
+ nvme_show_result("Missing telemetry-type. Using default - host.\n");
+ }
- tele_area = cfg.area;
+ if (!opt.telemetry_log) {
+ nvme_show_result("\nMissing telemetry-log. Fetching from drive...\n");
+ err = get_telemetry_log_page_data(dev, tele_type);//Pull Telemetry log
+ if (err) {
+ nvme_show_error("Failed to fetch telemetry-log from the drive.\n");
+ goto out;
+ }
+ nvme_show_result("telemetry.bin generated. Proceeding with next steps.\n");
+ opt.telemetry_log = DEFAULT_TELEMETRY_BIN;
+ }
- if ((tele_area != 1 && tele_area != 3) ||
- (tele_type == TELEMETRY_TYPE_CONTROLLER && tele_area != 3)) {
- printf("\nUnsupported parameters entered.\n");
- printf("Possible combinations; {'host0',1}, {'host0',3}, {'host1',1}, {'host1',3}, {'controller',3}\n");
- return err;
+ if (!opt.string_log) {
+ nvme_show_result("Missing string-log. Fetching from drive...\n");
+ err = get_c9_log_page_data(dev, 0, 1); //Pull String log
+ if (err) {
+ nvme_show_error("Failed to fetch string-log from the drive.\n");
+ goto out;
}
- } else {
- printf("\nShould provide these all; 'telemetry_type' and 'telemetry_data_area'\n");
- return err;
+ nvme_show_result("string.bin generated. Proceeding with next steps.\n");
+ opt.string_log = DEFAULT_STRING_BIN;
+ }
+
+ if (!opt.output_format) {
+ nvme_show_result("Missing format. Using default format - JSON.\n");
+ opt.output_format = DEFAULT_OUTPUT_FORMAT_JSON;
}
- if (tele_type == TELEMETRY_TYPE_NONE) {
+ switch (tele_type) {
+ case TELEMETRY_TYPE_HOST: {
+ printf("Extracting Telemetry Host Dump (Data Area %d)...\n", tele_area);
+ err = parse_ocp_telemetry_log(&opt);
+ if (err)
+ nvme_show_result("Status:(%x)\n", err);
+ }
+ break;
+ case TELEMETRY_TYPE_CONTROLLER: {
+ printf("Extracting Telemetry Controller Dump (Data Area %d)...\n", tele_area);
+ if (is_support_telemetry_controller == true) {
+ err = parse_ocp_telemetry_log(&opt);
+ if (err)
+ nvme_show_result("Status:(%x)\n", err);
+ }
+ }
+ break;
+ case TELEMETRY_TYPE_NONE: {
printf("\n-------------------------------------------------------------\n");
/* Host 0 (lsp == 0) must be executed before Host 1 (lsp == 1). */
printf("\nExtracting Telemetry Host 0 Dump (Data Area 1)...\n");
- err = get_telemetry_dump(dev, cfg.file, sn,
+ err = get_telemetry_dump(dev, opt.output_file, sn,
TELEMETRY_TYPE_HOST_0, 1, true);
if (err)
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
@@ -1352,7 +1873,7 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd,
printf("\nExtracting Telemetry Host 0 Dump (Data Area 3)...\n");
- err = get_telemetry_dump(dev, cfg.file, sn,
+ err = get_telemetry_dump(dev, opt.output_file, sn,
TELEMETRY_TYPE_HOST_0, 3, false);
if (err)
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
@@ -1361,7 +1882,7 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd,
printf("\nExtracting Telemetry Host 1 Dump (Data Area 1)...\n");
- err = get_telemetry_dump(dev, cfg.file, sn,
+ err = get_telemetry_dump(dev, opt.output_file, sn,
TELEMETRY_TYPE_HOST_1, 1, true);
if (err)
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
@@ -1370,7 +1891,7 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd,
printf("\nExtracting Telemetry Host 1 Dump (Data Area 3)...\n");
- err = get_telemetry_dump(dev, cfg.file, sn,
+ err = get_telemetry_dump(dev, opt.output_file, sn,
TELEMETRY_TYPE_HOST_1, 3, false);
if (err)
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
@@ -1380,35 +1901,35 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd,
printf("\nExtracting Telemetry Controller Dump (Data Area 3)...\n");
if (is_support_telemetry_controller == true) {
- err = get_telemetry_dump(dev, cfg.file, sn,
+ err = get_telemetry_dump(dev, opt.output_file, sn,
TELEMETRY_TYPE_CONTROLLER, 3, true);
if (err)
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
}
printf("\n-------------------------------------------------------------\n");
- } else if (tele_type == TELEMETRY_TYPE_CONTROLLER) {
- printf("Extracting Telemetry Controller Dump (Data Area %d)...\n", tele_area);
-
- if (is_support_telemetry_controller == true) {
- err = get_telemetry_dump(dev, cfg.file, sn, tele_type, tele_area, true);
- if (err)
- fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
- }
- } else {
+ }
+ break;
+ case TELEMETRY_TYPE_HOST_0:
+ case TELEMETRY_TYPE_HOST_1:
+ default: {
printf("Extracting Telemetry Host(%d) Dump (Data Area %d)...\n",
(tele_type == TELEMETRY_TYPE_HOST_0) ? 0 : 1, tele_area);
- err = get_telemetry_dump(dev, cfg.file, sn, tele_type, tele_area, true);
+ err = get_telemetry_dump(dev, opt.output_file, sn, tele_type, tele_area, true);
if (err)
fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
}
+ break;
+ }
- printf("telemetry-log done.\n");
-
-return err;
+ printf("ocp internal-log command completed.\n");
+out:
+ dev_close(dev);
+ return err;
}
+
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@@ -1511,7 +2032,7 @@ static void ocp_print_c5_log_binary(struct unsupported_requirement_log *log_data
static int get_c5_log_page(struct nvme_dev *dev, char *format)
{
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
int ret;
__u8 *data;
int i;
@@ -1585,7 +2106,6 @@ out:
return ret;
}
-
static int ocp_unsupported_requirements_log(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
@@ -1738,7 +2258,7 @@ static void ocp_print_c1_log_binary(struct ocp_error_recovery_log_page *log_data
static int get_c1_log_page(struct nvme_dev *dev, char *format)
{
struct ocp_error_recovery_log_page *log_data;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
int ret;
__u8 *data;
int i, j;
@@ -1954,7 +2474,7 @@ static void ocp_print_c4_log_binary(struct ocp_device_capabilities_log_page *log
static int get_c4_log_page(struct nvme_dev *dev, char *format)
{
struct ocp_device_capabilities_log_page *log_data;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
int ret;
__u8 *data;
int i, j;
@@ -2060,6 +2580,90 @@ static int ocp_device_capabilities_log(int argc, char **argv, struct command *cm
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
+/// Set Telemetry Profile (Feature Identifier C8h) Set Feature
+
+static int ocp_set_telemetry_profile(struct nvme_dev *dev, __u8 tps)
+{
+ __u32 result;
+ int err;
+ __u8 uuid_index = 0;
+
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ nvme_show_error("ERROR: No OCP UUID index found");
+ return err;
+ }
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = 0xC8,
+ .nsid = 0xFFFFFFFF,
+ .cdw11 = tps,
+ .cdw12 = 0,
+ .save = true,
+ .uuidx = uuid_index,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ nvme_show_perror("Set Telemetry Profile");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully Set Telemetry Profile (feature: 0xC8) to below values\n");
+ printf("Telemetry Profile Select: 0x%x\n", tps);
+ }
+
+ return err;
+}
+
+static int ocp_set_telemetry_profile_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Set Telemetry Profile (Feature Identifier C8h) Set Feature.";
+ const char *tps = "Telemetry Profile Select for device debug data collection";
+ struct nvme_dev *dev;
+ int err;
+
+ struct config {
+ __u8 tps;
+ };
+
+ struct config cfg = {
+ .tps = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("telemetry-profile-select", 't', &cfg.tps, tps),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (argconfig_parse_seen(opts, "telemetry-profile-select"))
+ err = ocp_set_telemetry_profile(dev, cfg.tps);
+ else
+ nvme_show_error("Telemetry Profile Select is a required argument");
+
+ dev_close(dev);
+
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
/// DSSD Power State (Feature Identifier C7h) Set Feature
static int set_dssd_power_state(struct nvme_dev *dev, const __u32 nsid,
@@ -2068,7 +2672,7 @@ static int set_dssd_power_state(struct nvme_dev *dev, const __u32 nsid,
{
__u32 result;
int err;
- int uuid_index = 0;
+ __u8 uuid_index = 0;
if (uuid) {
/* OCP 2.0 requires UUID index support */
@@ -2143,7 +2747,7 @@ static int set_dssd_power_state_feature(int argc, char **argv, struct command *c
if (err)
return err;
- if (argconfig_parse_seen(opts, "power state"))
+ if (argconfig_parse_seen(opts, "power-state"))
err = set_dssd_power_state(dev, nsid, fid, cfg.power_state,
cfg.save,
!argconfig_parse_seen(opts, "no-uuid"));
@@ -2157,140 +2761,374 @@ static int set_dssd_power_state_feature(int argc, char **argv, struct command *c
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
+/// DSSD Power State (Feature Identifier C7h) Get Feature
+
+static int get_dssd_power_state(struct nvme_dev *dev, const __u32 nsid,
+ const __u8 fid, __u8 sel, bool uuid)
+{
+ __u32 result;
+ int err;
+ __u8 uuid_index = 0;
+
+ if (uuid) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ nvme_show_error("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .sel = sel,
+ .cdw11 = 0,
+ .uuidx = uuid_index,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_get_features(&args);
+ if (!err) {
+ printf("get-feature:0xC7 %s value: %#08x\n", nvme_select_to_string(sel), result);
+
+ if (sel == NVME_GET_FEATURES_SEL_SUPPORTED)
+ nvme_show_select_result(fid, result);
+ } else {
+ nvme_show_error("Could not get feature: 0xC7 with sel: %d\n", sel);
+ }
+
+ return err;
+}
+
+static int get_dssd_power_state_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Define DSSD Power State (Feature Identifier C7h) Get Feature.";
+ const char *all = "Print out all 3 values at once - Current, Default, and Saved";
+ const char *sel = "[0-3]: current/default/saved/supported/";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xC7;
+ struct nvme_dev *dev;
+ int i, err;
+
+ struct config {
+ __u8 sel;
+ bool all;
+ };
+
+ struct config cfg = {
+ .sel = 0,
+ .all = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("sel", 'S', &cfg.sel, sel),
+ OPT_FLAG("all", 'a', NULL, all),
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (argconfig_parse_seen(opts, "all")) {
+ for (i = 0; i < 3; i++) {
+ err = get_dssd_power_state(dev, nsid, fid, i,
+ !argconfig_parse_seen(opts, "no-uuid"));
+ if (err)
+ break;
+ }
+ } else if (argconfig_parse_seen(opts, "sel"))
+ err = get_dssd_power_state(dev, nsid, fid, cfg.sel,
+ !argconfig_parse_seen(opts, "no-uuid"));
+ else
+ nvme_show_error("Required to have --sel as an argument, or pass the --all flag.");
+
+ dev_close(dev);
+
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
/// plp_health_check_interval
static int set_plp_health_check_interval(int argc, char **argv, struct command *cmd,
- struct plugin *plugin)
-{
-
- const char *desc = "Define Issue Set Feature command (FID : 0xC6) PLP Health Check Interval";
- const char *plp_health_interval = "[31:16]:PLP Health Check Interval";
- const char *save = "Specifies that the controller shall save the attribute";
- const __u32 nsid = 0;
- const __u8 fid = 0xc6;
- struct nvme_dev *dev;
- int err;
- __u32 result;
- int uuid_index = 0;
-
- struct config {
- __le16 plp_health_interval;
- bool save;
- };
-
- struct config cfg = {
- .plp_health_interval = 0,
- .save = false,
- };
-
- OPT_ARGS(opts) = {
- OPT_BYTE("plp_health_interval", 'p', &cfg.plp_health_interval, plp_health_interval),
- OPT_FLAG("save", 's', &cfg.save, save),
- OPT_FLAG("no-uuid", 'n', NULL,
- "Skip UUID index search (UUID index not required for OCP 1.0)"),
- OPT_END()
- };
-
- err = parse_and_open(&dev, argc, argv, desc, opts);
- if (err)
- return err;
-
-
- if (!argconfig_parse_seen(opts, "no-uuid")) {
- /* OCP 2.0 requires UUID index support */
- err = ocp_get_uuid_index(dev, &uuid_index);
- if (err || !uuid_index) {
- printf("ERROR: No OCP UUID index found");
- return err;
- }
- }
-
-
- struct nvme_set_features_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
- .fid = fid,
- .nsid = nsid,
- .cdw11 = cfg.plp_health_interval << 16,
- .cdw12 = 0,
- .save = cfg.save,
- .uuidx = uuid_index,
- .cdw15 = 0,
- .data_len = 0,
- .data = NULL,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .result = &result,
- };
-
- err = nvme_set_features(&args);
- if (err > 0) {
- nvme_show_status(err);
- } else if (err < 0) {
- nvme_show_perror("Define PLP Health Check Interval");
- fprintf(stderr, "Command failed while parsing.\n");
- } else {
- printf("Successfully set the PLP Health Check Interval");
- printf("PLP Health Check Interval: 0x%x\n", cfg.plp_health_interval);
- printf("Save bit Value: 0x%x\n", cfg.save);
- }
- return err;
+ struct plugin *plugin)
+{
+
+ const char *desc = "Define Issue Set Feature command (FID : 0xC6) PLP Health Check Interval";
+ const char *plp_health_interval = "[31:16]:PLP Health Check Interval";
+ const char *save = "Specifies that the controller shall save the attribute";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xc6;
+ struct nvme_dev *dev;
+ int err;
+ __u32 result;
+ __u8 uuid_index = 0;
+
+ struct config {
+ __le16 plp_health_interval;
+ bool save;
+ };
+
+ struct config cfg = {
+ .plp_health_interval = 0,
+ .save = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("plp_health_interval", 'p', &cfg.plp_health_interval, plp_health_interval),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+
+ if (!argconfig_parse_seen(opts, "no-uuid")) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ printf("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = cfg.plp_health_interval << 16,
+ .cdw12 = 0,
+ .save = cfg.save,
+ .uuidx = uuid_index,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ nvme_show_perror("Define PLP Health Check Interval");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully set the PLP Health Check Interval");
+ printf("PLP Health Check Interval: 0x%x\n", cfg.plp_health_interval);
+ printf("Save bit Value: 0x%x\n", cfg.save);
+ }
+ return err;
}
static int get_plp_health_check_interval(int argc, char **argv, struct command *cmd,
- struct plugin *plugin)
-{
-
- const char *desc = "Define Issue Get Feature command (FID : 0xC6) PLP Health Check Interval";
- const char *sel = "[0-3,8]: current/default/saved/supported/changed";
- const __u32 nsid = 0;
- const __u8 fid = 0xc6;
- struct nvme_dev *dev;
- __u32 result;
- int err;
-
- struct config {
- __u8 sel;
- };
-
- struct config cfg = {
- .sel = 0,
- };
-
- OPT_ARGS(opts) = {
- OPT_BYTE("sel", 'S', &cfg.sel, sel),
- OPT_END()
- };
-
- err = parse_and_open(&dev, argc, argv, desc, opts);
- if (err)
- return err;
-
-
- struct nvme_get_features_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
- .fid = fid,
- .nsid = nsid,
- .sel = cfg.sel,
- .cdw11 = 0,
- .uuidx = 0,
- .data_len = 0,
- .data = NULL,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .result = &result,
- };
-
- err = nvme_get_features(&args);
- if (!err) {
- printf("get-feature:0xC6 %s value: %#08x\n", nvme_select_to_string(cfg.sel), result);
-
- if (cfg.sel == NVME_GET_FEATURES_SEL_SUPPORTED)
- nvme_show_select_result(fid, result);
- } else {
- nvme_show_error("Could not get feature: 0xC6");
- }
-
- return err;
+ struct plugin *plugin)
+{
+
+ const char *desc = "Define Issue Get Feature command (FID : 0xC6) PLP Health Check Interval";
+ const char *sel = "[0-3,8]: current/default/saved/supported/changed";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xc6;
+ struct nvme_dev *dev;
+ __u32 result;
+ int err;
+
+ struct config {
+ __u8 sel;
+ };
+
+ struct config cfg = {
+ .sel = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("sel", 'S', &cfg.sel, sel),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .sel = cfg.sel,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_get_features(&args);
+ if (!err) {
+ printf("get-feature:0xC6 %s value: %#08x\n", nvme_select_to_string(cfg.sel), result);
+
+ if (cfg.sel == NVME_GET_FEATURES_SEL_SUPPORTED)
+ nvme_show_select_result(fid, result);
+ } else {
+ nvme_show_error("Could not get feature: 0xC6");
+ }
+
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// dssd_async_event_config
+
+static int set_dssd_async_event_config(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+
+ const char *desc = "Issue Set Feature command (FID : 0xC9) DSSD Async Event Config";
+ const char *epn = "[0]:Enable Panic Notices";
+ const char *save = "Specifies that the controller shall save the attribute";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xc9;
+ struct nvme_dev *dev;
+ int err;
+ __u32 result;
+ __u8 uuid_index = 0;
+
+ struct config {
+ bool epn;
+ bool save;
+ };
+
+ struct config cfg = {
+ .epn = false,
+ .save = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("enable-panic-notices", 'e', &cfg.epn, epn),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ printf("ERROR: No OCP UUID index found\n");
+ return err;
+ }
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = cfg.epn ? 1 : 0,
+ .cdw12 = 0,
+ .save = cfg.save,
+ .uuidx = uuid_index,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ nvme_show_perror("Set DSSD Asynchronous Event Configuration\n");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully set the DSSD Asynchronous Event Configuration\n");
+ printf("Enable Panic Notices bit Value: 0x%x\n", cfg.epn);
+ printf("Save bit Value: 0x%x\n", cfg.save);
+ }
+ return err;
+}
+
+static int get_dssd_async_event_config(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+
+ const char *desc = "Issue Get Feature command (FID : 0xC9) DSSD Async Event Config";
+ const char *sel = "[0-3]: current/default/saved/supported";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xc9;
+ struct nvme_dev *dev;
+ __u32 result;
+ int err;
+
+ struct config {
+ __u8 sel;
+ };
+
+ struct config cfg = {
+ .sel = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("sel", 'S', &cfg.sel, sel),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .sel = cfg.sel,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_get_features(&args);
+ if (!err) {
+ printf("get-feature:0xC9 %s value: %#08x\n", nvme_select_to_string(cfg.sel), result);
+
+ if (cfg.sel == NVME_GET_FEATURES_SEL_SUPPORTED)
+ nvme_show_select_result(fid, result);
+ } else {
+ nvme_show_error("Could not get feature: 0xC9\n");
+ }
+
+ return err;
}
///////////////////////////////////////////////////////////////////////////////
@@ -2299,645 +3137,807 @@ static int get_plp_health_check_interval(int argc, char **argv, struct command *
///////////////////////////////////////////////////////////////////////////////
/// Telemetry String Log Format Log Page (LID : C9h)
-/* C9 Telemetry String Log Format Log Page */
-#define C9_GUID_LENGTH 16
-#define C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE 0xC9
-#define C9_TELEMETRY_STR_LOG_LEN 432
-#define C9_TELEMETRY_STR_LOG_SIST_OFST 431
+/* Function declaration for Telemetry String Log Format (LID:C9h) */
+static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
-/**
- * struct telemetry_str_log_format - Telemetry String Log Format
- * @log_page_version: indicates the version of the mapping this log page uses
- * Shall be set to 01h.
- * @reserved1: Reserved.
- * @log_page_guid: Shall be set to B13A83691A8F408B9EA495940057AA44h.
- * @sls: Shall be set to the number of DWORDS in the String Log.
- * @reserved2: reserved.
- * @sits: shall be set to the number of DWORDS in the Statistics
- * Identifier String Table
- * @ests: Shall be set to the number of DWORDS from byte 0 of this
- * log page to the start of the Event String Table
- * @estsz: shall be set to the number of DWORDS in the Event String Table
- * @vu_eve_sts: Shall be set to the number of DWORDS from byte 0 of this
- * log page to the start of the VU Event String Table
- * @vu_eve_st_sz: shall be set to the number of DWORDS in the VU Event String Table
- * @ascts: the number of DWORDS from byte 0 of this log page until the ASCII Table Starts.
- * @asctsz: the number of DWORDS in the ASCII Table
- * @fifo1: FIFO 0 ASCII String
- * @fifo2: FIFO 1 ASCII String
- * @fifo3: FIFO 2 ASCII String
- * @fifo4: FIFO 3 ASCII String
- * @fif05: FIFO 4 ASCII String
- * @fifo6: FIFO 5 ASCII String
- * @fifo7: FIFO 6 ASCII String
- * @fifo8: FIFO 7 ASCII String
- * @fifo9: FIFO 8 ASCII String
- * @fifo10: FIFO 9 ASCII String
- * @fif011: FIFO 10 ASCII String
- * @fif012: FIFO 11 ASCII String
- * @fifo13: FIFO 12 ASCII String
- * @fif014: FIFO 13 ASCII String
- * @fif015: FIFO 14 ASCII String
- * @fif016: FIFO 15 ASCII String
- * @reserved3: reserved
- */
-struct __attribute__((__packed__)) telemetry_str_log_format {
- __u8 log_page_version;
- __u8 reserved1[15];
- __u8 log_page_guid[C9_GUID_LENGTH];
- __le64 sls;
- __u8 reserved2[24];
- __le64 sits;
- __le64 sitsz;
- __le64 ests;
- __le64 estsz;
- __le64 vu_eve_sts;
- __le64 vu_eve_st_sz;
- __le64 ascts;
- __le64 asctsz;
- __u8 fifo1[16];
- __u8 fifo2[16];
- __u8 fifo3[16];
- __u8 fifo4[16];
- __u8 fifo5[16];
- __u8 fifo6[16];
- __u8 fifo7[16];
- __u8 fifo8[16];
- __u8 fifo9[16];
- __u8 fifo10[16];
- __u8 fifo11[16];
- __u8 fifo12[16];
- __u8 fifo13[16];
- __u8 fifo14[16];
- __u8 fifo15[16];
- __u8 fifo16[16];
- __u8 reserved3[48];
-};
-/*
- * struct statistics_id_str_table_entry - Statistics Identifier String Table Entry
- * @vs_si: Shall be set the Vendor Unique Statistic Identifier number.
- * @reserved1: Reserved
- * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
- * @ascii_id_ofst: Shall be set to the offset from DWORD 0/Byte 0 of the Start
- * of the ASCII Table to the first character of the string for
- * this Statistic Identifier string..
- * @reserved2 reserved
- */
-struct __attribute__((__packed__)) statistics_id_str_table_entry {
- __le16 vs_si;
- __u8 reserved1;
- __u8 ascii_id_len;
- __le64 ascii_id_ofst;
- __le32 reserved2;
-};
+static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data, __u8 *log_data_buf)
+{
+ //calculating the index value for array
+ __le64 stat_id_index = (log_data->sitsz * 4) / 16;
+ __le64 eve_id_index = (log_data->estsz * 4) / 16;
+ __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16;
+ __le64 ascii_table_index = (log_data->asctsz * 4);
+ //Calculating the offset for dynamic fields.
+ __le64 stat_id_str_table_ofst = log_data->sits * 4;
+ __le64 event_str_table_ofst = log_data->ests * 4;
+ __le64 vu_event_str_table_ofst = log_data->vu_eve_sts * 4;
+ __le64 ascii_table_ofst = log_data->ascts * 4;
+ struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index];
+ struct event_id_str_table_entry event_id_str_table_arr[eve_id_index];
+ struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index];
+ int j;
-/*
- * struct event_id_str_table_entry - Event Identifier String Table Entry
- * @deb_eve_class: Shall be set the Debug Class.
- * @ei: Shall be set to the Event Identifier
- * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
- * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the
- * ASCII table to the ASCII data for this identifier
- * @reserved2 reserved
- */
-struct __attribute__((__packed__)) event_id_str_table_entry {
- __u8 deb_eve_class;
- __le16 ei;
- __u8 ascii_id_len;
- __le64 ascii_id_ofst;
- __le32 reserved2;
+ printf(" Log Page Version : 0x%x\n", log_data->log_page_version);
+
+ printf(" Reserved : ");
+ for (j = 0; j < 15; j++)
+ printf("%d", log_data->reserved1[j]);
+ printf("\n");
+
+ printf(" Log page GUID : 0x");
+ for (j = C9_GUID_LENGTH - 1; j >= 0; j--)
+ printf("%x", log_data->log_page_guid[j]);
+ printf("\n");
+
+ printf(" Telemetry String Log Size : 0x%lx\n", le64_to_cpu(log_data->sls));
+
+ printf(" Reserved : ");
+ for (j = 0; j < 24; j++)
+ printf("%d", log_data->reserved2[j]);
+ printf("\n");
+
+ printf(" Statistics Identifier String Table Start : 0x%lx\n", le64_to_cpu(log_data->sits));
+ printf(" Statistics Identifier String Table Size : 0x%lx\n", le64_to_cpu(log_data->sitsz));
+ printf(" Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->ests));
+ printf(" Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->estsz));
+ printf(" VU Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->vu_eve_sts));
+ printf(" VU Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->vu_eve_st_sz));
+ printf(" ASCII Table Start : 0x%lx\n", le64_to_cpu(log_data->ascts));
+ printf(" ASCII Table Size : 0x%lx\n", le64_to_cpu(log_data->asctsz));
+
+ printf(" FIFO 1 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo1[j], log_data->fifo1[j]);
+
+ printf(" FIFO 2 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo2[j], log_data->fifo2[j]);
+
+ printf(" FIFO 3 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo3[j], log_data->fifo3[j]);
+
+ printf(" FIFO 4 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo4[j], log_data->fifo4[j]);
+
+ printf(" FIFO 5 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo5[j], log_data->fifo5[j]);
+
+ printf(" FIFO 6 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo6[j], log_data->fifo6[j]);
+
+ printf(" FIFO 7 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo7[j], log_data->fifo7[j]);
+
+ printf(" FIFO 8 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo8[j], log_data->fifo8[j]);
+
+ printf(" FIFO 9 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo9[j], log_data->fifo9[j]);
+
+ printf(" FIFO 10 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo10[j], log_data->fifo10[j]);
+
+ printf(" FIFO 11 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo11[j], log_data->fifo11[j]);
+
+ printf(" FIFO 12 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo12[j], log_data->fifo12[j]);
+
+ printf(" FIFO 13 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo13[j], log_data->fifo13[j]);
+
+ printf(" FIFO 14 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo14[j], log_data->fifo14[j]);
+
+ printf(" FIFO 15 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo15[j], log_data->fifo16[j]);
+
+ printf(" FIFO 16 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++)
+ printf(" %d %d %c \n", j, log_data->fifo16[j], log_data->fifo16[j]);
+
+ printf(" Reserved : ");
+ for (j = 0; j < 48; j++)
+ printf("%d", log_data->reserved3[j]);
+ printf("\n");
+
+
+ if (log_data->sitsz != 0) {
+ memcpy(stat_id_str_table_arr,
+ (__u8 *)log_data_buf + stat_id_str_table_ofst,
+ (log_data->sitsz * 4));
+ printf(" Statistics Identifier String Table\n");
+ for (j = 0; j < stat_id_index; j++) {
+ printf(" Vendor Specific Statistic Identifier : 0x%x\n",
+ le16_to_cpu(stat_id_str_table_arr[j].vs_si));
+ printf(" Reserved : 0x%x\n",
+ stat_id_str_table_arr[j].reserved1);
+ printf(" ASCII ID Length : 0x%x\n",
+ stat_id_str_table_arr[j].ascii_id_len);
+ printf(" ASCII ID offset : 0x%lx\n",
+ le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst));
+ printf(" Reserved : 0x%x\n",
+ stat_id_str_table_arr[j].reserved2);
+ }
+ }
+
+
+ if (log_data->estsz != 0) {
+ memcpy(event_id_str_table_arr, (__u8 *)log_data_buf +
+ event_str_table_ofst, (log_data->estsz * 4));
+ printf(" Event Identifier String Table Entry\n");
+ for (j = 0; j < eve_id_index; j++) {
+ printf(" Debug Event Class : 0x%x\n",
+ event_id_str_table_arr[j].deb_eve_class);
+ printf(" Event Identifier : 0x%x\n",
+ le16_to_cpu(event_id_str_table_arr[j].ei));
+ printf(" ASCII ID Length : 0x%x\n",
+ event_id_str_table_arr[j].ascii_id_len);
+ printf(" ASCII ID offset : 0x%lx\n",
+ le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst));
+ printf(" Reserved : 0x%x\n",
+ event_id_str_table_arr[j].reserved2);
+
+ }
+ }
+
+ if (log_data->vu_eve_st_sz != 0) {
+ memcpy(vu_event_id_str_table_arr, (__u8 *)log_data_buf +
+ vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4));
+ printf(" VU Event Identifier String Table Entry\n");
+ for (j = 0; j < vu_eve_index; j++) {
+ printf(" Debug Event Class : 0x%x\n",
+ vu_event_id_str_table_arr[j].deb_eve_class);
+ printf(" VU Event Identifier : 0x%x\n",
+ le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei));
+ printf(" ASCII ID Length : 0x%x\n",
+ vu_event_id_str_table_arr[j].ascii_id_len);
+ printf(" ASCII ID offset : 0x%lx\n",
+ le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst));
+ printf(" Reserved : 0x%x\n",
+ vu_event_id_str_table_arr[j].reserved);
+
+ }
+ }
+
+ if (log_data->asctsz != 0) {
+ printf(" ASCII Table\n");
+ printf(" Byte Data_Byte ASCII_Character\n");
+ for (j = 0; j < ascii_table_index; j++)
+ printf(" %lld %d %c\n",
+ ascii_table_ofst+j, log_data_buf[ascii_table_ofst + j],
+ (char)log_data_buf[ascii_table_ofst + j]);
+ }
+
+ return 0;
+}
+
+static int ocp_print_C9_log_json(struct telemetry_str_log_format *log_data, __u8 *log_data_buf)
+{
+ struct json_object *root = json_create_object();
+ char res_arr[48];
+ char *res = res_arr;
+ char guid_buf[C9_GUID_LENGTH];
+ char *guid = guid_buf;
+ char fifo_arr[16];
+ char *fifo = fifo_arr;
+ char buf[128];
+ //calculating the index value for array
+ __le64 stat_id_index = (log_data->sitsz * 4) / 16;
+ __le64 eve_id_index = (log_data->estsz * 4) / 16;
+ __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16;
+ __le64 ascii_table_index = (log_data->asctsz * 4);
+ //Calculating the offset for dynamic fields.
+ __le64 stat_id_str_table_ofst = log_data->sits * 4;
+ __le64 event_str_table_ofst = log_data->ests * 4;
+ __le64 vu_event_str_table_ofst = log_data->vu_eve_sts * 4;
+ __le64 ascii_table_ofst = log_data->ascts * 4;
+ struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index];
+ struct event_id_str_table_entry event_id_str_table_arr[eve_id_index];
+ struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index];
+ __u8 ascii_table_info_arr[ascii_table_index];
+ char ascii_buf[ascii_table_index];
+ char *ascii = ascii_buf;
+ int j;
+
+ json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+
+ memset((__u8 *)res, 0, 15);
+ for (j = 0; j < 15; j++)
+ res += sprintf(res, "%d", log_data->reserved1[j]);
+ json_object_add_value_string(root, "Reserved", res_arr);
+
+ memset((void *)guid, 0, C9_GUID_LENGTH);
+ for (j = C9_GUID_LENGTH - 1; j >= 0; j--)
+ guid += sprintf(guid, "%02x", log_data->log_page_guid[j]);
+ json_object_add_value_string(root, "Log page GUID", guid_buf);
+
+ json_object_add_value_int(root, "Telemetry String Log Size", le64_to_cpu(log_data->sls));
+
+ memset((__u8 *)res, 0, 24);
+ for (j = 0; j < 24; j++)
+ res += sprintf(res, "%d", log_data->reserved2[j]);
+ json_object_add_value_string(root, "Reserved", res_arr);
+
+ json_object_add_value_int(root, "Statistics Identifier String Table Start", le64_to_cpu(log_data->sits));
+ json_object_add_value_int(root, "Event String Table Start", le64_to_cpu(log_data->ests));
+ json_object_add_value_int(root, "Event String Table Size", le64_to_cpu(log_data->estsz));
+ json_object_add_value_int(root, "VU Event String Table Start", le64_to_cpu(log_data->vu_eve_sts));
+ json_object_add_value_int(root, "VU Event String Table Size", le64_to_cpu(log_data->vu_eve_st_sz));
+ json_object_add_value_int(root, "ASCII Table Start", le64_to_cpu(log_data->ascts));
+ json_object_add_value_int(root, "ASCII Table Size", le64_to_cpu(log_data->asctsz));
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo1[j]);
+ json_object_add_value_string(root, "FIFO 1 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo2[j]);
+ json_object_add_value_string(root, "FIFO 2 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo3[j]);
+ json_object_add_value_string(root, "FIFO 3 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo4[j]);
+ json_object_add_value_string(root, "FIFO 4 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo5[j]);
+ json_object_add_value_string(root, "FIFO 5 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo6[j]);
+ json_object_add_value_string(root, "FIFO 6 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo7[j]);
+ json_object_add_value_string(root, "FIFO 7 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo8[j]);
+ json_object_add_value_string(root, "FIFO 8 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo9[j]);
+ json_object_add_value_string(root, "FIFO 9 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo10[j]);
+ json_object_add_value_string(root, "FIFO 10 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo11[j]);
+ json_object_add_value_string(root, "FIFO 11 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo12[j]);
+ json_object_add_value_string(root, "FIFO 12 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo13[j]);
+ json_object_add_value_string(root, "FIFO 13 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo14[j]);
+ json_object_add_value_string(root, "FIFO 14 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo15[j]);
+ json_object_add_value_string(root, "FIFO 15 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo16[j]);
+ json_object_add_value_string(root, "FIFO 16 ASCII String", fifo_arr);
+
+ memset((__u8 *)res, 0, 48);
+ for (j = 0; j < 48; j++)
+ res += sprintf(res, "%d", log_data->reserved3[j]);
+ json_object_add_value_string(root, "Reserved", res_arr);
+
+ if (log_data->sitsz != 0) {
+
+ memcpy(stat_id_str_table_arr,
+ (__u8 *)log_data_buf + stat_id_str_table_ofst,
+ (log_data->sitsz * 4));
+ struct json_object *stat_table = json_create_object();
+
+ for (j = 0; j < stat_id_index; j++) {
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_uint(entry, "Vendor Specific Statistic Identifier",
+ le16_to_cpu(stat_id_str_table_arr[j].vs_si));
+ json_object_add_value_uint(entry, "Reserved",
+ le64_to_cpu(stat_id_str_table_arr[j].reserved1));
+ json_object_add_value_uint(entry, "ASCII ID Length",
+ le64_to_cpu(stat_id_str_table_arr[j].ascii_id_len));
+ json_object_add_value_uint(entry, "ASCII ID offset",
+ le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst));
+ json_object_add_value_uint(entry, "Reserved2",
+ le64_to_cpu(stat_id_str_table_arr[j].reserved2));
+ sprintf(buf, "Statistics Identifier String Table %d", j);
+ json_object_add_value_object(stat_table, buf, entry);
+ }
+
+ json_object_add_value_object(root,
+ "Statistics Identifier String Table", stat_table);
+ }
+
+ if (log_data->estsz != 0) {
+ struct json_object *eve_table = json_create_object();
+
+ memcpy(event_id_str_table_arr,
+ (__u8 *)log_data_buf + event_str_table_ofst,
+ (log_data->estsz * 4));
+ for (j = 0; j < eve_id_index; j++) {
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_int(entry, "Debug Event Class",
+ le16_to_cpu(event_id_str_table_arr[j].deb_eve_class));
+ json_object_add_value_int(entry, "Event Identifier",
+ le16_to_cpu(event_id_str_table_arr[j].ei));
+ json_object_add_value_int(entry, "ASCII ID Length",
+ le64_to_cpu(event_id_str_table_arr[j].ascii_id_len));
+ json_object_add_value_int(entry, "ASCII ID offset",
+ le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst));
+ json_object_add_value_int(entry, "Reserved",
+ le64_to_cpu(event_id_str_table_arr[j].reserved2));
+ sprintf(buf, "Event Identifier String Table Entry %d", j);
+ json_object_add_value_object(eve_table, buf, entry);
+ }
+ json_object_add_value_object(root,
+ "Event Identifier String Table Entry",
+ eve_table);
+ }
+
+ if (log_data->vu_eve_st_sz != 0) {
+ struct json_object *vu_eve_table = json_create_object();
+
+ memcpy(vu_event_id_str_table_arr,
+ (__u8 *)log_data_buf + vu_event_str_table_ofst,
+ (log_data->vu_eve_st_sz * 4));
+ for (j = 0; j < vu_eve_index; j++) {
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_int(entry, "Debug Event Class",
+ le16_to_cpu(vu_event_id_str_table_arr[j].deb_eve_class));
+ json_object_add_value_int(entry, "VU Event Identifier",
+ le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei));
+ json_object_add_value_int(entry, "ASCII ID Length",
+ le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_len));
+ json_object_add_value_int(entry, "ASCII ID offset",
+ le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst));
+ json_object_add_value_int(entry, "Reserved",
+ le64_to_cpu(vu_event_id_str_table_arr[j].reserved));
+ sprintf(buf, "VU Event Identifier String Table Entry %d", j);
+ json_object_add_value_object(vu_eve_table, buf, entry);
+ }
+ json_object_add_value_object(root,
+ "VU Event Identifier String Table Entry",
+ vu_eve_table);
+ }
+
+ if (log_data->asctsz != 0) {
+ memcpy(ascii_table_info_arr,
+ (__u8 *)log_data_buf + ascii_table_ofst,
+ (log_data->asctsz * 4));
+ memset((void *)ascii, 0, ascii_table_index);
+ for (j = 0; j < ascii_table_index; j++)
+ ascii += sprintf(ascii, "%c", ascii_table_info_arr[j]);
+ json_object_add_value_string(root, "ASCII Table", ascii_buf);
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+
+ return 0;
+}
+
+static void ocp_print_c9_log_binary(__u8 *log_data_buf, int total_log_page_size)
+{
+ return d_raw((unsigned char *)log_data_buf, total_log_page_size);
+}
+
+static int get_c9_log_page(struct nvme_dev *dev, char *format)
+{
+
+ int ret = 0;
+
+ nvme_print_flags_t fmt;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR : OCP : invalid output format\n");
+ return ret;
+ }
+
+ get_c9_log_page_data(dev, 1, 0);
+
+ if (!ret) {
+ switch (fmt) {
+ case NORMAL:
+ ocp_print_C9_log_normal(log_data, pC9_string_buffer);
+ break;
+ case JSON:
+ ocp_print_C9_log_json(log_data, pC9_string_buffer);
+ break;
+ case BINARY:
+ ocp_print_c9_log_binary(pC9_string_buffer, total_log_page_sz);
+ break;
+ default:
+ fprintf(stderr, "unhandled output format\n");
+ break;
+ }
+ } else
+ fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n");
+ free(header_data);
+ return ret;
+}
+
+static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ struct nvme_dev *dev;
+ int ret = 0;
+ const char *desc = "Retrieve telemetry string log format";
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_c9_log_page(dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : OCP : Failure reading the C9 Log Page, ret = %d\n", ret);
+
+ dev_close(dev);
+
+ return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// TCG Configuration Log Page (LID : C7h)
+
+/* C7 TCG Configuration Log Page */
+#define C7_GUID_LENGTH 16
+#define C7_TCG_CONFIGURATION_LEN 512
+#define C7_TCG_CONFIGURATION_OPCODE 0xC7
+#define C7_TCG_CONFIGURATION_LOG_VERSION 0x1
+
+static __u8 tcg_configuration_guid[C7_GUID_LENGTH] = {
+ 0x06, 0x40, 0x24, 0xBD,
+ 0x7E, 0xE0, 0xE6, 0x83,
+ 0xC0, 0x47, 0x54, 0xFA,
+ 0x9D, 0x2A, 0xE0, 0x54
};
/*
- * struct vu_event_id_str_table_entry - VU Event Identifier String Table Entry
- * @deb_eve_class: Shall be set the Debug Class.
- * @vu_ei: Shall be set to the VU Event Identifier
- * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
- * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the
- * ASCII table to the ASCII data for this identifier
- * @reserved reserved
+ * struct tcg_configuration_log - TCG Configuration Log Page Structure
+ * @state: state
+ * @rsvd1: Reserved1
+ * @locking_sp_act_count: Locking SP Activation Count
+ * @type_rev_count: Tper Revert Count
+ * @locking_sp_rev_count: Locking SP Revert Count.
+ * @no_of_locking_obj: Number of Locking Objects
+ * @no_of_single_um_locking_obj: Number of Single User Mode Locking Objects
+ * @no_of_range_prov_locking_obj: Number of Range Provisioned Locking Objects
+ * @no_of_ns_prov_locking_obj: Number of Namespace Provisioned Locking Objects
+ * @no_of_read_lock_locking_obj: Number of Read Locked Locking Objects
+ * @no_of_write_lock_locking_obj: Number of Write Locked Locking Objects
+ * @no_of_read_unlock_locking_obj: Number of Read Unlocked Locking Objects
+ * @no_of_read_unlock_locking_obj: Number of Write Unlocked Locking Objects
+ * @rsvd2: Reserved2
+ * @sid_auth_try_count: SID Authentication Try Count
+ * @sid_auth_try_limit: SID Authentication Try Limit
+ * @pro_tcg_rc: Programmatic TCG Reset Count
+ * @pro_rlc: Programmatic Reset Lock Count
+ * @tcg_ec: TCG Error Count
+ * @rsvd3: Reserved3
+ * @log_page_version: Log Page Version
*/
-struct __attribute__((__packed__)) vu_event_id_str_table_entry {
- __u8 deb_eve_class;
- __le16 vu_ei;
- __u8 ascii_id_len;
- __le64 ascii_id_ofst;
- __le32 reserved;
+struct __packed tcg_configuration_log {
+ __u8 state;
+ __u8 rsvd1[3];
+ __u8 locking_sp_act_count;
+ __u8 type_rev_count;
+ __u8 locking_sp_rev_count;
+ __u8 no_of_locking_obj;
+ __u8 no_of_single_um_locking_obj;
+ __u8 no_of_range_prov_locking_obj;
+ __u8 no_of_ns_prov_locking_obj;
+ __u8 no_of_read_lock_locking_obj;
+ __u8 no_of_write_lock_locking_obj;
+ __u8 no_of_read_unlock_locking_obj;
+ __u8 no_of_write_unlock_locking_obj;
+ __u8 rsvd2;
+ __u32 sid_auth_try_count;
+ __u32 sid_auth_try_limit;
+ __u32 pro_tcg_rc;
+ __u32 pro_rlc;
+ __u32 tcg_ec;
+ __u8 rsvd3[458];
+ __le16 log_page_version;
+ __u8 log_page_guid[C7_GUID_LENGTH];
+
};
-/* Function declaration for Telemetry String Log Format (LID:C9h) */
-static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd,
- struct plugin *plugin);
-
-
-static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data,__u8 *log_data_buf)
-{
- //calculating the index value for array
- __le64 stat_id_index = (log_data->sitsz * 4) / 16;
- __le64 eve_id_index = (log_data->estsz * 4) / 16;
- __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16;
- __le64 ascii_table_index = (log_data->asctsz * 4);
- //Calculating the offset for dynamic fields.
- __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4);
- __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4);
- __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4);
- __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4);
- struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index];
- struct event_id_str_table_entry event_id_str_table_arr[eve_id_index];
- struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index];
- __u8 ascii_table_info_arr[ascii_table_index];
- int j;
-
- printf(" Log Page Version : 0x%x\n", log_data->log_page_version);
-
- printf(" Reserved : ");
- for (j = 0; j < 15; j++)
- printf("%d", log_data->reserved1[j]);
- printf("\n");
-
- printf(" Log page GUID : 0x");
- for (j = C9_GUID_LENGTH - 1; j >= 0; j--)
- printf("%x", log_data->log_page_guid[j]);
- printf("\n");
-
- printf(" Telemetry String Log Size : 0x%lx\n", le64_to_cpu(log_data->sls));
-
- printf(" Reserved : ");
- for (j = 0; j < 24; j++)
- printf("%d", log_data->reserved2[j]);
- printf("\n");
-
- printf(" Statistics Identifier String Table Start : 0x%lx\n", le64_to_cpu(log_data->sits));
- printf(" Statistics Identifier String Table Size : 0x%lx\n", le64_to_cpu(log_data->sitsz));
- printf(" Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->ests));
- printf(" Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->estsz));
- printf(" VU Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->vu_eve_sts));
- printf(" VU Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->vu_eve_st_sz));
- printf(" ASCII Table Start : 0x%lx\n", le64_to_cpu(log_data->ascts));
- printf(" ASCII Table Size : 0x%lx\n", le64_to_cpu(log_data->asctsz));
-
- printf(" FIFO 1 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo1[j], log_data->fifo1[j]);
- }
-
- printf(" FIFO 2 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo2[j], log_data->fifo2[j]);
- }
-
- printf(" FIFO 3 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo3[j], log_data->fifo3[j]);
- }
-
- printf(" FIFO 4 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
-
- printf(" %d %d %c \n", j, log_data->fifo4[j], log_data->fifo4[j]);
- }
-
- printf(" FIFO 5 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo5[j], log_data->fifo5[j]);
- }
-
- printf(" FIFO 6 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo6[j], log_data->fifo6[j]);
- }
-
- printf(" FIFO 7 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo7[j], log_data->fifo7[j]);
- }
-
- printf(" FIFO 8 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf("index value ascii_val");
- printf(" %d %d %c \n", j, log_data->fifo8[j], log_data->fifo8[j]);
- }
-
- printf(" FIFO 9 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo9[j], log_data->fifo9[j]);
- }
-
- printf(" FIFO 10 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo10[j], log_data->fifo10[j]);
- }
-
- printf(" FIFO 11 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo11[j], log_data->fifo11[j]);
- }
-
- printf(" FIFO 12 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo12[j], log_data->fifo12[j]);
- }
-
- printf(" FIFO 13 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo13[j], log_data->fifo13[j]);
- }
-
- printf(" FIFO 14 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo14[j], log_data->fifo14[j]);
- }
-
- printf(" FIFO 15 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo15[j], log_data->fifo16[j]);
- }
-
- printf(" FIFO 16 ASCII String\n");
- printf(" index value ascii_val\n");
- for (j = 0; j < 16; j++){
- printf(" %d %d %c \n", j, log_data->fifo16[j], log_data->fifo16[j]);
- }
-
- printf(" Reserved : ");
- for (j = 0; j < 48; j++)
- printf("%d", log_data->reserved3[j]);
- printf("\n");
-
- memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4));
- memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4));
- memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4));
- memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4));
-
- printf(" Statistics Identifier String Table\n");
- for (j = 0; j < stat_id_index; j++){
- printf(" Vendor Specific Statistic Identifier : 0x%x\n",le16_to_cpu(stat_id_str_table_arr[j].vs_si));
- printf(" Reserved : 0x%d",stat_id_str_table_arr[j].reserved1);
- printf(" ASCII ID Length : 0x%x\n",stat_id_str_table_arr[j].ascii_id_len);
- printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst));
- printf(" Reserved : 0x%d\n",stat_id_str_table_arr[j].reserved2);
- }
-
- printf(" Event Identifier String Table Entry\n");
- for (j = 0; j < eve_id_index; j++){
- printf(" Debug Event Class : 0x%x\n",event_id_str_table_arr[j].deb_eve_class);
- printf(" Event Identifier : 0x%x\n",le16_to_cpu(event_id_str_table_arr[j].ei));
- printf(" ASCII ID Length : 0x%x\n",event_id_str_table_arr[j].ascii_id_len);
- printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst));
- printf(" Reserved : 0x%d\n",event_id_str_table_arr[j].reserved2);
-
- }
-
- printf(" VU Event Identifier String Table Entry\n");
- for (j = 0; j < vu_eve_index; j++){
- printf(" Debug Event Class : 0x%x\n",vu_event_id_str_table_arr[j].deb_eve_class);
- printf(" VU Event Identifier : 0x%x\n",le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei));
- printf(" ASCII ID Length : 0x%x\n",vu_event_id_str_table_arr[j].ascii_id_len);
- printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst));
- printf(" Reserved : 0x%d\n",vu_event_id_str_table_arr[j].reserved);
-
- }
-
- printf(" ASCII Table\n");
- printf(" Byte Data_Byte ASCII_Character\n");
- for (j = 0; j < ascii_table_index; j++){
- printf(" %lld 0x%x %c \n",ascii_table_ofst+j,ascii_table_info_arr[j],ascii_table_info_arr[j]);
- }
- return 0;
-}
-
-static int ocp_print_C9_log_json(struct telemetry_str_log_format *log_data,__u8 *log_data_buf)
-{
- struct json_object *root = json_create_object();
- struct json_object *stat_table = json_create_object();
- struct json_object *eve_table = json_create_object();
- struct json_object *vu_eve_table = json_create_object();
- struct json_object *entry = json_create_object();
- char res_arr[48];
- char *res = res_arr;
- char guid_buf[C9_GUID_LENGTH];
- char *guid = guid_buf;
- char fifo_arr[16];
- char *fifo = fifo_arr;
- //calculating the index value for array
- __le64 stat_id_index = (log_data->sitsz * 4) / 16;
- __le64 eve_id_index = (log_data->estsz * 4) / 16;
- __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16;
- __le64 ascii_table_index = (log_data->asctsz * 4);
- //Calculating the offset for dynamic fields.
- __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4);
- __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4);
- __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4);
- __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4);
- struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index];
- struct event_id_str_table_entry event_id_str_table_arr[eve_id_index];
- struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index];
- __u8 ascii_table_info_arr[ascii_table_index];
- char ascii_buf[ascii_table_index];
- char *ascii = ascii_buf;
- int j;
-
- json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
-
- memset((__u8 *)res, 0, 15);
- for (j = 0; j < 15; j++)
- res += sprintf(res, "%d", log_data->reserved1[j]);
- json_object_add_value_string(root, "Reserved", res_arr);
-
- memset((void *)guid, 0, C9_GUID_LENGTH);
- for (j = C9_GUID_LENGTH - 1; j >= 0; j--)
- guid += sprintf(guid, "%02x", log_data->log_page_guid[j]);
- json_object_add_value_string(root, "Log page GUID", guid_buf);
-
- json_object_add_value_int(root, "Telemetry String Log Size", le64_to_cpu(log_data->sls));
-
- memset((__u8 *)res, 0, 24);
- for (j = 0; j < 24; j++)
- res += sprintf(res, "%d", log_data->reserved2[j]);
- json_object_add_value_string(root, "Reserved", res_arr);
-
- json_object_add_value_int(root, "Statistics Identifier String Table Start", le64_to_cpu(log_data->sits));
- json_object_add_value_int(root, "Event String Table Start", le64_to_cpu(log_data->ests));
- json_object_add_value_int(root, "Event String Table Size", le64_to_cpu(log_data->estsz));
- json_object_add_value_int(root, "VU Event String Table Start", le64_to_cpu(log_data->vu_eve_sts));
- json_object_add_value_int(root, "VU Event String Table Size", le64_to_cpu(log_data->vu_eve_st_sz));
- json_object_add_value_int(root, "ASCII Table Start", le64_to_cpu(log_data->ascts));
- json_object_add_value_int(root, "ASCII Table Size", le64_to_cpu(log_data->asctsz));
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo1[j]);
- json_object_add_value_string(root, "FIFO 1 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo2[j]);
- json_object_add_value_string(root, "FIFO 2 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo3[j]);
- json_object_add_value_string(root, "FIFO 3 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo4[j]);
- json_object_add_value_string(root, "FIFO 4 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo5[j]);
- json_object_add_value_string(root, "FIFO 5 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo6[j]);
- json_object_add_value_string(root, "FIFO 6 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo7[j]);
- json_object_add_value_string(root, "FIFO 7 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo8[j]);
- json_object_add_value_string(root, "FIFO 8 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo9[j]);
- json_object_add_value_string(root, "FIFO 9 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo10[j]);
- json_object_add_value_string(root, "FIFO 10 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo11[j]);
- json_object_add_value_string(root, "FIFO 11 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo12[j]);
- json_object_add_value_string(root, "FIFO 12 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo13[j]);
- json_object_add_value_string(root, "FIFO 13 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo14[j]);
- json_object_add_value_string(root, "FIFO 14 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo15[j]);
- json_object_add_value_string(root, "FIFO 15 ASCII String", fifo_arr);
-
- memset((void *)fifo, 0, 16);
- for (j = 0; j < 16; j++)
- fifo += sprintf(fifo, "%c", log_data->fifo16[j]);
- json_object_add_value_string(root, "FIFO 16 ASCII String", fifo_arr);
-
- memset((__u8 *)res, 0, 48);
- for (j = 0; j < 48; j++)
- res += sprintf(res, "%d", log_data->reserved3[j]);
- json_object_add_value_string(root, "Reserved", res_arr);
-
- memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4));
- memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4));
- memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4));
- memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4));
-
- for (j = 0; j < stat_id_index; j++){
- json_object_add_value_int(entry, "Vendor Specific Statistic Identifier", le16_to_cpu(stat_id_str_table_arr[j].vs_si));
- json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved1));
- json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_len));
- json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst));
- json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved2));
- json_array_add_value_object(stat_table, entry);
- }
- json_object_add_value_array(root, "Statistics Identifier String Table", stat_table);
-
- for (j = 0; j < eve_id_index; j++){
- json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(event_id_str_table_arr[j].deb_eve_class));
- json_object_add_value_int(entry, "Event Identifier", le16_to_cpu(event_id_str_table_arr[j].ei));
- json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(event_id_str_table_arr[j].ascii_id_len));
- json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst));
- json_object_add_value_int(entry, "Reserved", le64_to_cpu(event_id_str_table_arr[j].reserved2));
- json_array_add_value_object(eve_table, entry);
- }
- json_object_add_value_array(root, "Event Identifier String Table Entry", eve_table);
-
- for (j = 0; j < vu_eve_index; j++){
- json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(vu_event_id_str_table_arr[j].deb_eve_class));
- json_object_add_value_int(entry, "VU Event Identifier", le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei));
- json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_len));
- json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst));
- json_object_add_value_int(entry, "Reserved", le64_to_cpu(vu_event_id_str_table_arr[j].reserved));
- json_array_add_value_object(vu_eve_table, entry);
- }
- json_object_add_value_array(root, "VU Event Identifier String Table Entry", vu_eve_table);
-
- memset((void *)ascii, 0, ascii_table_index);
- for (j = 0; j < ascii_table_index; j++)
- ascii += sprintf(ascii, "%c", ascii_table_info_arr[j]);
- json_object_add_value_string(root, "ASCII Table", ascii_buf);
-
- json_print_object(root, NULL);
- printf("\n");
- json_free_object(root);
- json_free_object(stat_table);
- json_free_object(eve_table);
- json_free_object(vu_eve_table);
-
- return 0;
-}
-
-static void ocp_print_c9_log_binary(__u8 *log_data_buf,int total_log_page_size)
-{
- return d_raw((unsigned char *)log_data_buf, total_log_page_size);
+/* Function declaration for TCG Configuration log page (LID:C7h) */
+static int ocp_tcg_configuration_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
+
+static int ocp_print_C7_log_normal(struct nvme_dev *dev,
+ struct tcg_configuration_log *log_data)
+{
+ int j;
+
+ printf("TCG Configuration C7 Log Page Data-\n");
+
+ printf(" State : 0x%x\n", log_data->state);
+ printf(" Reserved1 : 0x");
+ for (j = 0; j < 3; j++)
+ printf("%d", log_data->rsvd1[j]);
+ printf("\n");
+ printf(" Locking SP Activation Count : 0x%x\n", log_data->locking_sp_act_count);
+ printf(" Tper Revert Count : 0x%x\n", log_data->type_rev_count);
+ printf(" Locking SP Revert Count : 0x%x\n", log_data->locking_sp_rev_count);
+ printf(" Number of Locking Objects : 0x%x\n", log_data->no_of_locking_obj);
+ printf(" Number of Single User Mode Locking Objects : 0x%x\n", log_data->no_of_single_um_locking_obj);
+ printf(" Number of Range Provisioned Locking Objects : 0x%x\n", log_data->no_of_range_prov_locking_obj);
+ printf(" Number of Namespace Provisioned Locking Objects : 0x%x\n", log_data->no_of_ns_prov_locking_obj);
+ printf(" Number of Read Locked Locking Objects : 0x%x\n", log_data->no_of_read_lock_locking_obj);
+ printf(" Number of Write Locked Locking Objects : 0x%x\n", log_data->no_of_write_lock_locking_obj);
+ printf(" Number of Read Unlocked Locking Objects : 0x%x\n", log_data->no_of_read_unlock_locking_obj);
+ printf(" Number of Write Unlocked Locking Objects : 0x%x\n", log_data->no_of_write_unlock_locking_obj);
+ printf(" Reserved2 : 0x%x\n", log_data->rsvd2);
+
+ printf(" SID Authentication Try Count : 0x%x\n", le32_to_cpu(log_data->sid_auth_try_count));
+ printf(" SID Authentication Try Limit : 0x%x\n", le32_to_cpu(log_data->sid_auth_try_limit));
+ printf(" Programmatic TCG Reset Count : 0x%x\n", le32_to_cpu(log_data->pro_tcg_rc));
+ printf(" Programmatic Reset Lock Count : 0x%x\n", le32_to_cpu(log_data->pro_rlc));
+ printf(" TCG Error Count : 0x%x\n", le32_to_cpu(log_data->tcg_ec));
+
+ printf(" Reserved3 : 0x");
+ for (j = 0; j < 458; j++)
+ printf("%d", log_data->rsvd3[j]);
+ printf("\n");
+
+ printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version));
+ printf(" Log page GUID : 0x");
+ for (j = C7_GUID_LENGTH - 1; j >= 0; j--)
+ printf("%x", log_data->log_page_guid[j]);
+ printf("\n");
+
+ return 0;
}
-static int get_c9_log_page(struct nvme_dev *dev, char *format)
+static void ocp_print_C7_log_json(struct tcg_configuration_log *log_data)
{
- int ret = 0;
- __u8 *header_data;
- struct telemetry_str_log_format *log_data;
- enum nvme_print_flags fmt;
- __u8 *full_log_buf_data = NULL;
- __le64 stat_id_str_table_ofst = 0;
- __le64 event_str_table_ofst = 0;
- __le64 vu_event_str_table_ofst = 0;
- __le64 ascii_table_ofst = 0;
- __le64 total_log_page_sz = 0;
-
- ret = validate_output_format(format, &fmt);
- if (ret < 0) {
- fprintf(stderr, "ERROR : OCP : invalid output format\n");
- return ret;
- }
-
- header_data = (__u8 *)malloc(sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN);
- if (!header_data) {
- fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
- return -1;
- }
- memset(header_data, 0, sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN);
-
- ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE,
- C9_TELEMETRY_STR_LOG_LEN, header_data);
-
- if (!ret) {
- log_data = (struct telemetry_str_log_format *)header_data;
- printf("Statistics Identifier String Table Size = %lld\n",log_data->sitsz);
- printf("Event String Table Size = %lld\n",log_data->estsz);
- printf("VU Event String Table Size = %lld\n",log_data->vu_eve_st_sz);
- printf("ASCII Table Size = %lld\n",log_data->asctsz);
-
- //Calculating the offset for dynamic fields.
- stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4);
- event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4);
- vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4);
- ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4);
- total_log_page_sz = stat_id_str_table_ofst + event_str_table_ofst + vu_event_str_table_ofst + ascii_table_ofst;
-
- printf("stat_id_str_table_ofst = %lld\n",stat_id_str_table_ofst);
- printf("event_str_table_ofst = %lld\n",event_str_table_ofst);
- printf("vu_event_str_table_ofst = %lld\n",vu_event_str_table_ofst);
- printf("ascii_table_ofst = %lld\n",ascii_table_ofst);
- printf("total_log_page_sz = %lld\n",total_log_page_sz);
-
- full_log_buf_data = (__u8 *)malloc(sizeof(__u8) * total_log_page_sz);
- if (!full_log_buf_data) {
- fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
- return -1;
- }
- memset(full_log_buf_data, 0, sizeof(__u8) * total_log_page_sz);
-
- ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE,
- total_log_page_sz, full_log_buf_data);
-
- if (!ret) {
- switch (fmt) {
- case NORMAL:
- ocp_print_C9_log_normal(log_data,full_log_buf_data);
- break;
- case JSON:
- ocp_print_C9_log_json(log_data,full_log_buf_data);
- break;
- case BINARY:
- ocp_print_c9_log_binary(full_log_buf_data,total_log_page_sz);
- break;
- default:
- fprintf(stderr, "unhandled output format\n");
- break;
- }
- } else{
- fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n");
- }
- } else {
- fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n");
- }
-
- free(header_data);
- free(full_log_buf_data);
-
- return ret;
+ int j;
+ struct json_object *root;
+ char guid_buf[C7_GUID_LENGTH];
+ char *guid = guid_buf;
+ char res_arr[458];
+ char *res = res_arr;
+
+ root = json_create_object();
+
+ json_object_add_value_int(root, "State", le16_to_cpu(log_data->state));
+ memset((__u8 *)res, 0, 3);
+ for (j = 0; j < 3; j++)
+ res += sprintf(res, "%d", log_data->rsvd1[j]);
+ json_object_add_value_string(root, "Reserved1", res_arr);
+ json_object_add_value_int(root, "Locking SP Activation Count", le16_to_cpu(log_data->locking_sp_act_count));
+ json_object_add_value_int(root, "Tper Revert Count", le16_to_cpu(log_data->locking_sp_rev_count));
+ json_object_add_value_int(root, "Number of Locking Objects", le16_to_cpu(log_data->no_of_locking_obj));
+ json_object_add_value_int(root, "Number of Single User Mode Locking Objects", le16_to_cpu(log_data->no_of_single_um_locking_obj));
+ json_object_add_value_int(root, "Number of Range Provisioned Locking Objects", le16_to_cpu(log_data->no_of_range_prov_locking_obj));
+ json_object_add_value_int(root, "Number of Namespace Provisioned Locking Objects", le16_to_cpu(log_data->no_of_ns_prov_locking_obj));
+ json_object_add_value_int(root, "Number of Read Locked Locking Objects", le16_to_cpu(log_data->no_of_read_lock_locking_obj));
+ json_object_add_value_int(root, "Number of Write Locked Locking Objects", le16_to_cpu(log_data->no_of_write_lock_locking_obj));
+ json_object_add_value_int(root, "Number of Read Unlocked Locking Objects", le16_to_cpu(log_data->no_of_read_unlock_locking_obj));
+ json_object_add_value_int(root, "Number of Write Unlocked Locking Objects", le16_to_cpu(log_data->no_of_write_unlock_locking_obj));
+ json_object_add_value_int(root, "Reserved2", le16_to_cpu(log_data->rsvd2));
+
+ json_object_add_value_int(root, "SID Authentication Try Count", le16_to_cpu(log_data->sid_auth_try_count));
+ json_object_add_value_int(root, "SID Authentication Try Limit", le16_to_cpu(log_data->sid_auth_try_limit));
+ json_object_add_value_int(root, "Programmatic TCG Reset Count", le16_to_cpu(log_data->pro_tcg_rc));
+ json_object_add_value_int(root, "Programmatic Reset Lock Count", le16_to_cpu(log_data->pro_rlc));
+ json_object_add_value_int(root, "TCG Error Count", le16_to_cpu(log_data->tcg_ec));
+
+ memset((__u8 *)res, 0, 458);
+ for (j = 0; j < 458; j++)
+ res += sprintf(res, "%d", log_data->rsvd3[j]);
+ json_object_add_value_string(root, "Reserved3", res_arr);
+
+ json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+
+ memset((void *)guid, 0, C7_GUID_LENGTH);
+ for (j = C7_GUID_LENGTH - 1; j >= 0; j--)
+ guid += sprintf(guid, "%02x", log_data->log_page_guid[j]);
+ json_object_add_value_string(root, "Log page GUID", guid_buf);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
}
-static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd,
- struct plugin *plugin)
+static void ocp_print_c7_log_binary(struct tcg_configuration_log *log_data)
{
- struct nvme_dev *dev;
- int ret = 0;
- const char *desc = "Retrieve telemetry string log format";
+ return d_raw((unsigned char *)log_data, sizeof(*log_data));
+}
- struct config {
- char *output_format;
- };
+static int get_c7_log_page(struct nvme_dev *dev, char *format)
+{
+ nvme_print_flags_t fmt;
+ int ret;
+ __u8 *data;
+ int i;
+ struct tcg_configuration_log *log_data;
+ int j;
- struct config cfg = {
- .output_format = "normal",
- };
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR : OCP : invalid output format\n");
+ return ret;
+ }
- OPT_ARGS(opts) = {
- OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"),
- OPT_END()
- };
+ data = (__u8 *)malloc(sizeof(__u8) * C7_TCG_CONFIGURATION_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * C7_TCG_CONFIGURATION_LEN);
- ret = parse_and_open(&dev, argc, argv, desc, opts);
- if (ret)
- return ret;
+ ret = nvme_get_log_simple(dev_fd(dev), C7_TCG_CONFIGURATION_OPCODE,
+ C7_TCG_CONFIGURATION_LEN, data);
+ if (!ret) {
+ log_data = (struct tcg_configuration_log *)data;
- ret = get_c9_log_page(dev, cfg.output_format);
- if (ret)
- fprintf(stderr, "ERROR : OCP : Failure reading the C9 Log Page, ret = %d\n", ret);
+ /* check log page version */
+ if (log_data->log_page_version != C7_TCG_CONFIGURATION_LOG_VERSION) {
+ fprintf(stderr, "ERROR : OCP : invalid TCG Configuration Log Page version\n");
+ ret = -1;
+ goto out;
+ }
- dev_close(dev);
+ /*
+ * check log page guid
+ * Verify GUID matches
+ */
+ for (i = 0; i < 16; i++) {
+ if (tcg_configuration_guid[i] != log_data->log_page_guid[i]) {
+ fprintf(stderr, "ERROR : OCP : Unknown GUID in C7 Log Page data\n");
+ fprintf(stderr, "ERROR : OCP : Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", tcg_configuration_guid[j]);
+ fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_data->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ switch (fmt) {
+ case NORMAL:
+ ocp_print_C7_log_normal(dev, log_data);
+ break;
+ case JSON:
+ ocp_print_C7_log_json(log_data);
+ break;
+ case BINARY:
+ ocp_print_c7_log_binary(log_data);
+ break;
+ default:
+ break;
+ }
+ } else {
+ fprintf(stderr, "ERROR : OCP : Unable to read C7 data from buffer\n");
+ }
- return ret;
+out:
+ free(data);
+ return ret;
+}
+
+
+static int ocp_tcg_configuration_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve TCG Configuration Log Page Data";
+ struct nvme_dev *dev;
+ int ret = 0;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_c7_log_page(dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : OCP : Failure reading the C7 Log Page, ret = %d\n", ret);
+
+ dev_close(dev);
+ return ret;
}
///////////////////////////////////////////////////////////////////////////////
@@ -2969,3 +3969,177 @@ static int fw_activation_history_log(int argc, char **argv, struct command *cmd,
{
return ocp_fw_activation_history_log(argc, argv, cmd, plugin);
}
+
+static int error_injection_get(struct nvme_dev *dev, const __u8 sel, bool uuid)
+{
+ struct erri_get_cq_entry cq_entry;
+ int err;
+ int i;
+ const __u8 fid = 0xc0;
+
+ _cleanup_free_ struct erri_entry *entry = NULL;
+
+ struct nvme_get_features_args args = {
+ .result = (__u32 *)&cq_entry,
+ .data = entry,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .sel = sel,
+ .data_len = sizeof(*entry) * ERRI_ENTRIES_MAX,
+ .fid = fid,
+ };
+
+ if (uuid) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &args.uuidx);
+ if (err || !args.uuidx) {
+ nvme_show_error("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
+ entry = nvme_alloc(args.data_len);
+ if (!entry) {
+ nvme_show_error("malloc: %s", strerror(errno));
+ return -errno;
+ }
+
+ err = nvme_cli_get_features(dev, &args);
+ if (!err) {
+ nvme_show_result("Number of Error Injecttions (feature: %#0*x): %#0*x (%s: %d)",
+ fid ? 4 : 2, fid, cq_entry.nume ? 10 : 8, cq_entry.nume,
+ nvme_select_to_string(sel), cq_entry.nume);
+ if (sel == NVME_GET_FEATURES_SEL_SUPPORTED)
+ nvme_show_select_result(fid, *args.result);
+ for (i = 0; i < cq_entry.nume; i++) {
+ printf("Entry: %d, Flags: %x (%s%s), Type: %x (%s), NRTDP: %d\n", i,
+ entry->flags, entry->enable ? "Enabled" : "Disabled",
+ entry->single ? ", Single instance" : "", entry->type,
+ erri_type_to_string(entry->type), entry->nrtdp);
+ }
+ } else {
+ nvme_show_error("Could not get feature: %#0*x.", fid ? 4 : 2, fid);
+ }
+
+ return err;
+}
+
+static int get_error_injection(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Return set of error injection";
+ int err;
+ struct config {
+ __u8 sel;
+ };
+ struct config cfg = { 0 };
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("sel", 's', &cfg.sel, sel),
+ OPT_FLAG("no-uuid", 'n', NULL, no_uuid),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ return error_injection_get(dev, cfg.sel, !argconfig_parse_seen(opts, "no-uuid"));
+}
+
+static int error_injection_set(struct nvme_dev *dev, struct erri_config *cfg, bool uuid)
+{
+ int err;
+ __u32 result;
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = 0xc0,
+ .cdw11 = cfg->number,
+ .data_len = cfg->number * sizeof(struct erri_entry),
+ .timeout = nvme_cfg.timeout,
+ .result = &result,
+ };
+
+ _cleanup_fd_ int ffd = -1;
+
+ _cleanup_free_ struct erri_entry *entry = NULL;
+
+ if (uuid) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &args.uuidx);
+ if (err || !args.uuidx) {
+ nvme_show_error("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
+ entry = nvme_alloc(args.data_len);
+ if (!entry) {
+ nvme_show_error("malloc: %s", strerror(errno));
+ return -errno;
+ }
+
+ if (cfg->file && strlen(cfg->file)) {
+ ffd = open(cfg->file, O_RDONLY);
+ if (ffd < 0) {
+ nvme_show_error("Failed to open file %s: %s", cfg->file, strerror(errno));
+ return -EINVAL;
+ }
+ err = read(ffd, entry, args.data_len);
+ if (err < 0) {
+ nvme_show_error("failed to read data buffer from input file: %s",
+ strerror(errno));
+ return -errno;
+ }
+ } else {
+ entry->enable = 1;
+ entry->single = 1;
+ entry->type = cfg->type;
+ entry->nrtdp = cfg->nrtdp;
+ }
+
+ args.data = entry;
+
+ err = nvme_set_features(&args);
+ if (err) {
+ if (err < 0)
+ nvme_show_error("set-error-injection: %s", nvme_strerror(errno));
+ else if (err > 0)
+ nvme_show_status(err);
+ return err;
+ }
+
+ printf("set-error-injection, data: %s, number: %d, uuid: %d, type: %d, nrtdp: %d\n",
+ cfg->file, cfg->number, args.uuidx, cfg->type, cfg->nrtdp);
+ if (args.data)
+ d(args.data, args.data_len, 16, 1);
+
+ return 0;
+}
+
+static int set_error_injection(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Inject error conditions";
+ int err;
+ struct erri_config cfg = {
+ .number = 1,
+ };
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+
+ NVME_ARGS(opts,
+ OPT_FILE("data", 'd', &cfg.file, data),
+ OPT_BYTE("number", 'n', &cfg.number, number),
+ OPT_FLAG("no-uuid", 'N', NULL, no_uuid),
+ OPT_SHRT("type", 't', &cfg.type, type),
+ OPT_SHRT("nrtdp", 'r', &cfg.nrtdp, nrtdp));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ return error_injection_set(dev, &cfg, !argconfig_parse_seen(opts, "no-uuid"));
+}
diff --git a/plugins/ocp/ocp-nvme.h b/plugins/ocp/ocp-nvme.h
index 95539b0..16d929d 100644
--- a/plugins/ocp/ocp-nvme.h
+++ b/plugins/ocp/ocp-nvme.h
@@ -11,9 +11,10 @@
#if !defined(OCP_NVME) || defined(CMD_HEADER_MULTI_READ)
#define OCP_NVME
+#define OCP_PLUGIN_VERSION "2.9.0"
#include "cmd.h"
-PLUGIN(NAME("ocp", "OCP cloud SSD extensions", NVME_VERSION),
+PLUGIN(NAME("ocp", "OCP cloud SSD extensions", OCP_PLUGIN_VERSION),
COMMAND_LIST(
ENTRY("smart-add-log", "Retrieve extended SMART Information", smart_add_log)
ENTRY("latency-monitor-log", "Get Latency Monitor Log Page", ocp_latency_monitor_log)
@@ -26,10 +27,17 @@ PLUGIN(NAME("ocp", "OCP cloud SSD extensions", NVME_VERSION),
ENTRY("unsupported-reqs-log", "Get Unsupported Requirements Log Page", ocp_unsupported_requirements_log)
ENTRY("error-recovery-log", "Retrieve Error Recovery Log Page", ocp_error_recovery_log)
ENTRY("device-capability-log", "Get Device capabilities Requirements Log Page", ocp_device_capabilities_log)
- ENTRY("set-dssd-power-state-feature", "Get Device capabilities Requirements Log Page", set_dssd_power_state_feature)
+ ENTRY("set-dssd-power-state-feature", "Set DSSD Power State feature", set_dssd_power_state_feature)
+ ENTRY("get-dssd-power-state-feature", "Get DSSD Power State feature", get_dssd_power_state_feature)
ENTRY("set-plp-health-check-interval", "Set PLP Health Check Interval", set_plp_health_check_interval)
ENTRY("get-plp-health-check-interval", "Get PLP Health Check Interval", get_plp_health_check_interval)
ENTRY("telemetry-string-log", "Retrieve Telemetry string Log Page", ocp_telemetry_str_log_format)
+ ENTRY("set-telemetry-profile", "Set Telemetry Profile Feature", ocp_set_telemetry_profile_feature)
+ ENTRY("set-dssd-async-event-config", "Set DSSD Async Event Config", set_dssd_async_event_config)
+ ENTRY("get-dssd-async-event-config", "Get DSSD Async Event Config", get_dssd_async_event_config)
+ ENTRY("tcg-configuration-log", "Retrieve TCG Configuration Log Page", ocp_tcg_configuration_log)
+ ENTRY("get-error-injection", "Return set of error injection", get_error_injection)
+ ENTRY("set-error-injection", "Inject error conditions", set_error_injection)
)
);
diff --git a/plugins/ocp/ocp-smart-extended-log.c b/plugins/ocp/ocp-smart-extended-log.c
index 0d8ba81..6a524d3 100644
--- a/plugins/ocp/ocp-smart-extended-log.c
+++ b/plugins/ocp/ocp-smart-extended-log.c
@@ -252,7 +252,7 @@ static void ocp_print_C0_log_json(void *data)
static int get_c0_log_page(int fd, char *format)
{
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
__u8 *data;
int i;
int ret;
diff --git a/plugins/ocp/ocp-telemetry-decode.c b/plugins/ocp/ocp-telemetry-decode.c
new file mode 100644
index 0000000..11963be
--- /dev/null
+++ b/plugins/ocp/ocp-telemetry-decode.c
@@ -0,0 +1,1566 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (c) 2024 Western Digital Corporation or its affiliates.
+ *
+ * Authors: Jeff Lien <jeff.lien@wdc.com>,
+ */
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "util/types.h"
+#include "nvme-print.h"
+
+#include "ocp-telemetry-decode.h"
+
+
+void print_vu_event_data(__u32 size, __u8 *data)
+{
+ int j;
+ __u16 vu_event_id = *(__u16 *)data;
+
+ printf(" VU Event ID : 0x%02x\n", le16_to_cpu(vu_event_id));
+ printf(" VU Data : 0x");
+ for (j = 2; j < size; j++)
+ printf("%x", data[j]);
+ printf("\n\n");
+}
+
+void print_stats_desc(struct telemetry_stats_desc *stat_desc)
+{
+ int j;
+ /* Get the statistics Identifier string name and data size */
+ __u16 stat_id = stat_desc->id;
+ __u32 stat_data_sz = ((stat_desc->size) * 4);
+
+ printf("Statistics Identifier : 0x%x, %s\n",
+ stat_id, telemetry_stat_id_to_string(stat_id));
+ printf("Statistics info : 0x%x\n", stat_desc->info);
+ printf("NS info : 0x%x\n", stat_desc->ns_info);
+ printf("Statistic Data Size : 0x%x\n", le16_to_cpu(stat_data_sz));
+
+ if (stat_data_sz > 0) {
+ printf("%s : 0x",
+ telemetry_stat_id_to_string(stat_id));
+ for (j = 0; j < stat_data_sz; j++)
+ printf("%02x", stat_desc->data[j]);
+ printf("\n");
+ }
+ printf("\n");
+}
+
+void print_telemetry_fifo_event(__u8 class_type,
+ __u16 id, __u8 size_dw, __u8 *data)
+{
+ int j;
+ const char *class_str = NULL;
+ __u32 size = size_dw * 4;
+ char time_str[40];
+ uint64_t timestamp = 0;
+
+ memset((void *)time_str, '\0', 40);
+
+ if (class_type) {
+ class_str = telemetry_event_class_to_string(class_type);
+ printf("Event Class : %s\n", class_str);
+ }
+
+ switch (class_type) {
+ case TELEMETRY_TIMESTAMP_CLASS:
+ timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(*(uint64_t *)data));
+
+ memset((void *)time_str, 0, 9);
+ sprintf((char *)time_str, "%04d:%02d:%02d", (int)(le64_to_cpu(timestamp)/3600),
+ (int)((le64_to_cpu(timestamp%3600)/60)),
+ (int)(le64_to_cpu(timestamp%60)));
+
+ printf(" Event ID : 0x%02x %s\n", id, telemetry_ts_event_to_string(id));
+ printf(" Timestamp : %s\n", time_str);
+ printf(" Size : %d\n", size);
+ if (size > 8) {
+ printf(" VU Data : 0x");
+ for (j = 8; j < size; j++)
+ printf("%02x", data[j]);
+ printf("\n\n");
+ }
+ break;
+
+ case TELEMETRY_PCIE_CLASS:
+ printf(" Event ID : 0x%02x %s\n",
+ id, telemetry_pcie_event_id_to_string(id));
+ printf(" State : 0x%02x %s\n",
+ data[0], telemetry_pcie_state_data_to_string(data[0]));
+ printf(" Speed : 0x%02x %s\n",
+ data[1], telemetry_pcie_speed_data_to_string(data[1]));
+ printf(" Width : 0x%02x %s\n",
+ data[2], telemetry_pcie_width_data_to_string(data[2]));
+ if (size > 4) {
+ printf(" VU Data : ");
+ for (j = 4; j < size; j++)
+ printf("%x", data[j]);
+ printf("\n\n");
+ }
+ break;
+
+ case TELEMETRY_NVME_CLASS:
+ printf(" Event ID : 0x%02x %s\n",
+ id, telemetry_nvme_event_id_to_string(id));
+ if ((id == ADMIN_QUEUE_NONZERO_STATUS) ||
+ (id == IO_QUEUE_NONZERO_STATUS)) {
+ printf(" Cmd Op Code : 0x%02x\n", data[0]);
+ __u16 status = *(__u16 *)&data[1];
+ __u16 cmd_id = *(__u16 *)&data[3];
+ __u16 sq_id = *(__u16 *)&data[5];
+
+ printf(" Status Code : 0x%04x\n", le16_to_cpu(status));
+ printf(" Cmd ID : 0x%04x\n", le16_to_cpu(cmd_id));
+ printf(" SQ ID : 0x%04x\n", le16_to_cpu(sq_id));
+ } else if (id == CC_REGISTER_CHANGED) {
+ __u32 cc_reg_data = *(__u32 *)data;
+
+ printf(" CC Reg Data : 0x%08x\n",
+ le32_to_cpu(cc_reg_data));
+ } else if (id == CSTS_REGISTER_CHANGED) {
+ __u32 csts_reg_data = *(__u32 *)data;
+
+ printf(" CSTS Reg Data : 0x%08x\n",
+ le32_to_cpu(csts_reg_data));
+ }
+ if (size > 8)
+ print_vu_event_data(size, (__u8 *)&data[8]);
+ break;
+
+ case TELEMETRY_RESET_CLASS:
+ printf(" Event ID : 0x%02x %s\n",
+ id, telemetry_reset_event_id_to_string(id));
+ if (size)
+ print_vu_event_data(size, data);
+ break;
+
+ case TELEMETRY_BOOT_SEQ_CLASS:
+ printf(" Event ID : 0x%02x %s\n",
+ id, telemetry_boot_seq_event_id_to_string(id));
+ if (size)
+ print_vu_event_data(size, data);
+ break;
+
+ case TELEMETRY_FW_ASSERT_CLASS:
+ printf(" Event ID : 0x%02x %s\n",
+ id, telemetry_fw_assert_event_id_to_string(id));
+ if (size)
+ print_vu_event_data(size, data);
+ break;
+
+ case TELEMETRY_TEMPERATURE_CLASS:
+ printf(" Event ID : 0x%02x %s\n",
+ id, telemetry_temperature_event_id_to_string(id));
+ if (size)
+ print_vu_event_data(size, data);
+ break;
+
+ case TELEMETRY_MEDIA_DBG_CLASS:
+ printf(" Event ID : 0x%02x %s\n",
+ id, telemetry_media_debug_event_id_to_string(id));
+ if (size)
+ print_vu_event_data(size, data);
+ break;
+
+ case TELEMETRY_MEDIA_WEAR_CLASS:
+ printf(" Event ID : 0x%02x %s\n",
+ id, telemetry_media_debug_event_id_to_string(id));
+ __u32 host_tb_written = *(__u32 *)&data[0];
+ __u32 media_tb_written = *(__u32 *)&data[4];
+ __u32 media_tb_erased = *(__u32 *)&data[8];
+
+ printf(" Host TB Written : 0x%04x\n",
+ le16_to_cpu(host_tb_written));
+ printf(" Media TB Written : 0x%04x\n",
+ le16_to_cpu(media_tb_written));
+ printf(" Media TB Erased : 0x%04x\n",
+ le16_to_cpu(media_tb_erased));
+
+ if (size > 12)
+ print_vu_event_data(size, (__u8 *)&data[12]);
+ break;
+
+ case TELEMETRY_STAT_SNAPSHOT_CLASS:
+ printf(" Statistic ID : 0x%02x %s\n",
+ id, telemetry_stat_id_to_string(id));
+ print_stats_desc((struct telemetry_stats_desc *)data);
+ break;
+
+ default:
+ /*
+ * printf("Unknown Event Class Type\n");
+ * printf("Data : 0x");
+ * for (j = 0; j < size; j++)
+ * printf("%x", data[j]);
+ * printf("\n\n");
+ */
+ break;
+ }
+}
+
+struct statistic_entry statistic_identifiers_map[] = {
+ { 0x00, "Error, this entry does not exist." },
+ { 0x01, "Outstanding Admin Commands" },
+ { 0x02, "Host Write Bandwidth"},
+ { 0x03, "GC Write Bandwidth"},
+ { 0x04, "Active Namespaces"},
+ { 0x05, "Internal Write Workload"},
+ { 0x06, "Internal Read Workload"},
+ { 0x07, "Internal Write Queue Depth"},
+ { 0x08, "Internal Read Queue Depth"},
+ { 0x09, "Pending Trim LBA Count"},
+ { 0x0A, "Host Trim LBA Request Count"},
+ { 0x0B, "Current NVMe Power State"},
+ { 0x0C, "Current DSSD Power State"},
+ { 0x0D, "Program Fail Count"},
+ { 0x0E, "Erase Fail Count"},
+ { 0x0F, "Read Disturb Writes"},
+ { 0x10, "Retention Writes"},
+ { 0x11, "Wear Leveling Writes"},
+ { 0x12, "Read Recovery Writes"},
+ { 0x13, "GC Writes"},
+ { 0x14, "SRAM Correctable Count"},
+ { 0x15, "DRAM Correctable Count"},
+ { 0x16, "SRAM Uncorrectable Count"},
+ { 0x17, "DRAM Uncorrectable Count"},
+ { 0x18, "Data Integrity Error Count"},
+ { 0x19, "Read Retry Error Count"},
+ { 0x1A, "PERST Events Count"},
+ { 0x1B, "Max Die Bad Block"},
+ { 0x1C, "Max NAND Channel Bad Block"},
+ { 0x1D, "Minimum NAND Channel Bad Block"}
+};
+
+struct request_data host_log_page_header[] = {
+ { "LogIdentifier", 1 },
+ { "Reserved1", 4 },
+ { "IEEE OUI Identifier", 3 },
+ { "Telemetry Host-Initiated Data Area 1 Last Block", 2 },
+ { "Telemetry Host-Initiated Data Area 2 Last Block", 2 },
+ { "Telemetry Host-Initiated Data Area 3 Last Block", 2 },
+ { "Reserved2", 2 },
+ { "Telemetry Host-Initiated Data Area 4 Last Block", 4 },
+ { "Reserved3", 360 },
+ { "Telemetry Host-Initiated Scope", 1 },
+ { "Telemetry Host Initiated Generation Number", 1 },
+ { "Telemetry Host-Initiated Data Available", 1 },
+ { "Telemetry Controller-Initiated Data Generation Number", 1 }
+};
+
+struct request_data controller_log_page_header[] = {
+ { "LogIdentifier", 1 },
+ { "Reserved1", 4 },
+ { "IEEE OUI Identifier", 3 },
+ { "Telemetry Host-Initiated Data Area 1 Last Block", 2 },
+ { "Telemetry Host-Initiated Data Area 2 Last Block", 2 },
+ { "Telemetry Host-Initiated Data Area 3 Last Block", 2 },
+ { "Reserved2", 2 },
+ { "Telemetry Host-Initiated Data Area 4 Last Block", 4 },
+ { "Reserved3", 361 },
+ { "Telemetry Controller-Initiated Scope", 1 },
+ { "Telemetry Controller-Initiated Data Available", 1 },
+ { "Telemetry Controller-Initiated Data Generation Number", 1 }
+};
+
+struct request_data reason_identifier[] = {
+ { "Error ID", 64 },
+ { "File ID", 8 },
+ { "Line Number", 2 },
+ { "Valid Flags", 1 },
+ { "Reserved", 21 },
+ { "VU Reason Extension", 32 }
+};
+
+struct request_data ocp_header_in_da1[] = {
+ { "Major Version", 2 },
+ { "Minor Version", 2 },
+ { "Reserved1", 4 },
+ { "Timestamp", 8 },
+ { "Log page GUID", 16 },
+ { "Number Telemetry Profiles Supported", 1 },
+ { "Telemetry Profile Selected", 1 },
+ { "Reserved2", 6 },
+ { "Telemetry String Log Size", 8 },
+ { "Reserved3", 8 },
+ { "Firmware Revision", 8 },
+ { "Reserved4", 32 },
+ { "Data Area 1 Statistic Start", 8 },
+ { "Data Area 1 Statistic Size", 8 },
+ { "Data Area 2 Statistic Start", 8 },
+ { "Data Area 2 Statistic Size", 8 },
+ { "Reserved5", 32 },
+ { "Event FIFO 1 Data Area", 1 },
+ { "Event FIFO 2 Data Area", 1 },
+ { "Event FIFO 3 Data Area", 1 },
+ { "Event FIFO 4 Data Area", 1 },
+ { "Event FIFO 5 Data Area", 1 },
+ { "Event FIFO 6 Data Area", 1 },
+ { "Event FIFO 7 Data Area", 1 },
+ { "Event FIFO 8 Data Area", 1 },
+ { "Event FIFO 9 Data Area", 1 },
+ { "Event FIFO 10 Data Area", 1 },
+ { "Event FIFO 11 Data Area", 1 },
+ { "Event FIFO 12 Data Area", 1 },
+ { "Event FIFO 13 Data Area", 1 },
+ { "Event FIFO 14 Data Area", 1 },
+ { "Event FIFO 15 Data Area", 1 },
+ { "Event FIFO 16 Data Area", 1 },
+ { "Event FIFO 1 Start", 8 },
+ { "Event FIFO 1 Size", 8 },
+ { "Event FIFO 2 Start", 8 },
+ { "Event FIFO 2 Size", 8 },
+ { "Event FIFO 3 Start", 8 },
+ { "Event FIFO 3 Size", 8 },
+ { "Event FIFO 4 Start", 8 },
+ { "Event FIFO 4 Size", 8 },
+ { "Event FIFO 5 Start", 8 },
+ { "Event FIFO 5 Size", 8 },
+ { "Event FIFO 6 Start", 8 },
+ { "Event FIFO 6 Size", 8 },
+ { "Event FIFO 7 Start", 8 },
+ { "Event FIFO 7 Size", 8 },
+ { "Event FIFO 8 Start", 8 },
+ { "Event FIFO 8 Size", 8 },
+ { "Event FIFO 9 Start", 8 },
+ { "Event FIFO 9 Size", 8 },
+ { "Event FIFO 10 Start", 8 },
+ { "Event FIFO 10 Size", 8 },
+ { "Event FIFO 11 Start", 8 },
+ { "Event FIFO 11 Size", 8 },
+ { "Event FIFO 12 Start", 8 },
+ { "Event FIFO 12 Size", 8 },
+ { "Event FIFO 13 Start", 8 },
+ { "Event FIFO 13 Size", 8 },
+ { "Event FIFO 14 Start", 8 },
+ { "Event FIFO 14 Size", 8 },
+ { "Event FIFO 15 Start", 8 },
+ { "Event FIFO 15 Size", 8 },
+ { "Event FIFO 16 Start", 8 },
+ { "Event FIFO 16 Size", 8 },
+ { "Reserved6", 80 }
+};
+
+struct request_data smart[] = {
+ { "Critical Warning", 1 },
+ { "Composite Temperature", 2 },
+ { "Available Spare", 1 },
+ { "Available Spare Threshold", 1 },
+ { "Percentage Used", 1 },
+ { "Reserved1", 26 },
+ { "Data Units Read", 16 },
+ { "Data Units Written", 16 },
+ { "Host Read Commands", 16 },
+ { "Host Write Commands", 16 },
+ { "Controller Busy Time", 16 },
+ { "Power Cycles", 16 },
+ { "Power On Hours", 16 },
+ { "Unsafe Shutdowns", 16 },
+ { "Media and Data Integrity Errors", 16 },
+ { "Number of Error Information Log Entries", 16 },
+ { "Warning Composite Temperature Time", 4 },
+ { "Critical Composite Temperature Time", 4 },
+ { "Temperature Sensor 1", 2 },
+ { "Temperature Sensor 2", 2 },
+ { "Temperature Sensor 3", 2 },
+ { "Temperature Sensor 4", 2 },
+ { "Temperature Sensor 5", 2 },
+ { "Temperature Sensor 6", 2 },
+ { "Temperature Sensor 7", 2 },
+ { "Temperature Sensor 8", 2 },
+ { "Thermal Management Temperature 1 Transition Count", 4 },
+ { "Thermal Management Temperature 2 Transition Count", 4 },
+ { "Total Time for Thermal Management Temperature 1", 4 },
+ { "Total Time for Thermal Management Temperature 2", 4 },
+ { "Reserved2", 280 }
+};
+
+struct request_data smart_extended[] = {
+ { "Physical Media Units Written", 16 },
+ { "Physical Media Units Read", 16 },
+ { "Bad User NAND Blocks Raw Count", 6 },
+ { "Bad User NAND Blocks Normalized Value", 2 },
+ { "Bad System NAND Blocks Raw Count", 6 },
+ { "Bad System NAND Blocks Normalized Value", 2 },
+ { "XOR Recovery Count", 8 },
+ { "Uncorrectable Read Error Count", 8 },
+ { "Soft ECC Error Count", 8 },
+ { "End to End Correction Counts Detected Errors", 4 },
+ { "End to End Correction Counts Corrected Errors", 4 },
+ { "System Data Percent Used", 1 },
+ { "Refresh Counts", 7 },
+ { "Maximum User Data Erase Count", 4 },
+ { "Minimum User Data Erase Count", 4 },
+ { "Number of thermal throttling events", 1 },
+ { "Current Throttling Status", 1 },
+ { "Errata Version Field", 1 },
+ { "Point Version Field", 2 },
+ { "Minor Version Field", 2 },
+ { "Major Version Field", 1 },
+ { "PCIe Correctable Error Count", 8 },
+ { "Incomplete Shutdowns", 4 },
+ { "Reserved1", 4 },
+ { "Percent Free Blocks", 1 },
+ { "Reserved2", 7 },
+ { "Capacitor Health", 2 },
+ { "NVMe Base Errata Version", 1 },
+ { "NVMe Command Set Errata Version", 1 },
+ { "Reserved3", 4 },
+ { "Unaligned IO", 8 },
+ { "Security Version Number", 8 },
+ { "Total NUSE", 8 },
+ { "PLP Start Count", 16 },
+ { "Endurance Estimate", 16 },
+ { "PCIe Link Retraining Count", 8 },
+ { "Power State Change Count", 8 },
+ { "Lowest Permitted Firmware Revision", 8 },
+ { "Reserved4", 278 },
+ { "Log Page Version", 2 },
+ { "Log page GUID", 16 }
+};
+
+void json_add_formatted_u32_str(struct json_object *pobject, const char *msg, unsigned int pdata)
+{
+ char data_str[70] = { 0 };
+
+ sprintf(data_str, "0x%x", pdata);
+ json_object_add_value_string(pobject, msg, data_str);
+}
+
+void json_add_formatted_var_size_str(struct json_object *pobject, const char *msg, __u8 *pdata,
+ unsigned int data_size)
+{
+ char description_str[256] = "";
+ char temp_buffer[3] = { 0 };
+
+ for (size_t i = 0; i < data_size; ++i) {
+ sprintf(temp_buffer, "%02X", pdata[i]);
+ strcat(description_str, temp_buffer);
+ }
+
+ json_object_add_value_string(pobject, msg, description_str);
+}
+
+int get_telemetry_das_offset_and_size(
+ struct nvme_ocp_telemetry_common_header *ptelemetry_common_header,
+ struct nvme_ocp_telemetry_offsets *ptelemetry_das_offset)
+{
+ if (NULL == ptelemetry_common_header || NULL == ptelemetry_das_offset) {
+ nvme_show_error("Invalid input arguments.");
+ return -1;
+ }
+
+ if (ptelemetry_common_header->log_id == NVME_LOG_LID_TELEMETRY_HOST)
+ ptelemetry_das_offset->header_size =
+ sizeof(struct nvme_ocp_telemetry_host_initiated_header);
+ else if (ptelemetry_common_header->log_id == NVME_LOG_LID_TELEMETRY_CTRL)
+ ptelemetry_das_offset->header_size =
+ sizeof(struct nvme_ocp_telemetry_controller_initiated_header);
+ else
+ return -1;
+
+ ptelemetry_das_offset->da1_start_offset = ptelemetry_das_offset->header_size;
+ ptelemetry_das_offset->da1_size = ptelemetry_common_header->da1_last_block *
+ OCP_TELEMETRY_DATA_BLOCK_SIZE;
+
+ ptelemetry_das_offset->da2_start_offset = ptelemetry_das_offset->da1_start_offset +
+ ptelemetry_das_offset->da1_size;
+ ptelemetry_das_offset->da2_size =
+ (ptelemetry_common_header->da2_last_block -
+ ptelemetry_common_header->da1_last_block) * OCP_TELEMETRY_DATA_BLOCK_SIZE;
+
+ ptelemetry_das_offset->da3_start_offset = ptelemetry_das_offset->da2_start_offset +
+ ptelemetry_das_offset->da2_size;
+ ptelemetry_das_offset->da3_size =
+ (ptelemetry_common_header->da3_last_block -
+ ptelemetry_common_header->da2_last_block) * OCP_TELEMETRY_DATA_BLOCK_SIZE;
+
+ ptelemetry_das_offset->da4_start_offset = ptelemetry_das_offset->da3_start_offset +
+ ptelemetry_das_offset->da3_size;
+ ptelemetry_das_offset->da4_size =
+ (ptelemetry_common_header->da4_last_block -
+ ptelemetry_common_header->da3_last_block) * OCP_TELEMETRY_DATA_BLOCK_SIZE;
+
+ return 0;
+}
+
+int get_static_id_ascii_string(int identifier, char *description)
+{
+ if (pstring_buffer == NULL)
+ return -1;
+
+ struct nvme_ocp_telemetry_string_header *pocp_ts_header =
+ (struct nvme_ocp_telemetry_string_header *)pstring_buffer;
+
+ //Calculating the sizes of the tables. Note: Data is present in the form of DWORDS,
+ //So multiplying with sizeof(DWORD)
+ unsigned long long sits_table_size = (pocp_ts_header->sitsz) * SIZE_OF_DWORD;
+
+ //Calculating number of entries present in all 3 tables
+ int sits_entries = (int)sits_table_size /
+ sizeof(struct nvme_ocp_statistics_identifier_string_table);
+
+ for (int sits_entry = 0; sits_entry < sits_entries; sits_entry++) {
+ struct nvme_ocp_statistics_identifier_string_table
+ *peach_statistic_entry =
+ (struct nvme_ocp_statistics_identifier_string_table *)
+ (pstring_buffer + (pocp_ts_header->sits * SIZE_OF_DWORD) +
+ (sits_entry *
+ sizeof(struct nvme_ocp_statistics_identifier_string_table)));
+
+ if (identifier == (int)peach_statistic_entry->vs_statistic_identifier) {
+ char *pdescription = (char *)(pstring_buffer +
+ (pocp_ts_header->ascts * SIZE_OF_DWORD) +
+ (peach_statistic_entry->ascii_id_offset *
+ SIZE_OF_DWORD));
+
+ memcpy(description, pdescription,
+ peach_statistic_entry->ascii_id_length + 1);
+
+ // If ASCII string isn't found, see in our internal Map
+ // for 2.5 Spec defined strings (id < 0x1D).
+ if ((description == NULL) && (identifier < 0x1D))
+ memcpy(description,
+ statistic_identifiers_map[identifier].description,
+ peach_statistic_entry->ascii_id_length + 1);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int get_event_id_ascii_string(int identifier, int debug_event_class, char *description)
+{
+ if (pstring_buffer == NULL)
+ return -1;
+
+ struct nvme_ocp_telemetry_string_header *pocp_ts_header =
+ (struct nvme_ocp_telemetry_string_header *)pstring_buffer;
+
+ //Calculating the sizes of the tables. Note: Data is present in the form of DWORDS,
+ //So multiplying with sizeof(DWORD)
+ unsigned long long ests_table_size = (pocp_ts_header->estsz) * SIZE_OF_DWORD;
+
+ //Calculating number of entries present in all 3 tables
+ int ests_entries = (int)ests_table_size / sizeof(struct nvme_ocp_event_string_table);
+
+ for (int ests_entry = 0; ests_entry < ests_entries; ests_entry++) {
+ struct nvme_ocp_event_string_table *peach_event_entry =
+ (struct nvme_ocp_event_string_table *)
+ (pstring_buffer + (pocp_ts_header->ests * SIZE_OF_DWORD) +
+ (ests_entry * sizeof(struct nvme_ocp_event_string_table)));
+
+ if (identifier == (int)peach_event_entry->event_identifier &&
+ debug_event_class == (int)peach_event_entry->debug_event_class) {
+ char *pdescription = (char *)(pstring_buffer +
+ (pocp_ts_header->ascts * SIZE_OF_DWORD) +
+ (peach_event_entry->ascii_id_offset * SIZE_OF_DWORD));
+
+ memcpy(description, pdescription,
+ peach_event_entry->ascii_id_length + 1);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int get_vu_event_id_ascii_string(int identifier, int debug_event_class, char *description)
+{
+ if (pstring_buffer == NULL)
+ return -1;
+
+ struct nvme_ocp_telemetry_string_header *pocp_ts_header =
+ (struct nvme_ocp_telemetry_string_header *)pstring_buffer;
+
+ //Calculating the sizes of the tables. Note: Data is present in the form of DWORDS,
+ //So multiplying with sizeof(DWORD)
+ unsigned long long vuests_table_size = (pocp_ts_header->vu_estsz) * SIZE_OF_DWORD;
+
+ //Calculating number of entries present in all 3 tables
+ int vu_ests_entries = (int)vuests_table_size /
+ sizeof(struct nvme_ocp_vu_event_string_table);
+
+ for (int vu_ests_entry = 0; vu_ests_entry < vu_ests_entries; vu_ests_entry++) {
+ struct nvme_ocp_vu_event_string_table *peach_vu_event_entry =
+ (struct nvme_ocp_vu_event_string_table *)
+ (pstring_buffer + (pocp_ts_header->vu_ests * SIZE_OF_DWORD) +
+ (vu_ests_entry * sizeof(struct nvme_ocp_vu_event_string_table)));
+
+ if (identifier == (int)peach_vu_event_entry->vu_event_identifier &&
+ debug_event_class ==
+ (int)peach_vu_event_entry->debug_event_class) {
+ char *pdescription = (char *)(pstring_buffer +
+ (pocp_ts_header->ascts * SIZE_OF_DWORD) +
+ (peach_vu_event_entry->ascii_id_offset * SIZE_OF_DWORD));
+
+ memcpy(description, pdescription,
+ peach_vu_event_entry->ascii_id_length + 1);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int parse_ocp_telemetry_string_log(int event_fifo_num, int identifier, int debug_event_class,
+ enum ocp_telemetry_string_tables string_table, char *description)
+{
+ if (pstring_buffer == NULL)
+ return -1;
+
+ if (event_fifo_num != 0) {
+ struct nvme_ocp_telemetry_string_header *pocp_ts_header =
+ (struct nvme_ocp_telemetry_string_header *)pstring_buffer;
+
+ if (*pocp_ts_header->fifo_ascii_string[event_fifo_num-1] != '\0')
+ memcpy(description, pocp_ts_header->fifo_ascii_string[event_fifo_num-1],
+ 16);
+ else
+ description = "";
+
+ return 0;
+ }
+
+ if (string_table == STATISTICS_IDENTIFIER_STRING)
+ get_static_id_ascii_string(identifier, description);
+ else if (string_table == EVENT_STRING)
+ get_event_id_ascii_string(identifier, debug_event_class, description);
+ else if (string_table == VU_EVENT_STRING)
+ get_vu_event_id_ascii_string(identifier, debug_event_class, description);
+
+ return 0;
+}
+
+void parse_time_stamp_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp)
+{
+ struct nvme_ocp_time_stamp_dbg_evt_class_format *ptime_stamp_event =
+ (struct nvme_ocp_time_stamp_dbg_evt_class_format *) pevent_specific_data;
+
+ int vu_event_id = (int)ptime_stamp_event->vu_event_identifier;
+
+ unsigned int data_size = ((pevent_descriptor->event_data_size * SIZE_OF_DWORD)-
+ sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format));
+
+ __u8 *pdata = (__u8 *)ptime_stamp_event +
+ sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format);
+
+ char description_str[256] = "";
+
+ parse_ocp_telemetry_string_log(0, ptime_stamp_event->vu_event_identifier,
+ pevent_descriptor->debug_event_class_type,
+ VU_EVENT_STRING, description_str);
+
+ if (pevent_fifos_object != NULL) {
+ json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA,
+ ptime_stamp_event->time_stamp, DATA_SIZE_8);
+ json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING,
+ vu_event_id);
+ json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING,
+ description_str);
+ json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata,
+ data_size);
+ } else {
+ if (fp) {
+ print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA,
+ ptime_stamp_event->time_stamp, DATA_SIZE_8, fp);
+ fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ } else {
+ print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA,
+ ptime_stamp_event->time_stamp, DATA_SIZE_8, fp);
+ printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ printf("%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ }
+ }
+}
+
+void parse_pcie_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp)
+{
+ struct nvme_ocp_pcie_dbg_evt_class_format *ppcie_event =
+ (struct nvme_ocp_pcie_dbg_evt_class_format *) pevent_specific_data;
+ int vu_event_id = (int) ppcie_event->vu_event_identifier;
+ unsigned int data_size = ((pevent_descriptor->event_data_size * SIZE_OF_DWORD) -
+ sizeof(struct nvme_ocp_pcie_dbg_evt_class_format));
+ __u8 *pdata = (__u8 *) ppcie_event + sizeof(struct nvme_ocp_pcie_dbg_evt_class_format);
+ char description_str[256] = "";
+
+ parse_ocp_telemetry_string_log(0, ppcie_event->vu_event_identifier,
+ pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, description_str);
+
+ if (pevent_fifos_object != NULL) {
+ json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA,
+ ppcie_event->pCIeDebugEventData, DATA_SIZE_4);
+ json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING,
+ vu_event_id);
+ json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING,
+ description_str);
+ json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata,
+ data_size);
+ } else {
+ if (fp) {
+ print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA,
+ ppcie_event->pCIeDebugEventData, DATA_SIZE_4, fp);
+ fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ } else {
+ print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA,
+ ppcie_event->pCIeDebugEventData, DATA_SIZE_4, fp);
+ printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ printf("%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ }
+ }
+}
+
+void parse_nvme_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp)
+{
+ struct nvme_ocp_nvme_dbg_evt_class_format *pnvme_event =
+ (struct nvme_ocp_nvme_dbg_evt_class_format *) pevent_specific_data;
+ int vu_event_id = (int) pnvme_event->vu_event_identifier;
+ unsigned int data_size = ((pevent_descriptor->event_data_size *
+ SIZE_OF_DWORD) - sizeof(struct nvme_ocp_nvme_dbg_evt_class_format));
+ __u8 *pdata = (__u8 *) pnvme_event + sizeof(struct nvme_ocp_nvme_dbg_evt_class_format);
+ char description_str[256] = "";
+
+ parse_ocp_telemetry_string_log(0, pnvme_event->vu_event_identifier,
+ pevent_descriptor->debug_event_class_type, VU_EVENT_STRING,
+ description_str);
+
+ if (pevent_fifos_object != NULL) {
+ json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA,
+ pnvme_event->nvmeDebugEventData, DATA_SIZE_8);
+ json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING,
+ vu_event_id);
+ json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING,
+ description_str);
+ json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata,
+ data_size);
+ } else {
+ if (fp) {
+ print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA,
+ pnvme_event->nvmeDebugEventData, DATA_SIZE_8, fp);
+ fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ } else {
+ print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA,
+ pnvme_event->nvmeDebugEventData, DATA_SIZE_8, fp);
+ printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ printf("%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ }
+ }
+}
+
+void parse_common_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp)
+{
+ struct nvme_ocp_common_dbg_evt_class_format *pcommon_debug_event =
+ (struct nvme_ocp_common_dbg_evt_class_format *) pevent_specific_data;
+ int vu_event_id = (int) pcommon_debug_event->vu_event_identifier;
+ unsigned int data_size = ((pevent_descriptor->event_data_size *
+ SIZE_OF_DWORD) - sizeof(struct nvme_ocp_common_dbg_evt_class_format));
+ __u8 *pdata = (__u8 *) pcommon_debug_event +
+ sizeof(struct nvme_ocp_common_dbg_evt_class_format);
+ char description_str[256] = "";
+
+ parse_ocp_telemetry_string_log(0, pcommon_debug_event->vu_event_identifier,
+ pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, description_str);
+
+ if (pevent_fifos_object != NULL) {
+ json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING,
+ vu_event_id);
+ json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING,
+ description_str);
+ json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata,
+ data_size);
+ } else {
+ if (fp) {
+ fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ } else {
+ printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ printf("%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ }
+ }
+}
+
+void parse_media_wear_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp)
+{
+ struct nvme_ocp_media_wear_dbg_evt_class_format *pmedia_wear_event =
+ (struct nvme_ocp_media_wear_dbg_evt_class_format *) pevent_specific_data;
+ int vu_event_id = (int) pmedia_wear_event->vu_event_identifier;
+ unsigned int data_size = ((pevent_descriptor->event_data_size * SIZE_OF_DWORD) -
+ sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format));
+ __u8 *pdata = (__u8 *) pmedia_wear_event +
+ sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format);
+ char description_str[256] = "";
+
+ parse_ocp_telemetry_string_log(0, pmedia_wear_event->vu_event_identifier,
+ pevent_descriptor->debug_event_class_type, VU_EVENT_STRING,
+ description_str);
+
+ if (pevent_fifos_object != NULL) {
+ json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA,
+ pmedia_wear_event->currentMediaWear, DATA_SIZE_12);
+ json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING,
+ vu_event_id);
+ json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING,
+ description_str);
+ json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata,
+ data_size);
+ } else {
+ if (fp) {
+ print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA,
+ pmedia_wear_event->currentMediaWear, DATA_SIZE_12, fp);
+ fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ } else {
+ print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA,
+ pmedia_wear_event->currentMediaWear, DATA_SIZE_12, NULL);
+ printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id);
+ printf("%s: %s\n", STR_VU_EVENT_STRING, description_str);
+ print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp);
+ }
+ }
+}
+
+int parse_event_fifo(unsigned int fifo_num, unsigned char *pfifo_start,
+ struct json_object *pevent_fifos_object, unsigned char *pstring_buffer,
+ struct nvme_ocp_telemetry_offsets *poffsets, __u64 fifo_size, FILE *fp)
+{
+ if (NULL == pfifo_start || NULL == poffsets) {
+ nvme_show_error("Input buffer was NULL");
+ return -1;
+ }
+
+ int status = 0;
+ unsigned int event_fifo_number = fifo_num + 1;
+ char *description = (char *)malloc((40 + 1) * sizeof(char));
+
+ memset(description, 0, sizeof(40));
+
+ status =
+ parse_ocp_telemetry_string_log(event_fifo_number, 0, 0, EVENT_STRING, description);
+
+ if (status != 0) {
+ nvme_show_error("Failed to get C9 String. status: %d\n", status);
+ return -1;
+ }
+
+ char event_fifo_name[100] = {0};
+
+ snprintf(event_fifo_name, sizeof(event_fifo_name), "%s%d%s%s", "EVENT FIFO ",
+ event_fifo_number, " - ", description);
+
+ struct json_object *pevent_fifo_array = NULL;
+
+ if (pevent_fifos_object != NULL)
+ pevent_fifo_array = json_create_array();
+ else {
+ char buffer[1024] = {0};
+
+ sprintf(buffer, "%s%s\n%s", STR_LINE, event_fifo_name, STR_LINE);
+ if (fp)
+ fprintf(fp, "%s", buffer);
+ else
+ printf("%s", buffer);
+ }
+
+ int offset_to_move = 0;
+ unsigned int event_des_size = sizeof(struct nvme_ocp_telemetry_event_descriptor);
+
+ while ((fifo_size > 0) && (offset_to_move < fifo_size)) {
+ struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor =
+ (struct nvme_ocp_telemetry_event_descriptor *)
+ (pfifo_start + offset_to_move);
+
+ if (pevent_descriptor != NULL && pevent_descriptor->event_data_size >= 0) {
+ //Data is present in the form of DWORDS, So multiplying with sizeof(DWORD)
+ unsigned int data_size = pevent_descriptor->event_data_size *
+ SIZE_OF_DWORD;
+
+ __u8 *pevent_specific_data = (__u8 *)pevent_descriptor + event_des_size;
+
+ char description_str[256] = "";
+
+ parse_ocp_telemetry_string_log(0, pevent_descriptor->event_id,
+ pevent_descriptor->debug_event_class_type, EVENT_STRING,
+ description_str);
+
+ struct json_object *pevent_descriptor_obj =
+ ((pevent_fifos_object != NULL)?json_create_object():NULL);
+
+ if (pevent_descriptor_obj != NULL) {
+ json_add_formatted_u32_str(pevent_descriptor_obj,
+ STR_DBG_EVENT_CLASS_TYPE,
+ pevent_descriptor->debug_event_class_type);
+ json_add_formatted_u32_str(pevent_descriptor_obj,
+ STR_EVENT_IDENTIFIER, pevent_descriptor->event_id);
+ json_object_add_value_string(pevent_descriptor_obj,
+ STR_EVENT_STRING, description_str);
+ json_add_formatted_u32_str(pevent_descriptor_obj,
+ STR_EVENT_DATA_SIZE, pevent_descriptor->event_data_size);
+
+ if (pevent_descriptor->debug_event_class_type >= 0x80)
+ json_add_formatted_var_size_str(pevent_descriptor_obj,
+ STR_VU_DATA, pevent_specific_data, data_size);
+ } else {
+ if (fp) {
+ fprintf(fp, "%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE,
+ pevent_descriptor->debug_event_class_type);
+ fprintf(fp, "%s: 0x%x\n", STR_EVENT_IDENTIFIER,
+ pevent_descriptor->event_id);
+ fprintf(fp, "%s: %s\n", STR_EVENT_STRING, description_str);
+ fprintf(fp, "%s: 0x%x\n", STR_EVENT_DATA_SIZE,
+ pevent_descriptor->event_data_size);
+ } else {
+ printf("%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE,
+ pevent_descriptor->debug_event_class_type);
+ printf("%s: 0x%x\n", STR_EVENT_IDENTIFIER,
+ pevent_descriptor->event_id);
+ printf("%s: %s\n", STR_EVENT_STRING, description_str);
+ printf("%s: 0x%x\n", STR_EVENT_DATA_SIZE,
+ pevent_descriptor->event_data_size);
+ }
+
+ if (pevent_descriptor->debug_event_class_type >= 0x80)
+ print_formatted_var_size_str(STR_VU_DATA,
+ pevent_specific_data, data_size, fp);
+ }
+
+ switch (pevent_descriptor->debug_event_class_type) {
+ case TIME_STAMP_CLASS_TYPE:
+ parse_time_stamp_event(pevent_descriptor, pevent_descriptor_obj,
+ pevent_specific_data, pevent_fifos_object, fp);
+ break;
+ case PCIE_CLASS_TYPE:
+ parse_pcie_event(pevent_descriptor, pevent_descriptor_obj,
+ pevent_specific_data, pevent_fifos_object, fp);
+ break;
+ case NVME_CLASS_TYPE:
+ parse_nvme_event(pevent_descriptor, pevent_descriptor_obj,
+ pevent_specific_data, pevent_fifos_object, fp);
+ break;
+ case RESET_CLASS_TYPE:
+ case BOOT_SEQUENCE_CLASS_TYPE:
+ case FIRMWARE_ASSERT_CLASS_TYPE:
+ case TEMPERATURE_CLASS_TYPE:
+ case MEDIA_CLASS_TYPE:
+ parse_common_event(pevent_descriptor, pevent_descriptor_obj,
+ pevent_specific_data, pevent_fifos_object, fp);
+ break;
+ case MEDIA_WEAR_CLASS_TYPE:
+ parse_media_wear_event(pevent_descriptor, pevent_descriptor_obj,
+ pevent_specific_data, pevent_fifos_object, fp);
+ break;
+ case STATISTIC_SNAPSHOT_CLASS_TYPE: {
+ struct nvme_ocp_statistic_snapshot_evt_class_format
+ *pStaticSnapshotEvent =
+ (struct nvme_ocp_statistic_snapshot_evt_class_format *)
+ pevent_specific_data;
+ struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry =
+ (struct nvme_ocp_telemetry_statistic_descriptor *)
+ (&pStaticSnapshotEvent->statisticDescriptorData);
+
+ parse_statistic(pstatistic_entry, pevent_descriptor_obj, fp);
+ break;
+ }
+ case RESERVED_CLASS_TYPE:
+ default:
+ break;
+ }
+
+ if (pevent_descriptor_obj != NULL && pevent_fifo_array != NULL)
+ json_array_add_value_object(pevent_fifo_array, pevent_descriptor_obj);
+ else {
+ if (fp)
+ fprintf(fp, STR_LINE2);
+ else
+ printf(STR_LINE2);
+ }
+ } else
+ break;
+
+ offset_to_move += (pevent_descriptor->event_data_size * SIZE_OF_DWORD + event_des_size);
+ }
+
+ if (pevent_fifos_object != NULL && pevent_fifo_array != NULL)
+ json_object_add_value_array(pevent_fifos_object, event_fifo_name,
+ pevent_fifo_array);
+
+ free(description);
+ return 0;
+}
+
+int parse_event_fifos(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets,
+ FILE *fp)
+{
+ if (poffsets == NULL) {
+ nvme_show_error("Input buffer was NULL");
+ return -1;
+ }
+
+ struct json_object *pevent_fifos_object = NULL;
+
+ if (root != NULL)
+ pevent_fifos_object = json_create_object();
+
+ __u8 *pda1_header_offset = ptelemetry_buffer + poffsets->da1_start_offset;//512
+ __u8 *pda2_offset = ptelemetry_buffer + poffsets->da2_start_offset;
+ struct nvme_ocp_header_in_da1 *pda1_header = (struct nvme_ocp_header_in_da1 *)
+ pda1_header_offset;
+ struct nvme_ocp_event_fifo_data event_fifo[MAX_NUM_FIFOS];
+
+ for (int fifo_num = 0; fifo_num < MAX_NUM_FIFOS; fifo_num++) {
+ event_fifo[fifo_num].event_fifo_num = fifo_num;
+ event_fifo[fifo_num].event_fifo_da = pda1_header->event_fifo_da[fifo_num];
+ event_fifo[fifo_num].event_fifo_start =
+ pda1_header->fifo_offsets[fifo_num].event_fifo_start;
+ event_fifo[fifo_num].event_fifo_size =
+ pda1_header->fifo_offsets[fifo_num].event_fifo_size;
+ }
+
+ //Parse all the FIFOs DA wise
+ for (int fifo_no = 0; fifo_no < MAX_NUM_FIFOS; fifo_no++) {
+ if (event_fifo[fifo_no].event_fifo_da == poffsets->data_area) {
+ __u64 fifo_offset =
+ (event_fifo[fifo_no].event_fifo_start * SIZE_OF_DWORD);
+ __u64 fifo_size =
+ (event_fifo[fifo_no].event_fifo_size * SIZE_OF_DWORD);
+ __u8 *pfifo_start = NULL;
+
+ if (event_fifo[fifo_no].event_fifo_da == 1)
+ pfifo_start = pda1_header_offset + fifo_offset;
+ else if (event_fifo[fifo_no].event_fifo_da == 2)
+ pfifo_start = pda2_offset + fifo_offset;
+ else {
+ nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area);
+ return -1;
+ }
+
+ int status = parse_event_fifo(fifo_no, pfifo_start, pevent_fifos_object,
+ pstring_buffer, poffsets, fifo_size, fp);
+
+ if (status != 0) {
+ nvme_show_error("Failed to parse Event FIFO. status:%d\n", status);
+ return -1;
+ }
+ }
+ }
+
+ if (pevent_fifos_object != NULL && root != NULL) {
+ const char *data_area = (poffsets->data_area == 1 ? STR_DA_1_EVENT_FIFO_INFO :
+ STR_DA_2_EVENT_FIFO_INFO);
+
+ json_object_add_value_array(root, data_area, pevent_fifos_object);
+ }
+
+ return 0;
+}
+
+int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry,
+ struct json_object *pstats_array, FILE *fp)
+{
+ if (pstatistic_entry == NULL) {
+ nvme_show_error("Input buffer was NULL");
+ return -1;
+ }
+
+ unsigned int data_size = pstatistic_entry->statistic_data_size * SIZE_OF_DWORD;
+ __u8 *pdata = (__u8 *)pstatistic_entry +
+ sizeof(struct nvme_ocp_telemetry_statistic_descriptor);
+ char description_str[256] = "";
+
+ parse_ocp_telemetry_string_log(0, pstatistic_entry->statistic_id, 0,
+ STATISTICS_IDENTIFIER_STRING, description_str);
+
+ if (pstats_array != NULL) {
+ struct json_object *pstatistics_object = json_create_object();
+
+ json_add_formatted_u32_str(pstatistics_object, STR_STATISTICS_IDENTIFIER,
+ pstatistic_entry->statistic_id);
+ json_object_add_value_string(pstatistics_object, STR_STATISTICS_IDENTIFIER_STR,
+ description_str);
+ json_add_formatted_u32_str(pstatistics_object,
+ STR_STATISTICS_INFO_BEHAVIOUR_TYPE,
+ pstatistic_entry->statistic_info_behaviour_type);
+ json_add_formatted_u32_str(pstatistics_object, STR_STATISTICS_INFO_RESERVED,
+ pstatistic_entry->statistic_info_reserved);
+ json_add_formatted_u32_str(pstatistics_object, STR_NAMESPACE_IDENTIFIER,
+ pstatistic_entry->ns_info_nsid);
+ json_add_formatted_u32_str(pstatistics_object, STR_NAMESPACE_INFO_VALID,
+ pstatistic_entry->ns_info_ns_info_valid);
+ json_add_formatted_u32_str(pstatistics_object, STR_STATISTICS_DATA_SIZE,
+ pstatistic_entry->statistic_data_size);
+ json_add_formatted_u32_str(pstatistics_object, STR_RESERVED,
+ pstatistic_entry->reserved);
+ json_add_formatted_var_size_str(pstatistics_object, STR_STATISTICS_SPECIFIC_DATA,
+ pdata, data_size);
+
+ if (pstatistics_object != NULL)
+ json_array_add_value_object(pstats_array, pstatistics_object);
+ } else {
+ if (fp) {
+ fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_IDENTIFIER,
+ pstatistic_entry->statistic_id);
+ fprintf(fp, "%s: %s\n", STR_STATISTICS_IDENTIFIER_STR, description_str);
+ fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_INFO_BEHAVIOUR_TYPE,
+ pstatistic_entry->statistic_info_behaviour_type);
+ fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_INFO_RESERVED,
+ pstatistic_entry->statistic_info_reserved);
+ fprintf(fp, "%s: 0x%x\n", STR_NAMESPACE_IDENTIFIER,
+ pstatistic_entry->ns_info_nsid);
+ fprintf(fp, "%s: 0x%x\n", STR_NAMESPACE_INFO_VALID,
+ pstatistic_entry->ns_info_ns_info_valid);
+ fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_DATA_SIZE,
+ pstatistic_entry->statistic_data_size);
+ fprintf(fp, "%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved);
+ print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata,
+ data_size, fp);
+ fprintf(fp, STR_LINE2);
+ } else {
+ printf("%s: 0x%x\n", STR_STATISTICS_IDENTIFIER,
+ pstatistic_entry->statistic_id);
+ printf("%s: %s\n", STR_STATISTICS_IDENTIFIER_STR, description_str);
+ printf("%s: 0x%x\n", STR_STATISTICS_INFO_BEHAVIOUR_TYPE,
+ pstatistic_entry->statistic_info_behaviour_type);
+ printf("%s: 0x%x\n", STR_STATISTICS_INFO_RESERVED,
+ pstatistic_entry->statistic_info_reserved);
+ printf("%s: 0x%x\n", STR_NAMESPACE_IDENTIFIER,
+ pstatistic_entry->ns_info_nsid);
+ printf("%s: 0x%x\n", STR_NAMESPACE_INFO_VALID,
+ pstatistic_entry->ns_info_ns_info_valid);
+ printf("%s: 0x%x\n", STR_STATISTICS_DATA_SIZE,
+ pstatistic_entry->statistic_data_size);
+ printf("%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved);
+ print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata,
+ data_size, fp);
+ printf(STR_LINE2);
+ }
+ }
+
+ return 0;
+}
+
+int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets,
+ FILE *fp)
+{
+ if (poffsets == NULL) {
+ nvme_show_error("Input buffer was NULL");
+ return -1;
+ }
+
+ __u8 *pda1_ocp_header_offset = ptelemetry_buffer + poffsets->header_size;//512
+ __u32 statistics_size = 0;
+ __u32 stats_da_1_start_dw = 0, stats_da_1_size_dw = 0;
+ __u32 stats_da_2_start_dw = 0, stats_da_2_size_dw = 0;
+ __u8 *pstats_offset = NULL;
+
+ if (poffsets->data_area == 1) {
+ __u32 stats_da_1_start = *(__u32 *)(pda1_ocp_header_offset +
+ offsetof(struct nvme_ocp_header_in_da1, da1_statistic_start));
+ __u32 stats_da_1_size = *(__u32 *)(pda1_ocp_header_offset +
+ offsetof(struct nvme_ocp_header_in_da1, da1_statistic_size));
+
+ //Data is present in the form of DWORDS, So multiplying with sizeof(DWORD)
+ stats_da_1_start_dw = (stats_da_1_start * SIZE_OF_DWORD);
+ stats_da_1_size_dw = (stats_da_1_size * SIZE_OF_DWORD);
+
+ pstats_offset = pda1_ocp_header_offset + stats_da_1_start_dw;
+ statistics_size = stats_da_1_size_dw;
+ } else if (poffsets->data_area == 2) {
+ __u32 stats_da_2_start = *(__u32 *)(pda1_ocp_header_offset +
+ offsetof(struct nvme_ocp_header_in_da1, da2_statistic_start));
+ __u32 stats_da_2_size = *(__u32 *)(pda1_ocp_header_offset +
+ offsetof(struct nvme_ocp_header_in_da1, da2_statistic_size));
+
+ stats_da_2_start_dw = (stats_da_2_start * SIZE_OF_DWORD);
+ stats_da_2_size_dw = (stats_da_2_size * SIZE_OF_DWORD);
+
+ pstats_offset = pda1_ocp_header_offset + poffsets->da1_size + stats_da_2_start_dw;
+ statistics_size = stats_da_2_size_dw;
+ } else {
+ nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area);
+ return -1;
+ }
+
+ struct json_object *pstats_array = ((root != NULL) ? json_create_array() : NULL);
+
+ __u32 stat_des_size = sizeof(struct nvme_ocp_telemetry_statistic_descriptor);//8
+ __u32 offset_to_move = 0;
+
+ while (((statistics_size > 0) && (offset_to_move < statistics_size))) {
+ struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry =
+ (struct nvme_ocp_telemetry_statistic_descriptor *)
+ (pstats_offset + offset_to_move);
+
+ parse_statistic(pstatistic_entry, pstats_array, fp);
+ offset_to_move += (pstatistic_entry->statistic_data_size * SIZE_OF_DWORD +
+ stat_des_size);
+ }
+
+ if (root != NULL && pstats_array != NULL) {
+ const char *pdata_area =
+ (poffsets->data_area == 1 ? STR_DA_1_STATS : STR_DA_2_STATS);
+
+ json_object_add_value_array(root, pdata_area, pstats_array);
+ }
+
+ return 0;
+}
+
+int print_ocp_telemetry_normal(struct ocp_telemetry_parse_options *options)
+{
+ int status = 0;
+
+ if (options->output_file != NULL) {
+ FILE *fp = fopen(options->output_file, "w");
+
+ if (fp) {
+ fprintf(fp, STR_LINE);
+ fprintf(fp, "%s\n", STR_LOG_PAGE_HEADER);
+ fprintf(fp, STR_LINE);
+ if (!strcmp(options->telemetry_type, "host"))
+ generic_structure_parser(ptelemetry_buffer, host_log_page_header,
+ ARRAY_SIZE(host_log_page_header), NULL, 0, fp);
+ else if (!strcmp(options->telemetry_type, "controller"))
+ generic_structure_parser(ptelemetry_buffer,
+ controller_log_page_header,
+ ARRAY_SIZE(controller_log_page_header), NULL, 0, fp);
+ fprintf(fp, STR_LINE);
+ fprintf(fp, "%s\n", STR_REASON_IDENTIFIER);
+ fprintf(fp, STR_LINE);
+ __u8 *preason_identifier_offset = ptelemetry_buffer +
+ offsetof(struct nvme_ocp_telemetry_host_initiated_header,
+ reason_id);
+
+ generic_structure_parser(preason_identifier_offset, reason_identifier,
+ ARRAY_SIZE(reason_identifier), NULL, 0, fp);
+
+ fprintf(fp, STR_LINE);
+ fprintf(fp, "%s\n", STR_TELEMETRY_HOST_DATA_BLOCK_1);
+ fprintf(fp, STR_LINE);
+
+ //Set DA to 1 and get offsets
+ struct nvme_ocp_telemetry_offsets offsets = { 0 };
+
+ offsets.data_area = 1;// Default DA - DA1
+
+ struct nvme_ocp_telemetry_common_header *ptelemetry_common_header =
+ (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer;
+
+ get_telemetry_das_offset_and_size(ptelemetry_common_header, &offsets);
+
+ __u8 *pda1_header_offset = ptelemetry_buffer +
+ offsets.da1_start_offset;//512
+
+ generic_structure_parser(pda1_header_offset, ocp_header_in_da1,
+ ARRAY_SIZE(ocp_header_in_da1), NULL, 0, fp);
+
+ fprintf(fp, STR_LINE);
+ fprintf(fp, "%s\n", STR_SMART_HEALTH_INFO);
+ fprintf(fp, STR_LINE);
+ __u8 *pda1_smart_offset = pda1_header_offset +
+ offsetof(struct nvme_ocp_header_in_da1, smart_health_info);
+ //512+512 =1024
+
+ generic_structure_parser(pda1_smart_offset, smart, ARRAY_SIZE(smart),
+ NULL, 0, fp);
+
+ fprintf(fp, STR_LINE);
+ fprintf(fp, "%s\n", STR_SMART_HEALTH_INTO_EXTENDED);
+ fprintf(fp, STR_LINE);
+ __u8 *pda1_smart_ext_offset = pda1_header_offset +
+ offsetof(struct nvme_ocp_header_in_da1,
+ smart_health_info_extended);
+
+ generic_structure_parser(pda1_smart_ext_offset, smart_extended,
+ ARRAY_SIZE(smart_extended), NULL, 0, fp);
+
+ fprintf(fp, STR_LINE);
+ fprintf(fp, "%s\n", STR_DA_1_STATS);
+ fprintf(fp, STR_LINE);
+
+ status = parse_statistics(NULL, &offsets, fp);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+
+ fprintf(fp, STR_LINE);
+ fprintf(fp, "%s\n", STR_DA_1_EVENT_FIFO_INFO);
+ fprintf(fp, STR_LINE);
+ status = parse_event_fifos(NULL, &offsets, fp);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+
+ //Set the DA to 2
+ if (options->data_area == 2) {
+ offsets.data_area = 2;
+ fprintf(fp, STR_LINE);
+ fprintf(fp, "%s\n", STR_DA_2_STATS);
+ fprintf(fp, STR_LINE);
+ status = parse_statistics(NULL, &offsets, fp);
+
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+
+ fprintf(fp, STR_LINE);
+ fprintf(fp, "%s\n", STR_DA_2_EVENT_FIFO_INFO);
+ fprintf(fp, STR_LINE);
+ status = parse_event_fifos(NULL, &offsets, fp);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+ }
+
+ fprintf(fp, STR_LINE);
+ fclose(fp);
+ } else {
+ nvme_show_error("Failed to open %s file.\n", options->output_file);
+ return -1;
+ }
+ } else {
+ printf(STR_LINE);
+ printf("%s\n", STR_LOG_PAGE_HEADER);
+ printf(STR_LINE);
+ if (!strcmp(options->telemetry_type, "host"))
+ generic_structure_parser(ptelemetry_buffer, host_log_page_header,
+ ARRAY_SIZE(host_log_page_header), NULL, 0, NULL);
+ else if (!strcmp(options->telemetry_type, "controller"))
+ generic_structure_parser(ptelemetry_buffer, controller_log_page_header,
+ ARRAY_SIZE(controller_log_page_header), NULL, 0, NULL);
+
+ printf(STR_LINE);
+ printf("%s\n", STR_REASON_IDENTIFIER);
+ printf(STR_LINE);
+ __u8 *preason_identifier_offset = ptelemetry_buffer +
+ offsetof(struct nvme_ocp_telemetry_host_initiated_header, reason_id);
+ generic_structure_parser(preason_identifier_offset, reason_identifier,
+ ARRAY_SIZE(reason_identifier), NULL, 0, NULL);
+
+ printf(STR_LINE);
+ printf("%s\n", STR_TELEMETRY_HOST_DATA_BLOCK_1);
+ printf(STR_LINE);
+
+ //Set DA to 1 and get offsets
+ struct nvme_ocp_telemetry_offsets offsets = { 0 };
+
+ offsets.data_area = 1;
+
+ struct nvme_ocp_telemetry_common_header *ptelemetry_common_header =
+ (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer;
+
+ get_telemetry_das_offset_and_size(ptelemetry_common_header, &offsets);
+
+ __u8 *pda1_header_offset = ptelemetry_buffer + offsets.da1_start_offset;//512
+
+ generic_structure_parser(pda1_header_offset, ocp_header_in_da1,
+ ARRAY_SIZE(ocp_header_in_da1), NULL, 0, NULL);
+
+ printf(STR_LINE);
+ printf("%s\n", STR_SMART_HEALTH_INFO);
+ printf(STR_LINE);
+ __u8 *pda1_smart_offset = pda1_header_offset +
+ offsetof(struct nvme_ocp_header_in_da1, smart_health_info);
+
+ generic_structure_parser(pda1_smart_offset, smart, ARRAY_SIZE(smart), NULL, 0,
+ NULL);
+
+ printf(STR_LINE);
+ printf("%s\n", STR_SMART_HEALTH_INTO_EXTENDED);
+ printf(STR_LINE);
+ __u8 *pda1_smart_ext_offset = pda1_header_offset +
+ offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended);
+
+ generic_structure_parser(pda1_smart_ext_offset, smart_extended,
+ ARRAY_SIZE(smart_extended), NULL, 0, NULL);
+
+ printf(STR_LINE);
+ printf("%s\n", STR_DA_1_STATS);
+ printf(STR_LINE);
+ status = parse_statistics(NULL, &offsets, NULL);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+
+ printf(STR_LINE);
+ printf("%s\n", STR_DA_1_EVENT_FIFO_INFO);
+ printf(STR_LINE);
+ status = parse_event_fifos(NULL, &offsets, NULL);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+
+ //Set the DA to 2
+ if (options->data_area == 2) {
+ offsets.data_area = 2;
+ printf(STR_LINE);
+ printf("%s\n", STR_DA_2_STATS);
+ printf(STR_LINE);
+ status = parse_statistics(NULL, &offsets, NULL);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+
+ printf(STR_LINE);
+ printf("%s\n", STR_DA_2_EVENT_FIFO_INFO);
+ printf(STR_LINE);
+ status = parse_event_fifos(NULL, &offsets, NULL);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+ }
+
+ printf(STR_LINE);
+ }
+
+ return status;
+}
+
+int print_ocp_telemetry_json(struct ocp_telemetry_parse_options *options)
+{
+ int status = 0;
+
+ //create json objects
+ struct json_object *root, *pheader, *preason_identifier, *da1_header, *smart_obj,
+ *ext_smart_obj;
+
+ root = json_create_object();
+
+ //Add data to root json object
+
+ //"Log Page Header"
+ pheader = json_create_object();
+
+ generic_structure_parser(ptelemetry_buffer, host_log_page_header,
+ ARRAY_SIZE(host_log_page_header), pheader, 0, NULL);
+ json_object_add_value_object(root, STR_LOG_PAGE_HEADER, pheader);
+
+ //"Reason Identifier"
+ preason_identifier = json_create_object();
+
+ __u8 *preason_identifier_offset = ptelemetry_buffer +
+ offsetof(struct nvme_ocp_telemetry_host_initiated_header, reason_id);
+
+ generic_structure_parser(preason_identifier_offset, reason_identifier,
+ ARRAY_SIZE(reason_identifier), preason_identifier, 0, NULL);
+ json_object_add_value_object(pheader, STR_REASON_IDENTIFIER, preason_identifier);
+
+ struct nvme_ocp_telemetry_offsets offsets = { 0 };
+
+ //Set DA to 1 and get offsets
+ offsets.data_area = 1;
+ struct nvme_ocp_telemetry_common_header *ptelemetry_common_header =
+ (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer;
+
+ get_telemetry_das_offset_and_size(ptelemetry_common_header, &offsets);
+
+ //"Telemetry Host-Initiated Data Block 1"
+ __u8 *pda1_header_offset = ptelemetry_buffer + offsets.da1_start_offset;//512
+
+ da1_header = json_create_object();
+
+ generic_structure_parser(pda1_header_offset, ocp_header_in_da1,
+ ARRAY_SIZE(ocp_header_in_da1), da1_header, 0, NULL);
+ json_object_add_value_object(root, STR_TELEMETRY_HOST_DATA_BLOCK_1, da1_header);
+
+ //"SMART / Health Information Log(LID-02h)"
+ __u8 *pda1_smart_offset = pda1_header_offset + offsetof(struct nvme_ocp_header_in_da1,
+ smart_health_info);
+ smart_obj = json_create_object();
+
+ generic_structure_parser(pda1_smart_offset, smart, ARRAY_SIZE(smart), smart_obj, 0, NULL);
+ json_object_add_value_object(da1_header, STR_SMART_HEALTH_INFO, smart_obj);
+
+ //"SMART / Health Information Extended(LID-C0h)"
+ __u8 *pda1_smart_ext_offset = pda1_header_offset + offsetof(struct nvme_ocp_header_in_da1,
+ smart_health_info_extended);
+ ext_smart_obj = json_create_object();
+
+ generic_structure_parser(pda1_smart_ext_offset, smart_extended, ARRAY_SIZE(smart_extended),
+ ext_smart_obj, 0, NULL);
+ json_object_add_value_object(da1_header, STR_SMART_HEALTH_INTO_EXTENDED, ext_smart_obj);
+
+ //Data Area 1 Statistics
+ status = parse_statistics(root, &offsets, NULL);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+
+ //Data Area 1 Event FIFOs
+ status = parse_event_fifos(root, &offsets, NULL);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status, NULL);
+ return -1;
+ }
+
+ if (options->data_area == 2) {
+ //Set the DA to 2
+ offsets.data_area = 2;
+ //Data Area 2 Statistics
+ status = parse_statistics(root, &offsets, NULL);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+
+ //Data Area 2 Event FIFOs
+ status = parse_event_fifos(root, &offsets, NULL);
+ if (status != 0) {
+ nvme_show_error("status: %d\n", status);
+ return -1;
+ }
+ }
+
+ if (options->output_file != NULL) {
+ const char *json_string = json_object_to_json_string(root);
+ FILE *fp = fopen(options->output_file, "w");
+
+ if (fp) {
+ fputs(json_string, fp);
+ fclose(fp);
+ } else {
+ nvme_show_error("Failed to open %s file.\n", options->output_file);
+ return -1;
+ }
+ } else {
+ //Print root json object
+ json_print_object(root, NULL);
+ nvme_show_result("\n");
+ json_free_object(root);
+ }
+
+ return status;
+}
diff --git a/plugins/ocp/ocp-telemetry-decode.h b/plugins/ocp/ocp-telemetry-decode.h
new file mode 100644
index 0000000..ed31a6c
--- /dev/null
+++ b/plugins/ocp/ocp-telemetry-decode.h
@@ -0,0 +1,1228 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (c) 2024 Western Digital Corporation or its affiliates.
+ *
+ * Authors: Jeff Lien <jeff.lien@wdc.com>,
+ */
+
+#include "nvme.h"
+#include "nvme-print.h"
+#include "util/utils.h"
+#include "common.h"
+
+extern __u8 *ptelemetry_buffer;
+extern __u8 *pstring_buffer;
+
+/*****************************************************************************
+ * Telemetry Statistics ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_STATISTIC_ID {
+ TELEMETRY_STAT_ID_OAC = 0x1, /* Outstanding Admin Commands */
+ TELEMETRY_STAT_ID_HWB = 0x2, /* Host Write Bandwidth */
+ TELEMETRY_STAT_ID_GCWB = 0x3, /* Garbage Collection Write Bandwidth */
+ TELEMETRY_STAT_ID_AN = 0x4, /* Active Namespaces */
+ TELEMETRY_STAT_ID_IWW = 0x5, /* Internal Write Workload */
+ TELEMETRY_STAT_ID_IRW = 0x6, /* Internal Read Workload */
+ TELEMETRY_STAT_ID_IWQD = 0x7, /* Internal Write Queue Depth */
+ TELEMETRY_STAT_ID_IRQD = 0x8, /* Internal Read Queue Depth */
+ TELEMETRY_STAT_ID_PTC = 0x9, /* Pending Trim LBA Count */
+ TELEMETRY_STAT_ID_HTRC = 0xA, /* Host Trim LBA Request Count */
+ TELEMETRY_STAT_ID_CNPS = 0xB, /* Current NVMe Power State */
+ TELEMETRY_STAT_ID_CDPS = 0xC, /* Current DSSD Power State */
+ TELEMETRY_STAT_ID_PFC = 0xD, /* Program Fail Count */
+ TELEMETRY_STAT_ID_EFC = 0xE, /* Erase Fail Count */
+ TELEMETRY_STAT_ID_RDW = 0xF, /* Read Disturb Write */
+ TELEMETRY_STAT_ID_RW = 0x10, /* Retention Writes */
+ TELEMETRY_STAT_ID_WLW = 0x11, /* Wear Leveling Writes */
+ TELEMETRY_STAT_ID_RRW = 0x12, /* Read Recovery Writes */
+ TELEMETRY_STAT_ID_GCW = 0x13, /* Garbage Collection Writes */
+ TELEMETRY_STAT_ID_SCC = 0x14, /* SRAM Correctable Count */
+ TELEMETRY_STAT_ID_DCC = 0x15, /* DRAM Uncorrectable Count */
+ TELEMETRY_STAT_ID_SUC = 0x16, /* SRAM Correctable Count */
+ TELEMETRY_STAT_ID_DUC = 0x17, /* DRAM Uncorrectable Count */
+ TELEMETRY_STAT_ID_DIEC = 0x18, /* Data Integrity Error Count */
+ TELEMETRY_STAT_ID_RREC = 0x19, /* Read Retry Error Count */
+ TELEMETRY_STAT_ID_PEC = 0x1A, /* PERST Events Count */
+ TELEMETRY_STAT_ID_MAXDBB = 0x1B, /* Max Die Bad Block */
+ TELEMETRY_STAT_ID_MAXCBB = 0x1C, /* Max NAND Channel Bad Block */
+ TELEMETRY_STAT_ID_MINCBB = 0x1D, /* Min NAND Channel Bad Block */
+};
+
+static const char * const telemetry_stat_id_str[] = {
+ [TELEMETRY_STAT_ID_OAC] = "Outstanding Admin Commands",
+ [TELEMETRY_STAT_ID_HWB] = "Host Write Bandwidth",
+ [TELEMETRY_STAT_ID_GCWB] = "Garbage Collection Write Bandwidth",
+ [TELEMETRY_STAT_ID_AN] = "Active Namespaces",
+ [TELEMETRY_STAT_ID_IWW] = "Internal Write Workload",
+ [TELEMETRY_STAT_ID_IRW] = "Internal Read Workload",
+ [TELEMETRY_STAT_ID_IWQD] = "Internal Write Queue Depth",
+ [TELEMETRY_STAT_ID_IRQD] = "Internal Read Queue Depth",
+ [TELEMETRY_STAT_ID_PTC] = "Pending Trim LBA Count",
+ [TELEMETRY_STAT_ID_HTRC] = "Host Trim LBA Request Count",
+ [TELEMETRY_STAT_ID_CNPS] = "Current NVMe Power State",
+ [TELEMETRY_STAT_ID_CDPS] = "Current DSSD Power State",
+ [TELEMETRY_STAT_ID_PFC] = "Program Fail Count",
+ [TELEMETRY_STAT_ID_EFC] = "Erase Fail Count",
+ [TELEMETRY_STAT_ID_RDW] = "Read Disturb Write",
+ [TELEMETRY_STAT_ID_RW] = "Retention Writes",
+ [TELEMETRY_STAT_ID_WLW] = "Wear Leveling Writes",
+ [TELEMETRY_STAT_ID_RRW] = "Read Recovery Writes",
+ [TELEMETRY_STAT_ID_GCW] = "Garbage Collection Writes",
+ [TELEMETRY_STAT_ID_SCC] = "SRAM Correctable Count",
+ [TELEMETRY_STAT_ID_DCC] = "DRAM Correctable Count",
+ [TELEMETRY_STAT_ID_SUC] = "SRAM Uncorrectable Count",
+ [TELEMETRY_STAT_ID_DUC] = "DRAM Uncorrectable Count",
+ [TELEMETRY_STAT_ID_DIEC] = "Data Integrity Error Count",
+ [TELEMETRY_STAT_ID_RREC] = "Read Retry Error Count",
+ [TELEMETRY_STAT_ID_PEC] = "PERST Events Count",
+ [TELEMETRY_STAT_ID_MAXDBB] = "Max Die Bad Block",
+ [TELEMETRY_STAT_ID_MAXCBB] = "Max NAND Channel Bad Block",
+ [TELEMETRY_STAT_ID_MINCBB] = "Min NAND Channel Bad Block",
+};
+
+/*****************************************************************************
+ * Telemetry FIFO Event Class ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_EVENT_CLASS_TYPE {
+ TELEMETRY_TIMESTAMP_CLASS = 0x1,
+ TELEMETRY_PCIE_CLASS = 0x2,
+ TELEMETRY_NVME_CLASS = 0x3,
+ TELEMETRY_RESET_CLASS = 0x4,
+ TELEMETRY_BOOT_SEQ_CLASS = 0x5,
+ TELEMETRY_FW_ASSERT_CLASS = 0x6,
+ TELEMETRY_TEMPERATURE_CLASS = 0x7,
+ TELEMETRY_MEDIA_DBG_CLASS = 0x8,
+ TELEMETRY_MEDIA_WEAR_CLASS = 0x9,
+ TELEMETRY_STAT_SNAPSHOT_CLASS = 0xA,
+};
+
+static const char * const telemetry_event_class_str[] = {
+ [TELEMETRY_TIMESTAMP_CLASS] = "Timestamp Class",
+ [TELEMETRY_PCIE_CLASS] = "PCIe Class",
+ [TELEMETRY_NVME_CLASS] = "NVMe Class",
+ [TELEMETRY_RESET_CLASS] = "Reset Class",
+ [TELEMETRY_BOOT_SEQ_CLASS] = "Boot Sequence Class",
+ [TELEMETRY_FW_ASSERT_CLASS] = "FW Assert Class",
+ [TELEMETRY_TEMPERATURE_CLASS] = "Temperature Class",
+ [TELEMETRY_MEDIA_DBG_CLASS] = "Media Debug Class",
+ [TELEMETRY_MEDIA_WEAR_CLASS] = "Media Wear Class",
+ [TELEMETRY_STAT_SNAPSHOT_CLASS] = "Statistic Snapshot Class",
+};
+
+/*****************************************************************************
+ * Telemetry Timestamp Class (01h) Event ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_TIMESTAMP_EVENT_ID {
+ TIMESTAMP_HOST_CMD_ISSUED = 0x0000,
+ TIMESTAMP_SNAPSHOT = 0x0001,
+ TIMESTAMP_POWER_ON_HOURS = 0x0002,
+};
+
+static const char * const telemetry_timestamp_event_id_str[] = {
+ [TIMESTAMP_HOST_CMD_ISSUED] = "Timestamp Host Cmd Issued",
+ [TIMESTAMP_SNAPSHOT] = "Timestamp Snapshot",
+ [TIMESTAMP_POWER_ON_HOURS] = "Timestamp Power on Hours",
+};
+
+/*****************************************************************************
+ * Telemetry PCIE Class (02h) Event ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_PCIE_EVENT_ID {
+ PCIE_LINK_UP = 0x0000,
+ PCIE_LINK_DOWN = 0x0001,
+ PCIE_ERROR_DETECTED = 0x0002,
+ PCIE_PERST_ASSERTED = 0x0003,
+ PCIE_PERST_DEASSERTED = 0x0004,
+ PCIE_REFCLK_STABLE = 0x0005,
+ PCIE_VMAIN_STABLE = 0x0006,
+ PCIE_LINK_NEGOTIATED = 0x0007,
+};
+
+static const char * const telemetry_pcie_event_id_str[] = {
+ [PCIE_LINK_UP] = "PCIe Link Up",
+ [PCIE_LINK_DOWN] = "PCIe Link Down",
+ [PCIE_ERROR_DETECTED] = "PCIe Error Detected",
+ [PCIE_PERST_ASSERTED] = "PCIe PERST Asserted",
+ [PCIE_PERST_DEASSERTED] = "PCIe PERST Deasserted",
+ [PCIE_REFCLK_STABLE] = "PCIe Refclk Stable",
+ [PCIE_VMAIN_STABLE] = "PCIe Vmain Stable",
+ [PCIE_LINK_NEGOTIATED] = "PCIe Link Negotiated",
+};
+
+enum TELEMETRY_PCIE_STATE_DATA {
+ PCIE_STATE_UNCHANGED = 0x00,
+ PCIE_SPEED_CHANGED = 0x01,
+ PCIE_WIDTH_CHANGED = 0x02,
+};
+
+static const char * const telemetry_pcie_state_data_str[] = {
+ [PCIE_STATE_UNCHANGED] = "PCIe State Unchained",
+ [PCIE_SPEED_CHANGED] = "PCIe Speed Changed",
+ [PCIE_WIDTH_CHANGED] = "PCIe Width Changed",
+};
+
+enum TELEMETRY_PCIE_SPEED_DATA {
+ PCIE_LINK_GEN1 = 0x01,
+ PCIE_LINK_GEN2 = 0x02,
+ PCIE_LINK_GEN3 = 0x03,
+ PCIE_LINK_GEN4 = 0x04,
+ PCIE_LINK_GEN5 = 0x05,
+ PCIE_LINK_GEN6 = 0x06,
+ PCIE_LINK_GEN7 = 0x07,
+};
+
+static const char * const telemetry_pcie_speed_data_str[] = {
+ [PCIE_LINK_GEN1] = "PCIe Link Speed Gen1",
+ [PCIE_LINK_GEN2] = "PCIe Link Speed Gen2",
+ [PCIE_LINK_GEN3] = "PCIe Link Speed Gen3",
+ [PCIE_LINK_GEN4] = "PCIe Link Speed Gen4",
+ [PCIE_LINK_GEN5] = "PCIe Link Speed Gen5",
+ [PCIE_LINK_GEN6] = "PCIe Link Speed Gen6",
+ [PCIE_LINK_GEN7] = "PCIe Link Speed Gen7",
+};
+
+enum TELEMETRY_PCIE_WIDTH_DATA {
+ PCIE_LINK_X1 = 0x01,
+ PCIE_LINK_X2 = 0x02,
+ PCIE_LINK_X4 = 0x03,
+ PCIE_LINK_X8 = 0x04,
+ PCIE_LINK_X16 = 0x05,
+};
+
+static const char * const telemetry_pcie_width_data_str[] = {
+ [PCIE_LINK_X1] = "PCIe Link Width x1",
+ [PCIE_LINK_X2] = "PCIe Link Width x2",
+ [PCIE_LINK_X4] = "PCIe Link Width x4",
+ [PCIE_LINK_X8] = "PCIe Link Width x8",
+ [PCIE_LINK_X16] = "PCIe Link Width x16",
+};
+
+/*****************************************************************************
+ * Telemetry NVMe Class (03h) Event ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_NVME_EVENT_ID {
+ CC_EN_0_TO_1 = 0x0000,
+ CC_EN_1_TO_0 = 0x0001,
+ CSTS_RDY_0_TO_1 = 0x0002,
+ CSTS_RDY_1_TO_0 = 0x0003,
+ NVME_EVENT_ID_RESERVED = 0x0004,
+ CREATE_IO_QUEUE_PROCESSED = 0x0005,
+ ADMIN_QUEUE_CMD_PROCESSED = 0x0006,
+ ADMIN_QUEUE_NONZERO_STATUS = 0x0007,
+ IO_QUEUE_NONZERO_STATUS = 0x0008,
+ CSTS_CFS_0_TO_1 = 0x0009,
+ ADMIN_QUEUE_BASE_WRITTEN = 0x000A,
+ CC_REGISTER_CHANGED = 0x000B,
+ CSTS_REGISTER_CHANGED = 0x000C,
+ DELETE_IO_QUEUE_PROCESSED = 0x000D,
+};
+
+static const char * const telemetry_nvme_event_id_str[] = {
+ [CC_EN_0_TO_1] = "CC.EN Transitions from 0 to 1",
+ [CC_EN_1_TO_0] = "CC.EN Transitions from 1 to 0",
+ [CSTS_RDY_0_TO_1] = "CSTS.RDY Transitions from 0 to 1",
+ [CSTS_RDY_1_TO_0] = "CSTS.RDY Transitions from 1 to 0",
+ [NVME_EVENT_ID_RESERVED] = "Reserved NVMe Event ID",
+ [CREATE_IO_QUEUE_PROCESSED] = "Create IO SQ or CQ Command Processed",
+ [ADMIN_QUEUE_CMD_PROCESSED] = "Other Admin Queue Command Processed",
+ [ADMIN_QUEUE_NONZERO_STATUS] = "Admin Command Returned Non-zero Status",
+ [IO_QUEUE_NONZERO_STATUS] = "IO Command Returned Non-zero Status",
+ [CSTS_CFS_0_TO_1] = "CSTS.CFS Transitions from 0 to 1",
+ [ADMIN_QUEUE_BASE_WRITTEN] = "Admin SQ or CQ Base Address Written",
+ [CC_REGISTER_CHANGED] = "CC Register Changed",
+ [CSTS_REGISTER_CHANGED] = "CTS Register Changed",
+ [DELETE_IO_QUEUE_PROCESSED] = "Delete IO SQ or CQ Command Processed",
+};
+
+/*****************************************************************************
+ * Telemetry Reset Class (04h) Event ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_RESET_EVENT_ID {
+ PCIE_CONVENTIONAL_HOT_RESET = 0x0000,
+ MAIN_POWER_CYCLE = 0x0001,
+ PERST = 0x0002,
+ PCIE_FUNCTION_LEVEL_RESET = 0x0003,
+ NVME_SUBSYSTEM_RESET = 0x0004,
+};
+
+static const char * const telemetry_reset_event_id_str[] = {
+ [PCIE_CONVENTIONAL_HOT_RESET] = "PCIE Conventional Hot Reset",
+ [MAIN_POWER_CYCLE] = "Main Power_Cycle",
+ [PERST] = "PERST",
+ [PCIE_FUNCTION_LEVEL_RESET] = "PCIE Function Level Reset",
+ [NVME_SUBSYSTEM_RESET] = "NVMe Subsytem Reset",
+};
+
+/*****************************************************************************
+ * Telemetry Boot Sequence Class (05h) Event ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_BOOT_SEQ_EVENT_ID {
+ MAIN_FW_BOOT_COMPLETE = 0x0000,
+ FTL_LOAD_FROM_NVM_COMPLETE = 0x0001,
+ FTL_REBUILD_STARTED = 0x0002,
+ FTL_REBUILD_COMPLETE = 0x0003,
+};
+
+static const char * const telemetry_boot_seq_event_id_str[] = {
+ [MAIN_FW_BOOT_COMPLETE] = "Main Firmware Boot Complete",
+ [FTL_LOAD_FROM_NVM_COMPLETE] = "FTL Load from NVM Complete",
+ [FTL_REBUILD_STARTED] = "FTL Rebuild Started",
+ [FTL_REBUILD_COMPLETE] = "FTL Rebuild Complete",
+};
+
+/*****************************************************************************
+ * Telemetry Firmware Assert Class (06h) Event ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_FW_ASSERT_EVENT_ID {
+ ASSERT_NVME_CODE = 0x0000,
+ ASSERT_MEDIA_CODE = 0x0001,
+ ASSERT_SECURITY_CODE = 0x0002,
+ ASSERT_BACKGROUND_CODE = 0x0003,
+ FTL_REBUILD_FAILED = 0x0004,
+ FTL_DATA_MISMATCH = 0x0005,
+ ASSERT_OTHER_CODE = 0x0006,
+};
+
+static const char * const telemetry_fw_assert_event_id_str[] = {
+ [ASSERT_NVME_CODE] = "Assert in NVMe Processing Code",
+ [ASSERT_MEDIA_CODE] = "Assert in Media Code",
+ [ASSERT_SECURITY_CODE] = "Assert in Security Code",
+ [ASSERT_BACKGROUND_CODE] = "Assert in Background Services Code",
+ [FTL_REBUILD_FAILED] = "FTL Rebuild Failed",
+ [FTL_DATA_MISMATCH] = "FTL Data Mismatch",
+ [ASSERT_OTHER_CODE] = "FTL Other Code",
+};
+
+/*****************************************************************************
+ * Telemetry Temperature Class (07h) Event ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_TEMPERATURE_EVENT_ID {
+ COMPOSITE_TEMP_DECREASE = 0x0000,
+ COMPOSITE_TEMP_INCREASE_WCTEMP = 0x0001,
+ COMPOSITE_TEMP_INCREASE_CCTEMP = 0x0002,
+};
+
+static const char * const telemetry_temperature_event_id_str[] = {
+ [COMPOSITE_TEMP_DECREASE] = "Composite Temp Decreases to (WCTEMP-2)",
+ [COMPOSITE_TEMP_INCREASE_WCTEMP] = "Composite Temp Increases to WCTEMP",
+ [COMPOSITE_TEMP_INCREASE_CCTEMP] = "Composite Temp Increases to CCTEMP",
+};
+
+/*****************************************************************************
+ * Telemetry Media Debug Class (08h) Event ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_MEDIA_DEBUG_EVENT_ID {
+ XOR_RECOVERY_INVOKED = 0x0000,
+ UNCORRECTABLE_MEDIA_ERROR = 0x0001,
+ BAD_BLOCK_PROGRAM_ERROR = 0x0002,
+ BAD_BLOCK_ERASE_ERROR = 0x0003,
+ BAD_BLOCK_READ_ERROR = 0x0004,
+ PLANE_FAILURE_EVENT = 0x0005,
+};
+
+static const char * const telemetry_media_debug_event_id_str[] = {
+ [XOR_RECOVERY_INVOKED] = "XOR Recovery Invoked",
+ [UNCORRECTABLE_MEDIA_ERROR] = "Uncorrectable Media Error",
+ [BAD_BLOCK_PROGRAM_ERROR] = "Block Marked Bad Due to Program Error",
+ [BAD_BLOCK_ERASE_ERROR] = "Block Marked Bad Due to Erase Error",
+ [BAD_BLOCK_READ_ERROR] = "Block Marked Bad Due to Read Error",
+ [PLANE_FAILURE_EVENT] = "Plane Failure Event",
+};
+
+/*****************************************************************************
+ * Telemetry Media Wear Class (09h) Event ID's and Strings
+ *****************************************************************************/
+enum TELEMETRY_MEDIA_WEAR_EVENT_ID {
+ MEDIA_WEAR = 0x0000,
+};
+
+static const char * const telemetry_media_wear_event_id_str[] = {
+ [MEDIA_WEAR] = "Media Wear",
+};
+
+
+/*****************************************************************************
+ * Telemetry Data Structures
+ *****************************************************************************/
+#define TELEMETRY_HEADER_SIZE 512
+#define TELEMETRY_DATA_SIZE 1536
+#define TELEMETRY_BYTE_PER_BLOCK 512
+#define TELEMETRY_TRANSFER_SIZE 1024
+#define FILE_NAME_SIZE 2048
+
+enum TELEMETRY_TYPE {
+ TELEMETRY_TYPE_NONE = 0,
+ TELEMETRY_TYPE_HOST = 7,
+ TELEMETRY_TYPE_CONTROLLER = 8,
+ TELEMETRY_TYPE_HOST_0 = 9,
+ TELEMETRY_TYPE_HOST_1 = 10,
+};
+
+struct telemetry_initiated_log {
+ __u8 LogIdentifier;
+ __u8 Reserved1[4];
+ __u8 IEEE[3];
+ __le16 DataArea1LastBlock;
+ __le16 DataArea2LastBlock;
+ __le16 DataArea3LastBlock;
+ __u8 Reserved2[2];
+ __le32 DataArea4LastBlock;
+ __u8 Reserved3[361];
+ __u8 DataHostGenerationNumber;
+ __u8 CtlrDataAvailable;
+ __u8 DataCtlrGenerationNumber;
+ __u8 ReasonIdentifier[128];
+};
+
+struct telemetry_stats_desc {
+ __le16 id;
+ __u8 info;
+ __u8 ns_info;
+ __le16 size;
+ __le16 rsvd1;
+ __u8 data[];
+};
+
+struct telemetry_event_desc {
+ __u8 class;
+ __le16 id;
+ __u8 size;
+ __u8 data[];
+};
+
+struct event_fifo {
+ __le64 start;
+ __le64 size;
+};
+
+struct telemetry_data_area_1 {
+ __le16 major_version;
+ __le16 minor_version;
+ __u8 reserved1[4];
+ __le64 timestamp;
+ __u8 log_page_guid[16];
+ __u8 no_of_tps_supp;
+ __u8 tps;
+ __u8 reserved2[6];
+ __le64 sls;
+ __u8 reserved3[8];
+ __u8 fw_revision[8];
+ __u8 reserved4[32];
+ __le64 da1_stat_start;
+ __le64 da1_stat_size;
+ __le64 da2_stat_start;
+ __le64 da2_stat_size;
+ __u8 reserved5[32];
+ __u8 event_fifo_da[16];
+ struct event_fifo event_fifos[16];
+ __u8 reserved6[80];
+ __u8 smart_health_info[512];
+ __u8 smart_health_info_extended[512];
+};
+
+#define DATA_SIZE_12 12
+#define DATA_SIZE_8 8
+#define DATA_SIZE_4 4
+#define MAX_BUFFER_32_KB 0x8000
+#define OCP_TELEMETRY_DATA_BLOCK_SIZE 512
+#define SIZE_OF_DWORD 4
+#define MAX_NUM_FIFOS 16
+#define DA1_OFFSET 512
+#define DEFAULT_ASCII_STRING_SIZE 16
+
+#define DEFAULT_TELEMETRY_BIN "telemetry.bin"
+#define DEFAULT_STRING_BIN "string.bin"
+#define DEFAULT_OUTPUT_FORMAT_JSON "json"
+
+/* C9 Telemetry String Log Format Log Page */
+#define C9_GUID_LENGTH 16
+#define C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE 0xC9
+#define C9_TELEMETRY_STR_LOG_LEN 432
+#define C9_TELEMETRY_STR_LOG_SIST_OFST 431
+
+#define STR_LOG_PAGE_HEADER "Log Page Header"
+#define STR_REASON_IDENTIFIER "Reason Identifier"
+#define STR_TELEMETRY_HOST_DATA_BLOCK_1 "Telemetry Host-Initiated Data Block 1"
+#define STR_SMART_HEALTH_INFO "SMART / Health Information Log(LID-02h)"
+#define STR_SMART_HEALTH_INTO_EXTENDED "SMART / Health Information Extended(LID-C0h)"
+#define STR_DA_1_STATS "Data Area 1 Statistics"
+#define STR_DA_2_STATS "Data Area 2 Statistics"
+#define STR_DA_1_EVENT_FIFO_INFO "Data Area 1 Event FIFO info"
+#define STR_DA_2_EVENT_FIFO_INFO "Data Area 2 Event FIFO info"
+#define STR_STATISTICS_IDENTIFIER "Statistics Identifier"
+#define STR_STATISTICS_IDENTIFIER_STR "Statistic Identifier String"
+#define STR_STATISTICS_INFO_BEHAVIOUR_TYPE "Statistics Info Behavior Type"
+#define STR_STATISTICS_INFO_RESERVED "Statistics Info Reserved"
+#define STR_NAMESPACE_IDENTIFIER "Namespace Identifier"
+#define STR_NAMESPACE_INFO_VALID "Namespace Information Valid"
+#define STR_STATISTICS_DATA_SIZE "Statistic Data Size"
+#define STR_RESERVED "Reserved"
+#define STR_STATISTICS_SPECIFIC_DATA "Statistic Specific Data"
+#define STR_CLASS_SPECIFIC_DATA "Class Specific Data"
+#define STR_DBG_EVENT_CLASS_TYPE "Debug Event Class type"
+#define STR_EVENT_IDENTIFIER "Event Identifier"
+#define STR_EVENT_STRING "Event String"
+#define STR_EVENT_DATA_SIZE "Event Data Size"
+#define STR_VU_EVENT_STRING "VU Event String"
+#define STR_VU_EVENT_ID_STRING "VU Event Identifier"
+#define STR_VU_DATA "VU Data"
+#define STR_LINE "==============================================================================\n"
+#define STR_LINE2 "-----------------------------------------------------------------------------\n"
+
+/**
+ * enum ocp_telemetry_data_area - Telemetry Data Areas
+ * @DATA_AREA_1: Data Area 1
+ * @DATA_AREA_2: Data Area 2
+ * @DATA_AREA_3: Data Area 3
+ * @DATA_AREA_4: Data Area 4
+ */
+enum ocp_telemetry_data_area {
+ DATA_AREA_1 = 0x01,
+ DATA_AREA_2 = 0x02,
+ DATA_AREA_3 = 0x03,
+ DATA_AREA_4 = 0x04,
+};
+
+/**
+ * enum ocp_telemetry_string_tables - OCP telemetry string tables
+ * @STATISTICS_IDENTIFIER_STRING: Statistic Identifier string
+ * @EVENT_STRING: Event String
+ * @VU_EVENT_STRING: VU Event String
+ */
+enum ocp_telemetry_string_tables {
+ STATISTICS_IDENTIFIER_STRING = 0,
+ EVENT_STRING,
+ VU_EVENT_STRING
+};
+
+/**
+ * enum ocp_telemetry_debug_event_class_types - OCP Debug Event Class types
+ * @RESERVED_CLASS_TYPE: Reserved class
+ * @TIME_STAMP_CLASS_TYPE: Time stamp class
+ * @PCIE_CLASS_TYPE: PCIe class
+ * @NVME_CLASS_TYPE: NVME class
+ * @RESET_CLASS_TYPE: Reset class
+ * @BOOT_SEQUENCE_CLASS_TYPE: Boot Sequence class
+ * @FIRMWARE_ASSERT_CLASS_TYPE: Firmware Assert class
+ * @TEMPERATURE_CLASS_TYPE: Temperature class
+ * @MEDIA_CLASS_TYPE: Media class
+ * @MEDIA_WEAR_CLASS_TYPE: Media wear class
+ * @STATISTIC_SNAPSHOT_CLASS_TYPE: Statistic snapshot class
+ * @RESERVED: Reserved class
+ * @VENDOR_UNIQUE_CLASS_TYPE: Vendor Unique class
+ */
+enum ocp_telemetry_debug_event_class_types {
+ RESERVED_CLASS_TYPE = 0x00,
+ TIME_STAMP_CLASS_TYPE = 0x01,
+ PCIE_CLASS_TYPE = 0x02,
+ NVME_CLASS_TYPE = 0x03,
+ RESET_CLASS_TYPE = 0x04,
+ BOOT_SEQUENCE_CLASS_TYPE = 0x05,
+ FIRMWARE_ASSERT_CLASS_TYPE = 0x06,
+ TEMPERATURE_CLASS_TYPE = 0x07,
+ MEDIA_CLASS_TYPE = 0x08,
+ MEDIA_WEAR_CLASS_TYPE = 0x09,
+ STATISTIC_SNAPSHOT_CLASS_TYPE = 0x0A,
+ //RESERVED = 7Fh-0Bh,
+ //VENDOR_UNIQUE_CLASS_TYPE = FFh-80h,
+};
+
+/**
+ * struct telemetry_str_log_format - Telemetry String Log Format
+ * @log_page_version: indicates the version of the mapping this log page uses
+ * Shall be set to 01h.
+ * @reserved1: Reserved.
+ * @log_page_guid: Shall be set to B13A83691A8F408B9EA495940057AA44h.
+ * @sls: Shall be set to the number of DWORDS in the String Log.
+ * @reserved2: reserved.
+ * @sits: shall be set to the number of DWORDS in the Statistics
+ * Identifier String Table
+ * @ests: Shall be set to the number of DWORDS from byte 0 of this
+ * log page to the start of the Event String Table
+ * @estsz: shall be set to the number of DWORDS in the Event String Table
+ * @vu_eve_sts: Shall be set to the number of DWORDS from byte 0 of this
+ * log page to the start of the VU Event String Table
+ * @vu_eve_st_sz: shall be set to the number of DWORDS in the VU Event String Table
+ * @ascts: the number of DWORDS from byte 0 of this log page until the
+ * ASCII Table Starts.
+ * @asctsz: the number of DWORDS in the ASCII Table
+ * @fifo1: FIFO 0 ASCII String
+ * @fifo2: FIFO 1 ASCII String
+ * @fifo3: FIFO 2 ASCII String
+ * @fifo4: FIFO 3 ASCII String
+ * @fif05: FIFO 4 ASCII String
+ * @fifo6: FIFO 5 ASCII String
+ * @fifo7: FIFO 6 ASCII String
+ * @fifo8: FIFO 7 ASCII String
+ * @fifo9: FIFO 8 ASCII String
+ * @fifo10: FIFO 9 ASCII String
+ * @fif011: FIFO 10 ASCII String
+ * @fif012: FIFO 11 ASCII String
+ * @fifo13: FIFO 12 ASCII String
+ * @fif014: FIFO 13 ASCII String
+ * @fif015: FIFO 14 ASCII String
+ * @fif016: FIFO 15 ASCII String
+ * @reserved3: reserved
+ */
+struct __packed telemetry_str_log_format {
+ __u8 log_page_version;
+ __u8 reserved1[15];
+ __u8 log_page_guid[C9_GUID_LENGTH];
+ __le64 sls;
+ __u8 reserved2[24];
+ __le64 sits;
+ __le64 sitsz;
+ __le64 ests;
+ __le64 estsz;
+ __le64 vu_eve_sts;
+ __le64 vu_eve_st_sz;
+ __le64 ascts;
+ __le64 asctsz;
+ __u8 fifo1[16];
+ __u8 fifo2[16];
+ __u8 fifo3[16];
+ __u8 fifo4[16];
+ __u8 fifo5[16];
+ __u8 fifo6[16];
+ __u8 fifo7[16];
+ __u8 fifo8[16];
+ __u8 fifo9[16];
+ __u8 fifo10[16];
+ __u8 fifo11[16];
+ __u8 fifo12[16];
+ __u8 fifo13[16];
+ __u8 fifo14[16];
+ __u8 fifo15[16];
+ __u8 fifo16[16];
+ __u8 reserved3[48];
+};
+
+/*
+ * struct statistics_id_str_table_entry - Statistics Identifier String Table Entry
+ * @vs_si: Shall be set the Vendor Unique Statistic Identifier number.
+ * @reserved1: Reserved
+ * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
+ * @ascii_id_ofst: Shall be set to the offset from DWORD 0/Byte 0 of the Start
+ * of the ASCII Table to the first character of the string for
+ * this Statistic Identifier string..
+ * @reserved2 reserved
+ */
+struct __packed statistics_id_str_table_entry {
+ __le16 vs_si;
+ __u8 reserved1;
+ __u8 ascii_id_len;
+ __le64 ascii_id_ofst;
+ __le32 reserved2;
+};
+
+/*
+ * struct event_id_str_table_entry - Event Identifier String Table Entry
+ * @deb_eve_class: Shall be set the Debug Class.
+ * @ei: Shall be set to the Event Identifier
+ * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
+ * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the
+ * ASCII table to the ASCII data for this identifier
+ * @reserved2 reserved
+ */
+struct __packed event_id_str_table_entry {
+ __u8 deb_eve_class;
+ __le16 ei;
+ __u8 ascii_id_len;
+ __le64 ascii_id_ofst;
+ __le32 reserved2;
+};
+
+/*
+ * struct vu_event_id_str_table_entry - VU Event Identifier String Table Entry
+ * @deb_eve_class: Shall be set the Debug Class.
+ * @vu_ei: Shall be set to the VU Event Identifier
+ * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
+ * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the
+ * ASCII table to the ASCII data for this identifier
+ * @reserved reserved
+ */
+struct __packed vu_event_id_str_table_entry {
+ __u8 deb_eve_class;
+ __le16 vu_ei;
+ __u8 ascii_id_len;
+ __le64 ascii_id_ofst;
+ __le32 reserved;
+};
+
+
+struct __packed ocp_telemetry_parse_options {
+ char *telemetry_log;
+ char *string_log;
+ char *output_file;
+ char *output_format;
+ int data_area;
+ char *telemetry_type;
+};
+
+struct __packed nvme_ocp_telemetry_reason_id
+{
+ __u8 error_id[64]; // Bytes 63:00
+ __u8 file_id[8]; // Bytes 71:64
+ __le16 line_number; // Bytes 73:72
+ __u8 valid_flags; // Bytes 74
+ __u8 reserved[21]; // Bytes 95:75
+ __u8 vu_reason_ext[32]; // Bytes 127:96
+};
+
+struct __packed nvme_ocp_telemetry_common_header
+{
+ __u8 log_id; // Byte 00
+ __le32 reserved1; // Bytes 04:01
+ __u8 ieee_oui_id[3]; // Bytes 07:05
+ __le16 da1_last_block; // Bytes 09:08
+ __le16 da2_last_block; // Bytes 11:10
+ __le16 da3_last_block; // Bytes 13:12
+ __le16 reserved2; // Bytes 15:14
+ __le32 da4_last_block; // Bytes 19:16
+};
+
+struct __packed nvme_ocp_telemetry_host_initiated_header
+{
+ struct nvme_ocp_telemetry_common_header commonHeader; // Bytes 19:00
+ __u8 reserved3[360]; // Bytes 379:20
+ __u8 host_initiated_scope; // Byte 380
+ __u8 host_initiated_gen_number; // Byte 381
+ __u8 host_initiated_data_available; // Byte 382
+ __u8 ctrl_initiated_gen_number; // Byte 383
+ struct nvme_ocp_telemetry_reason_id reason_id; // Bytes 511:384
+};
+
+struct __packed nvme_ocp_telemetry_controller_initiated_header
+{
+ struct nvme_ocp_telemetry_common_header commonHeader; // Bytes 19:00
+ __u8 reserved3[361]; // Bytes 380:20
+ __u8 ctrl_initiated_scope; // Byte 381
+ __u8 ctrl_initiated_data_available; // Byte 382
+ __u8 ctrl_initiated_gen_number; // Byte 383
+ struct nvme_ocp_telemetry_reason_id reason_id; // Bytes 511:384
+};
+
+struct __packed nvme_ocp_telemetry_smart
+{
+ __u8 critical_warning; // Byte 0
+ __le16 composite_temperature; // Bytes 2:1
+ __u8 available_spare; // Bytes 3
+ __u8 available_spare_threshold; // Bytes 4
+ __u8 percentage_used; // Bytes 5
+ __u8 reserved1[26]; // Bytes 31:6
+ __u8 data_units_read[16]; // Bytes 47:32
+ __u8 data_units_written[16]; // Bytes 63:48
+ __u8 host_read_commands[16]; // Byte 79:64
+ __u8 host_write_commands[16]; // Bytes 95:80
+ __u8 controller_busy_time[16]; // Bytes 111:96
+ __u8 power_cycles[16]; // Bytes 127:112
+ __u8 power_on_hours[16]; // Bytes 143:128
+ __u8 unsafe_shutdowns[16]; // Bytes 159:144
+ __u8 media_and_data_integrity_errors[16]; // Bytes 175:160
+ __u8 number_of_error_information_log_entries[16]; // Bytes 191:176
+ __le32 warning_composite_temperature_time; // Byte 195:192
+ __le32 critical_composite_temperature_time; // Bytes 199:196
+ __le16 temperature_sensor1; // Bytes 201:200
+ __le16 temperature_sensor2; // Byte 203:202
+ __le16 temperature_sensor3; // Byte 205:204
+ __le16 temperature_sensor4; // Bytes 207:206
+ __le16 temperature_sensor5; // Bytes 209:208
+ __le16 temperature_sensor6; // Bytes 211:210
+ __le16 temperature_sensor7; // Bytes 213:212
+ __le16 temperature_sensor8; // Bytes 215:214
+ __le32 thermal_management_temperature1_transition_count; // Bytes 219:216
+ __le32 thermal_management_temperature2_transition_count; // Bytes 223:220
+ __le32 total_time_for_thermal_management_temperature1; // Bytes 227:224
+ __le32 total_time_for_thermal_management_temperature2; // Bytes 231:228
+ __u8 reserved2[280]; // Bytes 511:232
+};
+
+struct __packed nvme_ocp_telemetry_smart_extended
+{
+ __u8 physical_media_units_written[16]; // Bytes 15:0
+ __u8 physical_media_units_read[16]; // Bytes 31:16
+ __u8 bad_user_nand_blocks_raw_count[6]; // Bytes 37:32
+ __le16 bad_user_nand_blocks_normalized_value; // Bytes 39:38
+ __u8 bad_system_nand_blocks_raw_count[6]; // Bytes 45:40
+ __le16 bad_system_nand_blocks_normalized_value; // Bytes 47:46
+ __le64 xor_recovery_count; // Bytes 55:48
+ __le64 uncorrectable_read_error_count; // Bytes 63:56
+ __le64 soft_ecc_error_count; // Bytes 71:64
+ __le32 end_to_end_correction_counts_detected_errors; // Bytes 75:72
+ __le32 end_to_end_correction_counts_corrected_errors; // Bytes 79:76
+ __u8 system_data_percent_used; // Byte 80
+ __u8 refresh_counts[7]; // Bytes 87:81
+ __le32 max_user_data_erase_count; // Bytes 91:88
+ __le32 min_user_data_erase_count; // Bytes 95:92
+ __u8 num_thermal_throttling_events; // Bytes 96
+ __u8 current_throttling_status; // Bytes 97
+ __u8 errata_version_field; // Byte 98
+ __le16 point_version_field; // Byte 100:99
+ __le16 minor_version_field; // Byte 102:101
+ __u8 major_version_field; // Byte 103
+ __le64 pcie_correctable_error_count; // Bytes 111:104
+ __le32 incomplete_shutdowns; // Bytes 115:112
+ __le32 reserved1; // Bytes 119:116
+ __u8 percent_free_blocks; // Byte 120
+ __u8 reserved2[7]; // Bytes 127:121
+ __le16 capacitor_health; // Bytes 129:128
+ __u8 nvme_base_errata_version; // Byte 130
+ __u8 nvme_command_set_errata_version; // Byte 131
+ __le32 reserved3; // Bytes 135:132
+ __le64 unaligned_io; // Bytes 143:136
+ __le64 security_version_number; // Bytes 151:144
+ __le64 total_nuse; // Bytes 159:152
+ __u8 plp_start_count[16]; // Bytes 175:160
+ __u8 endurance_estimate[16]; // Bytes 191:176
+ __le64 pcie_link_retraining_count; // Bytes 199:192
+ __le64 power_state_change_count; // Bytes 207:200
+ __le64 lowest_permitted_firmware_revision; // Bytes 215:208
+ __u8 reserved4[278]; // Bytes 493:216
+ __le16 log_page_version; // Bytes 495:494
+ __u8 log_page_guid[16]; // Bytes 511:496
+};
+
+struct __packed nvme_ocp_event_fifo_data
+{
+ __le32 event_fifo_num;
+ __u8 event_fifo_da;
+ __le64 event_fifo_start;
+ __le64 event_fifo_size;
+};
+
+struct __packed nvme_ocp_telemetry_offsets
+{
+ __le32 data_area;
+ __le32 header_size;
+ __le32 da1_start_offset;
+ __le32 da1_size;
+ __le32 da2_start_offset;
+ __le32 da2_size;
+ __le32 da3_start_offset;
+ __le32 da3_size;
+ __le32 da4_start_offset;
+ __le32 da4_size;
+};
+
+struct __packed nvme_ocp_event_fifo_offsets
+{
+ __le64 event_fifo_start;
+ __le64 event_fifo_size;
+};
+
+struct __packed nvme_ocp_header_in_da1
+{
+ __le16 major_version; // Bytes 1:0
+ __le16 minor_version; // Bytes 3:2
+ __le32 reserved1; // Bytes 7:4
+ __le64 time_stamp; // Bytes 15:8
+ __u8 log_page_guid[16]; // Bytes 31:16
+ __u8 num_telemetry_profiles_supported; // Byte 32
+ __u8 telemetry_profile_selected; // Byte 33
+ __u8 reserved2[6]; // Bytes 39:34
+ __le64 string_log_size; // Bytes 47:40
+ __le64 reserved3; // Bytes 55:48
+ __le64 firmware_revision; // Bytes 63:56
+ __u8 reserved4[32]; // Bytes 95:64
+ __le64 da1_statistic_start; // Bytes 103:96
+ __le64 da1_statistic_size; // Bytes 111:104
+ __le64 da2_statistic_start; // Bytes 119:112
+ __le64 da2_statistic_size; // Bytes 127:120
+ __u8 reserved5[32]; // Bytes 159:128
+ __u8 event_fifo_da[16]; // Bytes 175:160
+ struct nvme_ocp_event_fifo_offsets fifo_offsets[16]; // Bytes 431:176
+ __u8 reserved6[80]; // Bytes 511:432
+ struct nvme_ocp_telemetry_smart smart_health_info; // Bytes 1023:512
+ struct nvme_ocp_telemetry_smart_extended smart_health_info_extended; // Bytes 1535:1024
+};
+
+struct __packed nvme_ocp_telemetry_statistic_descriptor
+{
+ __le16 statistic_id; // Bytes 1:0
+ __u8 statistic_info_behaviour_type : 4; // Byte 2(3:0)
+ __u8 statistic_info_reserved : 4; // Byte 2(7:4)
+ __u8 ns_info_nsid : 7; // Bytes 3(6:0)
+ __u8 ns_info_ns_info_valid : 1; // Bytes 3(7)
+ __le16 statistic_data_size; // Bytes 5:4
+ __le16 reserved; // Bytes 7:6
+};
+
+struct __packed nvme_ocp_telemetry_event_descriptor
+{
+ __u8 debug_event_class_type; // Byte 0
+ __le16 event_id; // Bytes 2:1
+ __u8 event_data_size; // Byte 3
+};
+
+struct __packed nvme_ocp_time_stamp_dbg_evt_class_format
+{
+ __u8 time_stamp[DATA_SIZE_8]; // Bytes 11:4
+ __le16 vu_event_identifier; // Bytes 13:12
+};
+
+struct __packed nvme_ocp_pcie_dbg_evt_class_format
+{
+ __u8 pCIeDebugEventData[DATA_SIZE_4]; // Bytes 7:4
+ __le16 vu_event_identifier; // Bytes 9:8
+};
+
+struct __packed nvme_ocp_nvme_dbg_evt_class_format
+{
+ __u8 nvmeDebugEventData[DATA_SIZE_8]; // Bytes 11:4
+ __le16 vu_event_identifier; // Bytes 13:12
+};
+
+struct __packed nvme_ocp_common_dbg_evt_class_format
+{
+ __le16 vu_event_identifier; // Bytes 5:4
+};
+
+struct __packed nvme_ocp_media_wear_dbg_evt_class_format
+{
+ __u8 currentMediaWear[DATA_SIZE_12]; // Bytes 15:4
+ __le16 vu_event_identifier; // Bytes 17:16
+};
+
+struct __packed nvme_ocp_statistic_snapshot_evt_class_format
+{
+ struct nvme_ocp_telemetry_statistic_descriptor statisticDescriptorData; // Bytes 11:10
+};
+
+struct __packed nvme_ocp_statistics_identifier_string_table
+{
+ __le16 vs_statistic_identifier; //1:0
+ __u8 reserved1; //2
+ __u8 ascii_id_length; //3
+ __le64 ascii_id_offset; //11:4
+ __le32 reserved2; //15:12
+};
+
+struct __packed nvme_ocp_event_string_table
+{
+ __u8 debug_event_class; //0
+ __le16 event_identifier; //2:1
+ __u8 ascii_id_length; //3
+ __le64 ascii_id_offset; //11:4
+ __le32 reserved; //15:12
+};
+
+struct __packed nvme_ocp_vu_event_string_table
+{
+ __u8 debug_event_class; //0
+ __le16 vu_event_identifier; //2:1
+ __u8 ascii_id_length; //3
+ __le64 ascii_id_offset; //11:4
+ __le32 reserved; //15:12
+};
+
+struct __packed nvme_ocp_telemetry_string_header
+{
+ __u8 version; //0:0
+ __u8 reserved1[15]; //15:1
+ __u8 guid[16]; //32:16
+ __le64 string_log_size; //39:32
+ __u8 reserved2[24]; //63:40
+ __le64 sits; //71:64 Statistics Identifier String Table Start(SITS)
+ __le64 sitsz; //79:72 Statistics Identifier String Table Size (SITSZ)
+ __le64 ests; //87:80 Event String Table Start(ESTS)
+ __le64 estsz; //95:88 Event String Table Size(ESTSZ)
+ __le64 vu_ests; //103:96 VU Event String Table Start
+ __le64 vu_estsz; //111:104 VU Event String Table Size
+ __le64 ascts; //119:112 ASCII Table start
+ __le64 asctsz; //127:120 ASCII Table Size
+ __u8 fifo_ascii_string[16][16]; //383:128
+ __u8 reserved3[48]; //431:384
+};
+
+struct __packed statistic_entry {
+ int identifier;
+ char *description;
+};
+
+/************************************************************
+ * Telemetry Parsing Function Prototypes
+ ************************************************************/
+void print_vu_event_data(__u32 size, __u8 *data);
+void print_stats_desc(struct telemetry_stats_desc *stat_desc);
+void print_telemetry_fifo_event(__u8 class_type,
+ __u16 id, __u8 size, __u8 *data);
+
+
+/************************************************************
+ * Telemetry ID to String Conversion Functions
+ ************************************************************/
+static inline const char *arg_str(const char * const *strings,
+ size_t array_size, size_t idx)
+{
+ if (idx < array_size && strings[idx])
+ return strings[idx];
+ return "unrecognized";
+}
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#define ARGSTR(s, i) arg_str(s, ARRAY_SIZE(s), i)
+
+static inline const char *telemetry_stat_id_to_string(int stat_id)
+{
+ return ARGSTR(telemetry_stat_id_str, stat_id);
+}
+static inline const char *telemetry_event_class_to_string(int class)
+{
+ return ARGSTR(telemetry_event_class_str, class);
+}
+static inline const char *telemetry_ts_event_to_string(int event_id)
+{
+ return ARGSTR(telemetry_timestamp_event_id_str, event_id);
+}
+static inline const char *telemetry_pcie_event_id_to_string(int event_id)
+{
+ return ARGSTR(telemetry_pcie_event_id_str, event_id);
+}
+static inline const char *telemetry_pcie_state_data_to_string(int pcie_state)
+{
+ return ARGSTR(telemetry_pcie_state_data_str, pcie_state);
+}
+static inline const char *telemetry_pcie_speed_data_to_string(int pcie_speed)
+{
+ return ARGSTR(telemetry_pcie_speed_data_str, pcie_speed);
+}
+static inline const char *telemetry_pcie_width_data_to_string(int pcie_width)
+{
+ return ARGSTR(telemetry_pcie_width_data_str, pcie_width);
+}
+static inline const char *telemetry_nvme_event_id_to_string(int event_id)
+{
+ return ARGSTR(telemetry_nvme_event_id_str, event_id);
+}
+static inline const char *telemetry_reset_event_id_to_string(int event_id)
+{
+ return ARGSTR(telemetry_reset_event_id_str, event_id);
+}
+static inline const char *telemetry_boot_seq_event_id_to_string(int event_id)
+{
+ return ARGSTR(telemetry_boot_seq_event_id_str, event_id);
+}
+static inline const char *telemetry_fw_assert_event_id_to_string(int event_id)
+{
+ return ARGSTR(telemetry_fw_assert_event_id_str, event_id);
+}
+static inline const char *telemetry_temperature_event_id_to_string(int event_id)
+{
+ return ARGSTR(telemetry_temperature_event_id_str, event_id);
+}
+static inline const char *telemetry_media_debug_event_id_to_string(int event_id)
+{
+ return ARGSTR(telemetry_media_debug_event_id_str, event_id);
+}
+static inline const char *telemetry_media_wear_event_id_to_string(int event_id)
+{
+ return ARGSTR(telemetry_media_wear_event_id_str, event_id);
+}
+
+/**
+ * @brief parse the ocp telemetry host or controller log binary file
+ * into json or text
+ *
+ * @param options, input pointer for inputs like telemetry log bin file,
+ * string log bin file and output file etc.
+ *
+ * @return 0 success
+ */
+int parse_ocp_telemetry_log(struct ocp_telemetry_parse_options *options);
+
+/**
+ * @brief parse the ocp telemetry string log binary file to json or text
+ *
+ * @param event_fifo_num, input event FIFO number
+ * @param debug_event_class, input debug event class id
+ * @param string_table, input string table
+ * @param description, input description string
+ *
+ * @return 0 success
+ */
+int parse_ocp_telemetry_string_log(int event_fifo_num, int identifier, int debug_event_class,
+ enum ocp_telemetry_string_tables string_table, char *description);
+
+/**
+ * @brief gets the telemetry datas areas, offsets and sizes information
+ *
+ * @param ptelemetry_common_header, input telemetry common header pointer
+ * @param ptelemetry_das_offset, input telemetry offsets pointer
+ *
+ * @return 0 success
+ */
+int get_telemetry_das_offset_and_size(
+ struct nvme_ocp_telemetry_common_header *ptelemetry_common_header,
+ struct nvme_ocp_telemetry_offsets *ptelemetry_das_offset);
+
+/**
+ * @brief parses statistics data to text or json formats
+ *
+ * @param root, input time json root object pointer
+ * @param ptelemetry_das_offset, input telemetry offsets pointer
+ * @param fp, input file pointer
+ *
+ * @return 0 success
+ */
+int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets *pOffsets,
+ FILE *fp);
+
+/**
+ * @brief parses a single statistic data to text or json formats
+ *
+ * @param pstatistic_entry, statistic entry pointer
+ * @param pstats_array, stats array pointer
+ * @param fp, input file pointer
+ *
+ * @return 0 success
+ */
+int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry,
+ struct json_object *pstats_array, FILE *fp);
+
+/**
+ * @brief parses event fifos data to text or json formats
+ *
+ * @param root, input time json root object pointer
+ * @param poffsets, input telemetry offsets pointer
+ * @param fp, input file pointer
+ *
+ * @return 0 success
+ */
+int parse_event_fifos(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets,
+ FILE *fp);
+
+/**
+ * @brief parses a single event fifo data to text or json formats
+ *
+ * @param fifo_num, input event fifo number
+ * @param pfifo_start, event fifo start pointer
+ * @param pevent_fifos_object, event fifos json object pointer
+ * @param ptelemetry_das_offset, input telemetry offsets pointer
+ * @param fifo_size, input event fifo size
+ * @param fp, input file pointer
+ *
+ * @return 0 success
+ */
+int parse_event_fifo(unsigned int fifo_num, unsigned char *pfifo_start,
+ struct json_object *pevent_fifos_object, unsigned char *pstring_buffer,
+ struct nvme_ocp_telemetry_offsets *poffsets, __u64 fifo_size, FILE *fp);
+
+/**
+ * @brief parses event fifos data to text or json formats
+ *
+ * @return 0 success
+ */
+int print_ocp_telemetry_normal(struct ocp_telemetry_parse_options *options);
+
+/**
+ * @brief parses event fifos data to text or json formats
+ *
+ * @return 0 success
+ */
+int print_ocp_telemetry_json(struct ocp_telemetry_parse_options *options);
+
+/**
+ * @brief gets statistic id ascii string
+ *
+ * @param identifier, string id
+ * @param description, string description
+ *
+ * @return 0 success
+ */
+int get_static_id_ascii_string(int identifier, char *description);
+
+/**
+ * @brief gets event id ascii string
+ *
+ * @param identifier, string id
+ * @param debug_event_class, debug event class
+ * @param description, string description
+ *
+ * @return 0 success
+ */
+int get_event_id_ascii_string(int identifier, int debug_event_class, char *description);
+
+/**
+ * @brief gets vu event id ascii string
+ *
+ * @param identifier, string id
+ * @param debug_event_class, debug event class
+ * @param description, string description
+ *
+ * @return 0 success
+ */
+int get_vu_event_id_ascii_string(int identifier, int debug_event_class, char *description);
+
+/**
+ * @brief parses a time-stamp event fifo data to text or json formats
+ *
+ * @param pevent_descriptor, input event descriptor data
+ * @param pevent_descriptor_obj, event descriptor json object pointer
+ * @param pevent_specific_data, input event specific data
+ * @param pevent_fifos_object, event fifos json object pointer
+ * @param fp, input file pointer
+ *
+ * @return
+ */
+void parse_time_stamp_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp);
+
+/**
+ * @brief parses a pcie event fifo data to text or json formats
+ *
+ * @param pevent_descriptor, input event descriptor data
+ * @param pevent_descriptor_obj, event descriptor json object pointer
+ * @param pevent_specific_data, input event specific data
+ * @param pevent_fifos_object, event fifos json object pointer
+ * @param fp, input file pointer
+ *
+ * @return
+ */
+void parse_pcie_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp);
+
+/**
+ * @brief parses a nvme event fifo data to text or json formats
+ *
+ * @param pevent_descriptor, input event descriptor data
+ * @param pevent_descriptor_obj, event descriptor json object pointer
+ * @param pevent_specific_data, input event specific data
+ * @param pevent_fifos_object, event fifos json object pointer
+ * @param fp, input file pointer
+ *
+ * @return
+ */
+void parse_nvme_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp);
+
+/**
+ * @brief parses common event fifo data to text or json formats
+ *
+ * @param pevent_descriptor, input event descriptor data
+ * @param pevent_descriptor_obj, event descriptor json object pointer
+ * @param pevent_specific_data, input event specific data
+ * @param pevent_fifos_object, event fifos json object pointer
+ * @param fp, input file pointer
+ *
+ * @return
+ */
+void parse_common_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp);
+
+/**
+ * @brief parses a media-wear event fifo data to text or json formats
+ *
+ * @param pevent_descriptor, input event descriptor data
+ * @param pevent_descriptor_obj, event descriptor json object pointer
+ * @param pevent_specific_data, input event specific data
+ * @param pevent_fifos_object, event fifos json object pointer
+ * @param fp, input file pointer
+ *
+ * @return
+ */
+void parse_media_wear_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
+ struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
+ struct json_object *pevent_fifos_object, FILE *fp);
diff --git a/plugins/ocp/ocp-utils.c b/plugins/ocp/ocp-utils.c
index 1257b30..8a1462e 100644
--- a/plugins/ocp/ocp-utils.c
+++ b/plugins/ocp/ocp-utils.c
@@ -1,19 +1,32 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (c) 2022 Solidigm.
+ * Copyright (c) 2022-2024 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include <unistd.h>
+#include <errno.h>
#include "ocp-utils.h"
-#include "nvme-print.h"
const unsigned char ocp_uuid[NVME_UUID_LEN] = {
0xc1, 0x94, 0xd5, 0x5b, 0xe0, 0x94, 0x47, 0x94, 0xa2, 0x1d,
0x29, 0x99, 0x8f, 0x56, 0xbe, 0x6f };
-int ocp_get_uuid_index(struct nvme_dev *dev, int *index)
+int ocp_find_uuid_index(struct nvme_id_uuid_list *uuid_list, __u8 *index)
+{
+ int i = nvme_uuid_find(uuid_list, ocp_uuid);
+
+ *index = 0;
+ if (i > 0)
+ *index = i;
+ else
+ return -errno;
+
+ return 0;
+}
+
+int ocp_get_uuid_index(struct nvme_dev *dev, __u8 *index)
{
struct nvme_id_uuid_list uuid_list;
int err = nvme_identify_uuid(dev_fd(dev), &uuid_list);
@@ -22,11 +35,5 @@ int ocp_get_uuid_index(struct nvme_dev *dev, int *index)
if (err)
return err;
- for (int i = 0; i < NVME_ID_UUID_LIST_MAX; i++) {
- if (memcmp(ocp_uuid, &uuid_list.entry[i].uuid, NVME_UUID_LEN) == 0) {
- *index = i + 1;
- break;
- }
- }
- return err;
+ return ocp_find_uuid_index(&uuid_list, index);
}
diff --git a/plugins/ocp/ocp-utils.h b/plugins/ocp/ocp-utils.h
index d02bea9..1512db8 100644
--- a/plugins/ocp/ocp-utils.h
+++ b/plugins/ocp/ocp-utils.h
@@ -1,18 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * Copyright (c) 2022 Solidigm.
+ * Copyright (c) 2022-2024 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
#include "nvme.h"
+/*
+ * UUID assigned for OCP.
+ */
+extern const unsigned char ocp_uuid[NVME_UUID_LEN];
+
/**
* ocp_get_uuid_index() - Get OCP UUID index
* @dev: nvme device
* @index: integer pointer to here to save the index
- * @result: The command completion result from CQE dword0
*
- * Return: Zero if nvme device has UUID list log page, or result of get uuid list otherwise.
+ * Return: Zero if nvme device has UUID list identify page, or positive result of get uuid list
+ * or negative POSIX error code otherwise.
+ */
+int ocp_get_uuid_index(struct nvme_dev *dev, __u8 *index);
+
+/**
+ * ocp_find_uuid_index() - Find OCP UUID index in UUID list
+ * @uuid_list: uuid_list retrieved from Identify UUID List (CNS 0x17)
+ * @index: integer pointer to here to save the index
+ *
+ * Return: Zero if nvme device has UUID list log page, Negative POSIX error code otherwise.
*/
-int ocp_get_uuid_index(struct nvme_dev *dev, int *index);
+int ocp_find_uuid_index(struct nvme_id_uuid_list *uuid_list, __u8 *index);
diff --git a/plugins/sed/sedopal_cmd.c b/plugins/sed/sedopal_cmd.c
index 649e0b2..d9a789c 100644
--- a/plugins/sed/sedopal_cmd.c
+++ b/plugins/sed/sedopal_cmd.c
@@ -169,8 +169,10 @@ int sedopal_cmd_initialize(int fd)
struct opal_key key;
struct opal_lr_act lr_act = {};
struct opal_user_lr_setup lr_setup = {};
+ struct opal_new_pw new_pw = {};
sedopal_ask_key = true;
+ sedopal_ask_new_key = true;
rc = sedopal_set_key(&key);
if (rc != 0)
return rc;
@@ -217,6 +219,21 @@ int sedopal_cmd_initialize(int fd)
return rc;
}
+ /*
+ * set password
+ */
+ new_pw.new_user_pw.who = OPAL_ADMIN1;
+ new_pw.new_user_pw.opal_key.lr = 0;
+ new_pw.session.who = OPAL_ADMIN1;
+ new_pw.session.sum = 0;
+ new_pw.session.opal_key.lr = 0;
+ new_pw.session.opal_key = key;
+ new_pw.new_user_pw.opal_key = key;
+
+ rc = ioctl(fd, IOC_OPAL_SET_PW, &new_pw);
+ if (rc != 0)
+ fprintf(stderr, "Error: failed setting password - %d\n", rc);
+
return rc;
}
@@ -234,8 +251,21 @@ int sedopal_cmd_lock(int fd)
*/
int sedopal_cmd_unlock(int fd)
{
+ int rc;
+
+ rc = sedopal_lock_unlock(fd, OPAL_RW);
- return sedopal_lock_unlock(fd, OPAL_RW);
+ /*
+ * If the unlock was successful, force a re-read of the
+ * partition table. Return rc of unlock operation.
+ */
+ if (rc == 0) {
+ if (ioctl(fd, BLKRRPART, 0) != 0)
+ fprintf(stderr,
+ "Warning: failed re-reading partition\n");
+ }
+
+ return rc;
}
/*
@@ -258,18 +288,6 @@ int sedopal_lock_unlock(int fd, int lock_state)
if (rc != 0)
fprintf(stderr,
"Error: failed locking or unlocking - %d\n", rc);
-
- /*
- * If the unlock was successful, force a re-read of the
- * partition table.
- */
- if (rc == 0) {
- rc = ioctl(fd, BLKRRPART, 0);
- if (rc != 0)
- fprintf(stderr,
- "Error: failed re-reading partition\n");
- }
-
return rc;
}
@@ -380,6 +398,14 @@ int sedopal_cmd_revert(int fd)
revert_lsp.__pad = 0;
rc = ioctl(fd, IOC_OPAL_REVERT_LSP, &revert_lsp);
+ if (rc == 0) {
+ /*
+ * TPER must also be reverted.
+ */
+ rc = ioctl(fd, IOC_OPAL_REVERT_TPR, &revert_lsp.key);
+ if (rc != 0)
+ fprintf(stderr, "Error: revert TPR - %d\n", rc);
+ }
#else
rc = -EOPNOTSUPP;
#endif
@@ -448,14 +474,14 @@ void sedopal_print_locking_features(uint8_t features)
int sedopal_cmd_discover(int fd)
{
#ifdef IOC_OPAL_DISCOVERY
- int rc;
+ int rc, feat_length;
bool sedopal_locking_supported = false;
struct opal_discovery discover;
struct level_0_discovery_header *dh;
struct level_0_discovery_features *feat;
struct level_0_discovery_features *feat_end;
uint16_t code;
- uint8_t locking_flags;
+ uint8_t locking_flags = 0;
char buf[4096];
discover.data = (__u64)buf;
@@ -483,6 +509,7 @@ int sedopal_cmd_discover(int fd)
*/
while (feat < feat_end) {
code = be16toh(feat->code);
+ feat_length = feat->length + 4 /* hdr */;
switch (code) {
case OPAL_FEATURE_CODE_LOCKING:
locking_flags = feat->feature;
@@ -494,7 +521,7 @@ int sedopal_cmd_discover(int fd)
break;
}
- feat++;
+ feat = (struct level_0_discovery_features *)((char *)feat + feat_length);
}
rc = 0;
diff --git a/plugins/solidigm/meson.build b/plugins/solidigm/meson.build
index 052afa1..df2dc57 100644
--- a/plugins/solidigm/meson.build
+++ b/plugins/solidigm/meson.build
@@ -11,6 +11,7 @@ sources += [
'plugins/solidigm/solidigm-temp-stats.c',
'plugins/solidigm/solidigm-get-drive-info.c',
'plugins/solidigm/solidigm-ocp-version.c',
+ 'plugins/solidigm/solidigm-workload-tracker.c',
]
subdir('solidigm-telemetry')
diff --git a/plugins/solidigm/solidigm-garbage-collection.c b/plugins/solidigm/solidigm-garbage-collection.c
index a37e9c5..3c046b0 100644
--- a/plugins/solidigm/solidigm-garbage-collection.c
+++ b/plugins/solidigm/solidigm-garbage-collection.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (c) 2022 Solidigm.
+ * Copyright (c) 2022-2024 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
@@ -68,7 +68,7 @@ static void vu_gc_log_show(struct garbage_control_collection_log *payload, const
int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Get and parse Solidigm vendor specific garbage collection event log.";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_dev *dev;
int err;
__u8 uuid_index;
@@ -97,7 +97,7 @@ int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *c
return -EINVAL;
}
- uuid_index = solidigm_get_vu_uuid_index(dev);
+ sldgm_get_uuid_index(dev, &uuid_index);
struct garbage_control_collection_log gc_log;
const int solidigm_vu_gc_log_id = 0xfd;
diff --git a/plugins/solidigm/solidigm-get-drive-info.c b/plugins/solidigm/solidigm-get-drive-info.c
index 21f59bb..c783fa8 100644
--- a/plugins/solidigm/solidigm-get-drive-info.c
+++ b/plugins/solidigm/solidigm-get-drive-info.c
@@ -16,7 +16,7 @@ int sldgm_get_drive_info(int argc, char **argv, struct command *cmd, struct plug
const char *desc = "Get drive HW information";
const char *FTL_unit_size_str = "FTL_unit_size";
char *output_format = "normal";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
nvme_root_t r;
nvme_ctrl_t c;
nvme_ns_t n;
diff --git a/plugins/solidigm/solidigm-id-ctrl.c b/plugins/solidigm/solidigm-id-ctrl.c
index f45e758..67dc7b7 100644
--- a/plugins/solidigm/solidigm-id-ctrl.c
+++ b/plugins/solidigm/solidigm-id-ctrl.c
@@ -9,7 +9,7 @@
#include "common.h"
#include "solidigm-id-ctrl.h"
-struct __packed nvme_vu_id_ctrl_field { /* CDR MR5 */
+struct __packed nvme_vu_id_ctrl_field { // CPC
__u8 rsvd1[3];
__u8 ss;
char health[20];
@@ -22,6 +22,26 @@ struct __packed nvme_vu_id_ctrl_field { /* CDR MR5 */
__le64 ww;
char mic_bl[4];
char mic_fw[4];
+ __u8 rsvd3[678];
+ __u32 signature;
+ __u8 version;
+ __u8 product_type;
+ __u8 nand_type;
+ __u8 form_factor;
+ __u32 fw_status;
+ __u32 p4_revision; // git hash first 8 characters
+ __u32 customer_id;
+ __u32 usage_model;
+ struct{
+ __u32 zns_nvme : 1; // bit 0
+ __u32 mfnd_nvme : 1; // bit 1
+ __u32 cdw1413 : 1; // bit 2: CDW14 remapping into CDW13
+ __u32 vpd_avail : 1; // bit 3: VPD EEPROM is available
+ //at moment of id-ctrl response
+ __u32 rsvd : 28; // bit 4..31 are unused
+ }
+ command_set;
+
};
void sldgm_id_ctrl(uint8_t *vs, struct json_object *root)
@@ -37,6 +57,19 @@ void sldgm_id_ctrl(uint8_t *vs, struct json_object *root)
const char *str_ww = "wwid";
const char *str_mic_bl = "bwLimGran";
const char *str_mic_fw = "ioLimGran";
+ const char *str_signature = "signature";
+ const char *str_version = "version";
+ const char *str_product_type = "prodType";
+ const char *str_nand_type = "nandType";
+ const char *str_form_factor = "formFactor";
+ const char *str_fw_status = "fwStatus";
+ const char *str_p4_revision = "P4Revision";
+ const char *str_customer_id = "customerID";
+ const char *str_usage_model = "usageModel";
+ const char *str_zns_nvme = "znsNVMe";
+ const char *str_mfnd_nvme = "mfndNVMe";
+ const char *str_cdw14_cdw13 = "cdw14map13";
+ const char *str_vpd_avail = "vpdAvail";
struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
@@ -54,12 +87,25 @@ void sldgm_id_ctrl(uint8_t *vs, struct json_object *root)
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);
+ printf("%-10s: 0x%08X\n", str_signature, id->signature);
+ printf("%-10s: 0x%02X\n", str_version, id->version);
+ printf("%-10s: %u\n", str_product_type, id->product_type);
+ printf("%-10s: %u\n", str_nand_type, id->nand_type);
+ printf("%-10s: %u\n", str_form_factor, id->form_factor);
+ printf("%-10s: %u\n", str_fw_status, id->fw_status);
+ printf("%-10s: 0x%08X\n", str_p4_revision, id->p4_revision);
+ printf("%-10s: 0x%08X\n", str_customer_id, id->customer_id);
+ printf("%-10s: %u\n", str_usage_model, id->usage_model);
+ printf("%-10s: %u\n", str_zns_nvme, id->command_set.zns_nvme);
+ printf("%-10s: %u\n", str_mfnd_nvme, id->command_set.mfnd_nvme);
+ printf("%-10s: %u\n", str_cdw14_cdw13, id->command_set.cdw1413);
+ printf("%-10s: %u\n", str_vpd_avail, id->command_set.vpd_avail);
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_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);
@@ -67,7 +113,20 @@ void sldgm_id_ctrl(uint8_t *vs, struct json_object *root)
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_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)));
+ json_object_new_string_len(id->mic_fw, sizeof(id->mic_fw)));
+ json_object_add_value_uint(root, str_signature, id->signature);
+ json_object_add_value_uint(root, str_version, id->version);
+ json_object_add_value_uint(root, str_product_type, id->product_type);
+ json_object_add_value_uint(root, str_nand_type, id->nand_type);
+ json_object_add_value_uint(root, str_form_factor, id->form_factor);
+ json_object_add_value_uint(root, str_fw_status, id->fw_status);
+ json_object_add_value_uint(root, str_p4_revision, id->p4_revision);
+ json_object_add_value_uint(root, str_customer_id, id->customer_id);
+ json_object_add_value_uint(root, str_usage_model, id->usage_model);
+ json_object_add_value_uint(root, str_zns_nvme, id->command_set.zns_nvme);
+ json_object_add_value_uint(root, str_mfnd_nvme, id->command_set.mfnd_nvme);
+ json_object_add_value_uint(root, str_cdw14_cdw13, id->command_set.cdw1413);
+ json_object_add_value_uint(root, str_vpd_avail, id->command_set.vpd_avail);
}
diff --git a/plugins/solidigm/solidigm-internal-logs.c b/plugins/solidigm/solidigm-internal-logs.c
index c604761..f5b57f3 100644
--- a/plugins/solidigm/solidigm-internal-logs.c
+++ b/plugins/solidigm/solidigm-internal-logs.c
@@ -12,7 +12,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
-#include <linux/limits.h>
#include <time.h>
#include "common.h"
@@ -23,11 +22,15 @@
#include "solidigm-util.h"
#define DWORD_SIZE 4
+#define LOG_FILE_PERMISSION 0644
enum log_type {
NLOG = 0,
EVENTLOG = 1,
ASSERTLOG = 2,
+ HIT,
+ CIT,
+ ALL
};
#pragma pack(push, internal_logs, 1)
@@ -122,12 +125,20 @@ struct nlog_dump_header4_1 {
#pragma pack(pop, internal_logs)
struct config {
- __u32 namespace_id;
- char *dir_prefix;
+ char *out_dir;
char *type;
bool verbose;
};
+struct ilog {
+ struct nvme_dev *dev;
+ struct config *cfg;
+ int count;
+ struct nvme_id_ctrl id_ctrl;
+ enum nvme_telemetry_da max_da;
+ __u32 max_tx;
+};
+
static void print_nlog_header(__u8 *buffer)
{
struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *) buffer;
@@ -218,29 +229,29 @@ static int get_serial_number(char *str, int fd)
return err;
}
-static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
+static int ilog_dump_assert_logs(struct ilog *ilog)
{
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
__u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
- char file_path[PATH_MAX];
+ char file_path[PATH_MAX] = {0};
char file_name[] = "AssertLog.bin";
struct assert_dump_header *ad = (struct assert_dump_header *) head_buf;
struct nvme_passthru_cmd cmd = {
.opcode = 0xd2,
- .nsid = cfg.namespace_id,
+ .nsid = NVME_NSID_ALL,
.addr = (unsigned long)(void *)head_buf,
.cdw12 = ASSERTLOG,
.cdw13 = 0,
};
int output, err;
- err = read_header(&cmd, dev_fd(dev));
+ err = read_header(&cmd, dev_fd(ilog->dev));
if (err)
return err;
snprintf(file_path, sizeof(file_path), "%.*s/%s",
- (int) (sizeof(file_path) - sizeof(file_name) - 1), cfg.dir_prefix, file_name);
- output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ (int) (sizeof(file_path) - sizeof(file_name) - 1), ilog->cfg->out_dir, file_name);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, LOG_FILE_PERMISSION);
if (output < 0)
return -errno;
err = write_header((__u8 *)ad, output, ad->header.header_size * DWORD_SIZE);
@@ -251,7 +262,7 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
}
cmd.addr = (unsigned long)(void *)buf;
- if (cfg.verbose) {
+ if (ilog->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++)
@@ -262,28 +273,27 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
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);
+ err = cmd_dump_repeat(&cmd, ad->core[i].assertsize, output,
+ dev_fd(ilog->dev), false);
if (err) {
close(output);
return err;
}
}
close(output);
- printf("Successfully wrote log to %s\n", file_path);
+ printf("Successfully wrote Assert to %s\n", file_path);
return err;
}
-static int dump_event_logs(struct nvme_dev *dev, struct config cfg)
+static int ilog_dump_event_logs(struct ilog *ilog)
{
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
__u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
- char file_path[PATH_MAX];
+ char file_path[PATH_MAX] = {0};
struct event_dump_header *ehdr = (struct event_dump_header *) head_buf;
struct nvme_passthru_cmd cmd = {
.opcode = 0xd2,
- .nsid = cfg.namespace_id,
+ .nsid = NVME_NSID_ALL,
.addr = (unsigned long)(void *)head_buf,
.cdw12 = EVENTLOG,
.cdw13 = 0,
@@ -291,11 +301,11 @@ static int dump_event_logs(struct nvme_dev *dev, struct config cfg)
int output;
int core_num, err;
- err = read_header(&cmd, dev_fd(dev));
+ err = read_header(&cmd, dev_fd(ilog->dev));
if (err)
return err;
- snprintf(file_path, sizeof(file_path), "%s/EventLog.bin", cfg.dir_prefix);
- output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ snprintf(file_path, sizeof(file_path) - 1, "%s/EventLog.bin", ilog->cfg->out_dir);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, LOG_FILE_PERMISSION);
if (output < 0)
return -errno;
err = write_header(head_buf, output, INTERNAL_LOG_MAX_BYTE_TRANSFER);
@@ -308,11 +318,11 @@ static int dump_event_logs(struct nvme_dev *dev, struct config cfg)
}
cmd.addr = (unsigned long)(void *)buf;
- if (cfg.verbose)
+ if (ilog->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) {
+ if (ilog->cfg->verbose) {
for (int k = 0 ; k < 16; k++) {
printf("core: %d event: %d ", j, k);
printf("validity: %d ", ehdr->edumps[j].eventIdValidity[k]);
@@ -321,14 +331,14 @@ static int dump_event_logs(struct nvme_dev *dev, struct config cfg)
}
cmd.cdw13 = ehdr->edumps[j].coreoffset;
err = cmd_dump_repeat(&cmd, ehdr->edumps[j].coresize,
- output, dev_fd(dev), false);
+ output, dev_fd(ilog->dev), false);
if (err) {
close(output);
return err;
}
}
close(output);
- printf("Successfully wrote log to %s\n", file_path);
+ printf("Successfully wrote Events to %s\n", file_path);
return err;
}
@@ -348,16 +358,16 @@ static size_t get_nlog_header_size(struct nlog_dump_header_common *nlog_header)
}
/* dumps nlogs from specified core or all cores when core = -1 */
-static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
+static int ilog_dump_nlogs(struct ilog *ilog, int core)
{
int err = 0;
__u32 count, core_num;
__u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
- char file_path[PATH_MAX];
+ char file_path[PATH_MAX] = {0};
struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *)buf;
struct nvme_passthru_cmd cmd = {
.opcode = 0xd2,
- .nsid = cfg.namespace_id,
+ .nsid = NVME_NSID_ALL,
.addr = (unsigned long)(void *)buf
};
@@ -381,7 +391,7 @@ static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
do {
cmd.cdw13 = 0;
cmd.cdw12 = log_select.raw;
- err = read_header(&cmd, dev_fd(dev));
+ err = read_header(&cmd, dev_fd(ilog->dev));
if (err) {
if (is_open)
close(output);
@@ -390,9 +400,10 @@ static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
count = nlog_header->totalnlogs;
core_num = core < 0 ? nlog_header->corecount : 0;
if (!header_size) {
- snprintf(file_path, sizeof(file_path), "%s/NLog.bin",
- cfg.dir_prefix);
- output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ snprintf(file_path, sizeof(file_path) - 1, "%s/NLog.bin",
+ ilog->cfg->out_dir);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC,
+ LOG_FILE_PERMISSION);
if (output < 0)
return -errno;
header_size = get_nlog_header_size(nlog_header);
@@ -401,11 +412,11 @@ static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
err = write_header(buf, output, header_size);
if (err)
break;
- if (cfg.verbose)
+ if (ilog->cfg->verbose)
print_nlog_header(buf);
cmd.cdw13 = 0x400;
err = cmd_dump_repeat(&cmd, nlog_header->nlogbytesize / 4,
- output, dev_fd(dev), true);
+ output, dev_fd(ilog->dev), true);
if (err)
break;
} while (++log_select.selectNlog < count);
@@ -414,244 +425,552 @@ static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
} while (++log_select.selectCore < core_num);
if (is_open) {
close(output);
- printf("Successfully wrote log to %s\n", file_path);
+ printf("Successfully wrote Nlog to %s\n", file_path);
}
return err;
}
-enum telemetry_type {
- HOSTGENOLD,
- HOSTGENNEW,
- CONTROLLER
+int ensure_dir(const char *parent_dir_name, const char *name)
+{
+ char file_path[PATH_MAX] = {0};
+ struct stat sb;
+
+ snprintf(file_path, sizeof(file_path) - 1, "%s/%s", parent_dir_name, name);
+ if (!(stat(file_path, &sb) == 0 && S_ISDIR(sb.st_mode))) {
+ if (mkdir(file_path, 777) != 0) {
+ perror(file_path);
+ return -errno;
+ }
+ }
+ return 0;
+}
+
+struct log {
+ __u8 id;
+ const char *desc;
+ size_t buffer_size;
+ __u8 *buffer;
};
-static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetry_type ttype)
+static int log_save(struct log *log, const char *parent_dir_name, const char *subdir_name,
+ const char *file_name, __u8 *buffer, size_t buf_size)
{
- _cleanup_free_ struct nvme_telemetry_log *log = NULL;
- size_t log_size = 0;
- int err = 0;
- __u8 *buffer = NULL;
+ _cleanup_fd_ int output = -1;
+ char file_path[PATH_MAX] = {0};
size_t bytes_remaining = 0;
+ int err = 0;
+
+ ensure_dir(parent_dir_name, subdir_name);
+
+ snprintf(file_path, sizeof(file_path) - 1, "%s/%s/%s", parent_dir_name, subdir_name,
+ file_name);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, LOG_FILE_PERMISSION);
+ if (output < 0)
+ return -errno;
+
+ bytes_remaining = buf_size;
+
+ while (bytes_remaining) {
+ ssize_t bytes_written = write(output, buffer, bytes_remaining);
+
+ if (bytes_written < 0) {
+ err = -errno;
+ goto log_save_close_output;
+ }
+
+ bytes_remaining -= bytes_written;
+ buffer += bytes_written;
+ }
+ printf("Successfully wrote %s to %s\n", log->desc, file_path);
+
+log_save_close_output:
+ close(output);
+ return err;
+}
+
+static int ilog_dump_identify_page(struct ilog *ilog, struct log *cns, __u32 nsid)
+{
+ __u8 data[NVME_IDENTIFY_DATA_SIZE];
+ __u8 *buff = cns->buffer ? cns->buffer : data;
+ char filename[sizeof(
+ "cntid_XXXXX_cns_XXX_nsid_XXXXXXXXXX_nvmsetid_XXXXX_csi_XXX.bin")] = {0};
+ int err = nvme_identify_cns_nsid(dev_fd(ilog->dev), cns->id, nsid, buff);
+
+ if (err)
+ return err;
+
+ snprintf(filename, sizeof(filename) - 1, "cntid_0_cns_%d_nsid_%d_nvmsetid_0_csi_0.bin",
+ cns->id, nsid);
+ return log_save(cns, ilog->cfg->out_dir, "identify", filename, buff, sizeof(data));
+}
+
+static int ilog_ensure_dump_id_ctrl(struct ilog *ilog)
+{
+ static bool first = true;
+ static int err;
+ struct log idctrl = {NVME_IDENTIFY_CNS_CTRL, "Id Controller Data", sizeof(ilog->id_ctrl),
+ (__u8 *) &ilog->id_ctrl};
+
+ if (!first)
+ return err;
+
+ first = false;
+ err = ilog_dump_identify_page(ilog, &idctrl, 0);
+
+ if (err)
+ return err;
+
+ ilog->count++;
+
+ if (ilog->id_ctrl.lpa & 0x8)
+ ilog->max_da = NVME_TELEMETRY_DA_3;
+ if (ilog->id_ctrl.lpa & 0x40)
+ ilog->max_da = NVME_TELEMETRY_DA_4;
+
+ /* assuming CAP.MPSMIN is zero minimum Memory Page Size is at least 4096 bytes */
+ ilog->max_tx = (1 << ilog->id_ctrl.mdts) * NVME_LOG_PAGE_PDU_SIZE;
+ if (ilog->max_tx > DRIVER_MAX_TX_256K)
+ ilog->max_tx = DRIVER_MAX_TX_256K;
+
+ return err;
+}
+
+static int ilog_dump_telemetry(struct ilog *ilog, enum log_type ttype)
+{
+ int err = 0;
enum nvme_telemetry_da da;
size_t max_data_tx;
- char file_path[PATH_MAX];
- char *file_name;
- char *log_descr;
- struct stat sb;
+ const char *file_name;
+ struct nvme_feat_host_behavior prev = {0};
+ bool host_behavior_changed = false;
+ struct log log = {0};
+
+ err = ilog_ensure_dump_id_ctrl(ilog);
+ if (err)
+ return err;
- _cleanup_file_ int output = -1;
+ da = ilog->max_da;
+ max_data_tx = ilog->max_tx;
+
+ if (da == 4) {
+ __u32 result;
+ int err = nvme_get_features_host_behavior(dev_fd(ilog->dev), 0, &prev, &result);
+
+ if (!err && !prev.etdas) {
+ struct nvme_feat_host_behavior da4_enable = prev;
+
+ da4_enable.etdas = 1;
+ nvme_set_features_host_behavior(dev_fd(ilog->dev), 0, &da4_enable);
+ host_behavior_changed = true;
+ }
+ }
switch (ttype) {
- case HOSTGENNEW:
+ case HIT:
file_name = "lid_0x07_lsp_0x01_lsi_0x0000.bin";
- log_descr = "Generated Host Initiated";
- break;
- case HOSTGENOLD:
- file_name = "lid_0x07_lsp_0x00_lsi_0x0000.bin";
- log_descr = "Existing Host Initiated";
+ log.desc = "Host Initiated Telemetry";
+ err = nvme_get_telemetry_log(dev_fd(ilog->dev), true, false, false, max_data_tx, da,
+ (struct nvme_telemetry_log **) &log.buffer,
+ &log.buffer_size);
break;
- case CONTROLLER:
+ case CIT:
file_name = "lid_0x08_lsp_0x00_lsi_0x0000.bin";
- log_descr = "Controller Initiated";
+ log.desc = "Controller Initiated Telemetry";
+ err = nvme_get_telemetry_log(dev_fd(ilog->dev), false, true, true, max_data_tx, da,
+ (struct nvme_telemetry_log **) &log.buffer,
+ &log.buffer_size);
break;
default:
return -EINVAL;
}
- err = nvme_get_telemetry_max(dev_fd(dev), &da, &max_data_tx);
+
+ if (host_behavior_changed)
+ nvme_set_features_host_behavior(dev_fd(ilog->dev), 0, &prev);
+
if (err)
return err;
- if (max_data_tx > DRIVER_MAX_TX_256K)
- max_data_tx = DRIVER_MAX_TX_256K;
+ err = log_save(&log, ilog->cfg->out_dir, "log_pages", file_name, log.buffer,
+ log.buffer_size);
+ return err;
+}
- switch (ttype) {
- case HOSTGENNEW:
- err = nvme_get_telemetry_log(dev_fd(dev), true, false, false, max_data_tx, da,
- &log, &log_size);
- break;
- case HOSTGENOLD:
- err = nvme_get_telemetry_log(dev_fd(dev), false, false, false, max_data_tx, da,
- &log, &log_size);
- break;
- case CONTROLLER:
- err = nvme_get_telemetry_log(dev_fd(dev), false, true, true, max_data_tx, da, &log,
- &log_size);
- break;
+static int ilog_dump_identify_pages(struct ilog *ilog)
+{
+ struct nvme_ns_list ns_list;
+ __u32 j = 0;
+ struct log identify_base_list[] = {
+ {NVME_IDENTIFY_CNS_NS_ACTIVE_LIST, "Id Active Namespace ID list",
+ sizeof(ns_list), (__u8 *) &ns_list},
+ {NVME_IDENTIFY_CNS_NVMSET_LIST, "Id NVM Set List"},
+ {NVME_IDENTIFY_CNS_CSI_CTRL, "Id I/O Command Set specific"},
+ {NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST, "Id Allocated Namespace ID list"},
+ {NVME_IDENTIFY_CNS_CTRL_LIST, "Id Controller List"}
+ };
+ struct log identify_ns_required_list[] = {
+ {NVME_IDENTIFY_CNS_NS, "Id Namespace data"},
+ {NVME_IDENTIFY_CNS_NS_DESC_LIST, "Id Namespace Id Descriptor list"},
+ {NVME_IDENTIFY_CNS_CSI_NS, "Id Namespace ID I/O Command Set specific"},
+ {NVME_IDENTIFY_CNS_CSI_INDEPENDENT_ID_NS,
+ "I/O Command Set Independent Identify Namespace Data"},
+ {NVME_IDENTIFY_CNS_ALLOCATED_NS, "Id Namespace data "},
+ {NVME_IDENTIFY_CNS_NS_CTRL_LIST, "Id Namespace Id Controller List"},
+ };
+
+ ilog_ensure_dump_id_ctrl(ilog);
+
+ for (int i = 0; i < ARRAY_SIZE(identify_base_list); i++) {
+ int err = ilog_dump_identify_page(ilog, &identify_base_list[i], 0);
+
+ if (err == 0)
+ ilog->count++;
}
- if (err)
- return err;
+ while (ns_list.ns[j]) {
+ for (int i = 0; i < ARRAY_SIZE(identify_ns_required_list); i++) {
+ int err = ilog_dump_identify_page(ilog, &identify_ns_required_list[i],
+ ns_list.ns[j]);
- snprintf(file_path, sizeof(file_path), "%s/log_pages", cfg.dir_prefix);
- if (!(stat(file_path, &sb) == 0 && S_ISDIR(sb.st_mode))) {
- if (mkdir(file_path, 777) != 0) {
- perror(file_path);
- return -errno;
+ if (err == 0)
+ ilog->count++;
}
+ j++;
}
- snprintf(file_path, sizeof(file_path), "%s/log_pages/%s", cfg.dir_prefix, file_name);
- output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (output < 0)
- return -errno;
+ return 0;
+}
- bytes_remaining = log_size;
- buffer = (__u8 *)log;
+static int ilog_dump_log_page(struct ilog *ilog, struct log *lp, __u32 nsid)
+{
+ __u8 *buff = lp->buffer;
+ char filename[sizeof("lid_0xXX_lsp_0xXX_lsi_0xXXXX.bin")] = {0};
+ int err;
- while (bytes_remaining) {
- ssize_t bytes_written = write(output, buffer, bytes_remaining);
+ if (!lp->buffer_size)
+ return -EINVAL;
+ if (!buff) {
+ buff = nvme_alloc(lp->buffer_size);
+ if (!buff)
+ return -ENOMEM;
+ }
+ err = nvme_get_nsid_log(dev_fd(ilog->dev), 0, lp->id, 0, lp->buffer_size, buff);
+ if (err)
+ return err;
- if (bytes_written < 0) {
- err = -errno;
- goto tele_close_output;
- }
+ snprintf(filename, sizeof(filename), "lid_0x%02x_lsp_0x00_lsi_0x0000.bin",
+ lp->id);
+ return log_save(lp, ilog->cfg->out_dir, "log_pages", filename, buff, lp->buffer_size);
+}
- bytes_remaining -= bytes_written;
- buffer += bytes_written;
+static int ilog_dump_no_lsp_log_pages(struct ilog *ilog)
+{
+ struct lba_status_info {
+ __u32 lslplen;
+ __u32 nlslne;
+ __u32 estulb;
+ __u16 rsvd;
+ __u16 lsgc;
+ } lba_status = {};
+ __u64 num_entries = 0;
+ struct log log_page_dependent_list[] = {
+ {NVME_LOG_LID_LBA_STATUS},
+ {NVME_LOG_LID_ENDURANCE_GRP_EVT},
+ };
+ struct log log_page_base_list[] = {
+ {NVME_LOG_LID_SUPPORTED_LOG_PAGES, NULL, sizeof(struct nvme_supported_log_pages)},
+ {NVME_LOG_LID_ERROR, NULL,
+ (ilog->id_ctrl.elpe + 1) * sizeof(struct nvme_error_log_page)},
+ {NVME_LOG_LID_SMART, NULL, sizeof(struct nvme_smart_log)},
+ {NVME_LOG_LID_FW_SLOT, NULL, sizeof(struct nvme_firmware_slot)},
+ {NVME_LOG_LID_CHANGED_NS, NULL, sizeof(struct nvme_ns_list)},
+ {NVME_LOG_LID_CMD_EFFECTS, NULL, sizeof(struct nvme_cmd_effects_log)},
+ {NVME_LOG_LID_DEVICE_SELF_TEST, NULL, sizeof(struct nvme_self_test_log)},
+ {NVME_LOG_LID_LBA_STATUS, NULL, sizeof(lba_status), (__u8 *) &lba_status},
+ {NVME_LOG_LID_ENDURANCE_GRP_EVT, NULL, sizeof(num_entries), (__u8 *) &num_entries},
+ {NVME_LOG_LID_FID_SUPPORTED_EFFECTS, NULL,
+ sizeof(struct nvme_fid_supported_effects_log)},
+ {NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS, NULL,
+ sizeof(struct nvme_mi_cmd_supported_effects_log)},
+ {NVME_LOG_LID_CMD_AND_FEAT_LOCKDOWN, NULL, 512},
+ {NVME_LOG_LID_PHY_RX_EOM, NULL, 512},
+ {NVME_LOG_LID_SANITIZE, NULL, sizeof(struct nvme_sanitize_log_page)},
+ {0xC0, "OCP or VU SMART / Health Information Extended", 512},
+ {0xC1, "OCP Error Recovery or VU Latency Reads", 512},
+ {0xC2, "OCP Firmware Activation History or VU Latency Writes", 4096},
+ {0xC3, "OCP Latency Monitor", 512},
+ {0xC4, "OCP Device Capabilities or VU Endurance Manager Statistics", 4096},
+ {0xC5, "OCP Unsupported Requirements or VU Tempeture Statistics", 4096},
+ {0xC7, "OCP TCG Configuration", 512},
+ {0xCA, "SMART Attributes", 512},
+ {0xd5, "Tempeture Statistics", 512},
+ {0xfe, "Latency Outlier", 8192},
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(log_page_base_list); i++) {
+ log_page_base_list[i].desc = log_page_base_list[i].desc ?
+ log_page_base_list[i].desc :
+ nvme_log_to_string(log_page_base_list[i].id);
+ if (!ilog_dump_log_page(ilog, &log_page_base_list[i], 0))
+ ilog->count++;
}
- printf("Successfully wrote %s Telemetry log to %s\n", log_descr, file_path);
-tele_close_output:
- close(output);
+ /* if needed, patch logs based on retrieved log size */
+ if (lba_status.lslplen > sizeof(lba_status))
+ log_page_dependent_list[0].buffer_size = lba_status.lslplen;
+ if (num_entries)
+ log_page_dependent_list[1].buffer_size = sizeof(num_entries) +
+ (num_entries * sizeof(__u16));
+
+ for (int i = 0; i < ARRAY_SIZE(log_page_dependent_list); i++) {
+ log_page_dependent_list[i].desc = log_page_dependent_list[i].desc ?
+ log_page_dependent_list[i].desc :
+ nvme_log_to_string(log_page_dependent_list[i].id);
+ ilog_dump_log_page(ilog, &log_page_dependent_list[i], 0);
+ }
+
+ return 0;
+}
+
+static int ilog_dump_pel(struct ilog *ilog)
+{
+ struct log lp = {
+ NVME_LOG_LID_PERSISTENT_EVENT,
+ nvme_log_to_string(NVME_LOG_LID_PERSISTENT_EVENT)
+ };
+ void *pevent_log_full;
+ int err;
+ struct nvme_get_log_args args;
+
+ _cleanup_free_ struct nvme_persistent_event_log *pevent = NULL;
+
+ _cleanup_huge_ struct nvme_mem_huge mh = {0};
+
+ err = nvme_get_log_persistent_event(dev_fd(ilog->dev), NVME_PEVENT_LOG_RELEASE_CTX,
+ sizeof(*pevent), pevent);
+ if (err)
+ return err;
+
+
+ pevent = nvme_alloc(sizeof(*pevent));
+ if (!pevent)
+ return -ENOMEM;
+
+ err = nvme_get_log_persistent_event(dev_fd(ilog->dev), NVME_PEVENT_LOG_EST_CTX_AND_READ,
+ sizeof(*pevent), pevent);
+ if (err)
+ return err;
+
+ lp.buffer_size = le64_to_cpu(pevent->tll);
+
+ pevent_log_full = nvme_alloc_huge(lp.buffer_size, &mh);
+ if (!pevent_log_full)
+ return -ENOMEM;
+
+ err = nvme_get_log_persistent_event(dev_fd(ilog->dev), NVME_PEVENT_LOG_READ,
+ lp.buffer_size, pevent_log_full);
+ args = (struct nvme_get_log_args) {
+ .lpo = 0,
+ .result = NULL,
+ .log = pevent_log_full,
+ .args_size = sizeof(args),
+ .fd = dev_fd(ilog->dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = NVME_LOG_LID_PERSISTENT_EVENT,
+ .len = lp.buffer_size,
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_PEVENT_LOG_READ,
+ .uuidx = NVME_UUID_NONE,
+ .rae = false,
+ .ot = false,
+ };
+ err = nvme_get_log_page(dev_fd(ilog->dev), ilog->max_tx, &args);
+ if (err)
+ return err;
+
+ err = log_save(&lp, ilog->cfg->out_dir, "log_pages", "lid_0x0d_lsp_0x00_lsi_0x0000.bin",
+ pevent_log_full, lp.buffer_size);
+
+ nvme_get_log_persistent_event(dev_fd(ilog->dev), NVME_PEVENT_LOG_RELEASE_CTX,
+ sizeof(*pevent), pevent);
+
return err;
}
int solidigm_get_internal_log(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
- char folder[PATH_MAX];
- char zip_name[PATH_MAX];
- char *output_path;
char sn_prefix[sizeof(((struct nvme_id_ctrl *)0)->sn)+1];
- int log_count = 0;
+ char date_str[sizeof("-YYYYMMDDHHMMSS")];
+ char full_folder[PATH_MAX] = {0};
+ char unique_folder[sizeof(sn_prefix)+sizeof(date_str)-1] = {0};
+ char *initial_folder;
+ char zip_name[PATH_MAX] = {0};
+ char *output_path;
+ struct ilog ilog = {0};
int err;
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
- bool all = false;
- time_t t;
- struct tm tm;
+ enum log_type log_type = ALL;
+ char type_ALL[] = "ALL";
+ time_t current_time;
+ DIR *dir;
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 dir prefix; defaults to device serial number.";
+ const char *type = "Log type; Defaults to ALL.";
+ const char *out_dir = "Output directory; defaults to current working directory.";
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,
- .dir_prefix = NULL,
- .type = NULL,
+ .out_dir = ".",
+ .type = type_ALL,
};
OPT_ARGS(opts) = {
- OPT_STR("type", 't', &cfg.type, type),
- OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_FILE("dir-prefix", 'p', &cfg.dir_prefix, prefix),
- OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
+ OPT_STRING("type", 't', "ALL|CIT|HIT|NLOG|ASSERT|EVENT", &cfg.type, type),
+ OPT_STRING("dir-name", 'd', "DIRECTORY", &cfg.out_dir, out_dir),
+ OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
OPT_END()
};
err = parse_and_open(&dev, argc, argv, desc, opts);
if (err)
return err;
-
- if (!cfg.dir_prefix) {
- err = get_serial_number(sn_prefix, dev_fd(dev));
- if (err)
- return err;
- cfg.dir_prefix = sn_prefix;
+ ilog.dev = dev;
+ ilog.cfg = &cfg;
+
+ for (char *p = cfg.type; *p; ++p)
+ *p = toupper(*p);
+
+ if (!strcmp(cfg.type, "ALL"))
+ log_type = ALL;
+ else if (!strcmp(cfg.type, "HIT"))
+ log_type = HIT;
+ else if (!strcmp(cfg.type, "CIT"))
+ log_type = CIT;
+ else if (!strcmp(cfg.type, "NLOG"))
+ log_type = NLOG;
+ else if (!strcmp(cfg.type, "ASSERT"))
+ log_type = ASSERTLOG;
+ else if (!strcmp(cfg.type, "EVENT"))
+ log_type = EVENTLOG;
+ else {
+ fprintf(stderr, "Invalid log type: %s\n", cfg.type);
+ return -EINVAL;
}
- t = time(NULL);
- tm = *localtime(&t);
- snprintf(folder, sizeof(folder), "%s-%d%02d%02d%02d%02d%02d", cfg.dir_prefix,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
- if (mkdir(folder, 0777) != 0) {
- perror("mkdir");
+
+ dir = opendir(cfg.out_dir);
+ if (dir)
+ closedir(dir);
+ else {
+ perror(cfg.out_dir);
return -errno;
}
- cfg.dir_prefix = folder;
- output_path = folder;
- if (!cfg.type)
- cfg.type = "ALL";
- else {
- for (char *p = cfg.type; *p; ++p)
- *p = toupper(*p);
- }
+ initial_folder = cfg.out_dir;
- 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("Error retrieving Assert log");
+ err = get_serial_number(sn_prefix, dev_fd(dev));
+ if (err)
+ return err;
+
+ current_time = time(NULL);
+ strftime(date_str, sizeof(date_str), "-%Y%m%d%H%M%S", localtime(&current_time));
+ snprintf(unique_folder, sizeof(unique_folder), "%s%s", sn_prefix, date_str);
+ snprintf(full_folder, sizeof(full_folder) - 1, "%s/%s", cfg.out_dir, unique_folder);
+ if (mkdir(full_folder, 0755) != 0) {
+ perror("mkdir");
+ return -errno;
}
- if (all || !strcmp(cfg.type, "EVENT")) {
- err = dump_event_logs(dev, cfg);
+ cfg.out_dir = full_folder;
+ output_path = full_folder;
+
+ /* Retrieve first logs that records actions to retrieve other logs */
+ if (log_type == ALL || log_type == HIT) {
+ err = ilog_dump_telemetry(&ilog, HIT);
if (err == 0)
- log_count++;
+ ilog.count++;
else if (err < 0)
- perror("Error retrieving Event log");
+ perror("Error retrieving Host Initiated Telemetry");
}
- if (all || !strcmp(cfg.type, "NLOG")) {
- err = dump_nlogs(dev, cfg, -1);
+ if (log_type == ALL || log_type == NLOG) {
+ err = ilog_dump_nlogs(&ilog, -1);
if (err == 0)
- log_count++;
+ ilog.count++;
else if (err < 0)
perror("Error retrieving Nlog");
}
- if (all || !strcmp(cfg.type, "CONTROLLERINITTELEMETRY")) {
- err = dump_telemetry(dev, cfg, CONTROLLER);
+ if (log_type == ALL || log_type == CIT) {
+ err = ilog_dump_telemetry(&ilog, CIT);
if (err == 0)
- log_count++;
+ ilog.count++;
else if (err < 0)
- perror("Error retrieving Telemetry Controller Initiated");
+ perror("Error retrieving Controller Initiated Telemetry");
}
- if (all || !strcmp(cfg.type, "HOSTINITTELEMETRYNOGEN")) {
- err = dump_telemetry(dev, cfg, HOSTGENOLD);
+ if (log_type == ALL || log_type == ASSERTLOG) {
+ err = ilog_dump_assert_logs(&ilog);
if (err == 0)
- log_count++;
+ ilog.count++;
else if (err < 0)
- perror("Error retrieving previously existing Telemetry Host Initiated");
+ perror("Error retrieving Assert log");
}
- if (all || !strcmp(cfg.type, "HOSTINITTELEMETRY")) {
- err = dump_telemetry(dev, cfg, HOSTGENNEW);
+ if (log_type == ALL || log_type == EVENTLOG) {
+ err = ilog_dump_event_logs(&ilog);
if (err == 0)
- log_count++;
+ ilog.count++;
else if (err < 0)
- perror("Error retrieving Telemetry Host Initiated");
+ perror("Error retrieving Event log");
+ }
+ if (log_type == ALL) {
+ err = ilog_dump_identify_pages(&ilog);
+ if (err < 0)
+ perror("Error retrieving Identify pages");
+
+ err = ilog_dump_pel(&ilog);
+ if (err < 0)
+ perror("Error retrieving Persistent Event Log page");
+
+ err = ilog_dump_no_lsp_log_pages(&ilog);
+ if (err < 0)
+ perror("Error retrieving no LSP Log pages");
}
- if (log_count > 0) {
+ if (ilog.count > 0) {
int ret_cmd;
- char cmd[ARG_MAX];
- char *where_err = cfg.verbose ? "" : ">/dev/null 2>&1";
-
- snprintf(zip_name, sizeof(zip_name), "%s.zip", cfg.dir_prefix);
- snprintf(cmd, sizeof(cmd), "cd \"%s\" && zip -r \"../%s\" ./* %s", cfg.dir_prefix,
- zip_name, where_err);
+ char *cmd;
+ char *quiet = cfg.verbose ? "" : " -q";
+
+ snprintf(zip_name, sizeof(zip_name) - 1, "%s.zip", unique_folder);
+ if (asprintf(&cmd, "cd \"%s\" && zip -MM -r \"../%s\" ./* %s", cfg.out_dir,
+ zip_name, quiet) < 0) {
+ err = errno;
+ perror("Can't allocate string for zip command");
+ goto out;
+ }
printf("Compressing logs to %s\n", zip_name);
ret_cmd = system(cmd);
- if (ret_cmd == -1)
+ if (ret_cmd)
perror(cmd);
else {
output_path = zip_name;
- snprintf(cmd, sizeof(cmd), "rm -rf %s", cfg.dir_prefix);
- printf("Removing %s\n", cfg.dir_prefix);
+ free(cmd);
+ if (asprintf(&cmd, "rm -rf %s", cfg.out_dir) < 0) {
+ err = errno;
+ perror("Can't allocate string for cleanup");
+ goto out;
+ }
if (system(cmd) != 0)
perror("Failed removing logs folder");
}
+ free(cmd);
}
- if (log_count == 0) {
+out:
+ if (ilog.count == 0) {
if (err > 0)
nvme_show_status(err);
- } else if ((log_count > 1) || cfg.verbose)
- printf("Total: %d log files in %s\n", log_count, output_path);
+
+ } else if ((ilog.count > 1) || cfg.verbose)
+ printf("Total: %d log files in %s/%s\n", ilog.count, initial_folder, output_path);
return err;
}
diff --git a/plugins/solidigm/solidigm-latency-tracking.c b/plugins/solidigm/solidigm-latency-tracking.c
index 66f3c56..899075d 100644
--- a/plugins/solidigm/solidigm-latency-tracking.c
+++ b/plugins/solidigm/solidigm-latency-tracking.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (c) 2022 Solidigm.
+ * Copyright (c) 2022-2024 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
@@ -45,7 +45,7 @@ struct latency_tracker {
int fd;
__u8 uuid_index;
struct config cfg;
- enum nvme_print_flags print_flags;
+ nvme_print_flags_t print_flags;
struct latency_statistics stats;
struct json_object *bucket_list;
__u32 bucket_list_size;
@@ -430,7 +430,7 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd
return -EINVAL;
}
- lt.uuid_index = solidigm_get_vu_uuid_index(dev);
+ sldgm_get_uuid_index(dev, &lt.uuid_index);
err = latency_tracking_enable(&lt);
if (err) {
diff --git a/plugins/solidigm/solidigm-log-page-dir.c b/plugins/solidigm/solidigm-log-page-dir.c
index bf272f8..f8d1974 100644
--- a/plugins/solidigm/solidigm-log-page-dir.c
+++ b/plugins/solidigm/solidigm-log-page-dir.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (c) 2023 Solidigm.
+ * Copyright (c) 2023-2024 Solidigm.
*
* Author: karl.dedow@solidigm.com
*/
@@ -15,6 +15,7 @@
#include "nvme-print.h"
#include "plugins/ocp/ocp-utils.h"
+#include "solidigm-util.h"
#define MIN_VENDOR_LID 0xC0
#define SOLIDIGM_MAX_UUID 2
@@ -38,41 +39,9 @@ static void init_lid_dir(struct lid_dir *lid_dir)
}
}
-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,
@@ -81,7 +50,7 @@ static int get_supported_log_pages_log(struct nvme_dev *dev, int uuid_index,
.args_size = sizeof(args),
.fd = dev_fd(dev),
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .lid = LID,
+ .lid = NVME_LOG_LID_SUPPORTED_LOG_PAGES,
.len = sizeof(*supported),
.nsid = NVME_NSID_ALL,
.csi = NVME_CSI_NVM,
@@ -101,8 +70,8 @@ static struct lid_dir *get_standard_lids(struct nvme_supported_log_pages *suppor
init_lid_dir(&standard_dir);
- for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
- if (!supported->lid_support[lid] || lid >= MIN_VENDOR_LID)
+ for (int lid = 0; lid < MIN_VENDOR_LID; lid++) {
+ if (!supported->lid_support[lid])
continue;
standard_dir.lid[lid].supported = true;
@@ -128,12 +97,15 @@ static struct lid_dir *get_solidigm_lids(struct nvme_supported_log_pages *suppor
static struct lid_dir solidigm_dir = { 0 };
init_lid_dir(&solidigm_dir);
+ solidigm_dir.lid[0xC0].str = "OCP SMART / Health Information Extended";
solidigm_dir.lid[0xC1].str = "Read Commands Latency Statistics";
solidigm_dir.lid[0xC2].str = "Write Commands Latency Statistics";
+ solidigm_dir.lid[0xC3].str = "OCP Latency Monitor";
solidigm_dir.lid[0xC4].str = "Endurance Manager Statistics";
solidigm_dir.lid[0xC5].str = "Temperature Statistics";
solidigm_dir.lid[0xCA].str = "SMART Attributes";
solidigm_dir.lid[0xCB].str = "VU NVMe IO Queue Metrics Log Page";
+ solidigm_dir.lid[0xD5].str = solidigm_dir.lid[0xC5].str;
solidigm_dir.lid[0xDD].str = "VU Marketing Description Log Page";
solidigm_dir.lid[0xEF].str = "Performance Rating and LBA Access Histogram";
solidigm_dir.lid[0xF2].str = "Get Power Usage Log Page";
@@ -222,7 +194,7 @@ int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *c
OPT_END()
};
- struct nvme_dev *dev = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
int err = parse_and_open(&dev, argc, argv, description, options);
if (err)
@@ -247,16 +219,21 @@ int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *c
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);
+ __u8 sldgm_idx;
+ __u8 ocp_idx;
+
+ sldgm_find_uuid_index(&uuid_list, &sldgm_idx);
+ ocp_find_uuid_index(&uuid_list, &ocp_idx);
+
+ if (sldgm_idx && (sldgm_idx <= SOLIDIGM_MAX_UUID)) {
+ err = get_supported_log_pages_log(dev, sldgm_idx, &supported);
+ if (!err)
+ lid_dirs[sldgm_idx] = get_solidigm_lids(&supported);
+ }
+ if (ocp_idx && (ocp_idx <= SOLIDIGM_MAX_UUID)) {
+ err = get_supported_log_pages_log(dev, ocp_idx, &supported);
+ if (!err)
+ lid_dirs[ocp_idx] = get_ocp_lids(&supported);
}
}
} else {
@@ -264,7 +241,7 @@ int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *c
}
if (!err) {
- enum nvme_print_flags print_flag;
+ nvme_print_flags_t print_flag;
err = validate_output_format(format, &print_flag);
if (err < 0) {
@@ -279,8 +256,5 @@ int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *c
}
}
- /* Redundant close() to make static code analysis happy */
- close(dev->direct.fd);
- dev_close(dev);
return err;
}
diff --git a/plugins/solidigm/solidigm-market-log.c b/plugins/solidigm/solidigm-market-log.c
index d7d38da..e7e8728 100644
--- a/plugins/solidigm/solidigm-market-log.c
+++ b/plugins/solidigm/solidigm-market-log.c
@@ -12,7 +12,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
-#include <linux/limits.h>
#include "common.h"
#include "nvme.h"
diff --git a/plugins/solidigm/solidigm-nvme.c b/plugins/solidigm/solidigm-nvme.c
index 3fb86f5..8a7db07 100644
--- a/plugins/solidigm/solidigm-nvme.c
+++ b/plugins/solidigm/solidigm-nvme.c
@@ -21,6 +21,7 @@
#include "solidigm-temp-stats.h"
#include "solidigm-get-drive-info.h"
#include "solidigm-ocp-version.h"
+#include "solidigm-workload-tracker.h"
#include "plugins/ocp/ocp-clear-features.h"
#include "plugins/ocp/ocp-smart-extended-log.h"
@@ -107,3 +108,9 @@ static int get_cloud_SSDplugin_version(int argc, char **argv, struct command *cm
{
return sldgm_ocp_version(argc, argv, cmd, plugin);
}
+
+static int get_workload_tracker(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return sldgm_get_workload_tracker(argc, argv, cmd, plugin);
+}
diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h
index bee8266..2b74a02 100644
--- a/plugins/solidigm/solidigm-nvme.h
+++ b/plugins/solidigm/solidigm-nvme.h
@@ -13,7 +13,7 @@
#include "cmd.h"
-#define SOLIDIGM_PLUGIN_VERSION "1.1"
+#define SOLIDIGM_PLUGIN_VERSION "1.6"
PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
COMMAND_LIST(
@@ -32,6 +32,8 @@ PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_V
ENTRY("temp-stats", "Retrieve Temperature Statistics log", get_temp_stats_log)
ENTRY("vs-drive-info", "Retrieve drive information", get_drive_info)
ENTRY("cloud-SSDplugin-version", "Prints plug-in OCP version", get_cloud_SSDplugin_version)
+ ENTRY("workload-tracker", "Real Time capture Workload Tracker samples",
+ get_workload_tracker)
)
);
diff --git a/plugins/solidigm/solidigm-smart.c b/plugins/solidigm/solidigm-smart.c
index 62245fa..002753a 100644
--- a/plugins/solidigm/solidigm-smart.c
+++ b/plugins/solidigm/solidigm-smart.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (c) 2022 Solidigm.
+ * Copyright (c) 2022-2024 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
@@ -197,7 +197,7 @@ int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd
"Get Solidigm vendor specific smart log (optionally, for the specified namespace), and show it.";
const int solidigm_vu_smart_log_id = 0xCA;
struct vu_smart_log smart_log_payload;
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_dev *dev;
int err;
__u8 uuid_index;
@@ -229,7 +229,7 @@ int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd
return err;
}
- uuid_index = solidigm_get_vu_uuid_index(dev);
+ sldgm_get_uuid_index(dev, &uuid_index);
struct nvme_get_log_args args = {
.lpo = 0,
diff --git a/plugins/solidigm/solidigm-temp-stats.c b/plugins/solidigm/solidigm-temp-stats.c
index 85a3c37..7f385db 100644
--- a/plugins/solidigm/solidigm-temp-stats.c
+++ b/plugins/solidigm/solidigm-temp-stats.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (c) 2023 Solidigm.
+ * Copyright (c) 2023-2024 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
@@ -11,7 +11,8 @@
#include "nvme-print.h"
#include "solidigm-util.h"
-#define SLDGM_TEMP_STATS_LID 0xC5
+#define SLDGM_LEGACY_TEMP_STATS_LID 0xC5
+#define SLDGM_TEMP_STATS_LID 0xD5
struct temp_stats {
__le64 curr;
@@ -40,7 +41,7 @@ static void show_temp_stats(struct temp_stats *stats)
int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
unsigned char buffer[4096] = {0};
- struct nvme_dev *dev;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
__u8 uuid_idx;
int err;
@@ -63,7 +64,7 @@ int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct
if (err)
return err;
- uuid_idx = solidigm_get_vu_uuid_index(dev);
+ sldgm_get_uuid_index(dev, &uuid_idx);
struct nvme_get_log_args args = {
.lpo = 0,
@@ -84,25 +85,26 @@ int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct
};
err = nvme_get_log(&args);
- if (!err) {
- uint64_t *guid = (uint64_t *)&buffer[4080];
+ if (err > 0) {
+ args.lid = SLDGM_LEGACY_TEMP_STATS_LID;
+ err = nvme_get_log(&args);
+ if (!err) {
+ uint64_t *guid = (uint64_t *)&buffer[4080];
- if (guid[1] == 0xC7BB98B7D0324863 && guid[0] == 0xBB2C23990E9C722F) {
- fprintf(stderr, "Error: Log page has 'OCP unsupported Requirements' GUID\n");
- err = -EBADMSG;
- goto closefd;
+ if (guid[1] == 0xC7BB98B7D0324863 && guid[0] == 0xBB2C23990E9C722F) {
+ fprintf(stderr,
+ "Error: Log page has OCP unsupported Requirements GUID\n");
+ return -EBADMSG;
+ }
}
+ }
+ if (!err) {
if (!cfg.raw_binary)
show_temp_stats((struct temp_stats *) buffer);
else
d_raw(buffer, sizeof(struct temp_stats));
- } else if (err > 0) {
+ } else if (err > 0)
nvme_show_status(err);
- }
-closefd:
- /* Redundant close() to make static code analysis happy */
- close(dev->direct.fd);
- dev_close(dev);
return err;
}
diff --git a/plugins/solidigm/solidigm-util.c b/plugins/solidigm/solidigm-util.c
index 0171a49..05d1537 100644
--- a/plugins/solidigm/solidigm-util.c
+++ b/plugins/solidigm/solidigm-util.c
@@ -1,20 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (c) 2023 Solidigm.
+ * Copyright (c) 2023-2024 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
-#include "plugins/ocp/ocp-utils.h"
+#include <errno.h>
#include "solidigm-util.h"
-__u8 solidigm_get_vu_uuid_index(struct nvme_dev *dev)
+const unsigned char solidigm_uuid[NVME_UUID_LEN] = {
+ 0x96, 0x19, 0x58, 0x6e, 0xc1, 0x1b, 0x43, 0xad,
+ 0xaa, 0xaa, 0x65, 0x41, 0x87, 0xf6, 0xbb, 0xb2
+};
+
+int sldgm_find_uuid_index(struct nvme_id_uuid_list *uuid_list, __u8 *index)
{
- int ocp_uuid_index = 0;
+ int i = nvme_uuid_find(uuid_list, solidigm_uuid);
- if (ocp_get_uuid_index(dev, &ocp_uuid_index) == 0)
- if (ocp_uuid_index == 2)
- return 1;
+ *index = 0;
+ if (i > 0)
+ *index = i;
+ else
+ return -errno;
return 0;
}
+
+int sldgm_get_uuid_index(struct nvme_dev *dev, __u8 *index)
+{
+ struct nvme_id_uuid_list uuid_list;
+ int err = nvme_identify_uuid(dev_fd(dev), &uuid_list);
+
+ *index = 0;
+ if (err)
+ return err;
+
+ return sldgm_find_uuid_index(&uuid_list, index);
+}
diff --git a/plugins/solidigm/solidigm-util.h b/plugins/solidigm/solidigm-util.h
index fa5032f..ed7bf0f 100644
--- a/plugins/solidigm/solidigm-util.h
+++ b/plugins/solidigm/solidigm-util.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * Copyright (c) 2023 Solidigm.
+ * Copyright (c) 2023-2024 Solidigm.
*
* Author: leonardo.da.cunha@solidigm.com
*/
@@ -9,4 +9,5 @@
#define DRIVER_MAX_TX_256K (256 * 1024)
-__u8 solidigm_get_vu_uuid_index(struct nvme_dev *dev);
+int sldgm_find_uuid_index(struct nvme_id_uuid_list *uuid_list, __u8 *index);
+int sldgm_get_uuid_index(struct nvme_dev *dev, __u8 *index);
diff --git a/plugins/solidigm/solidigm-workload-tracker.c b/plugins/solidigm/solidigm-workload-tracker.c
new file mode 100644
index 0000000..73bb3c3
--- /dev/null
+++ b/plugins/solidigm/solidigm-workload-tracker.c
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2024 Solidigm.
+ *
+ * Authors: leonardo.da.cunha@solidigm.com
+ */
+
+#include "common.h"
+#include "nvme-print.h"
+#include <errno.h>
+#include <time.h>
+
+#define LID 0xf9
+#define FID 0xf1
+#define WLT2MS 25000
+#define MAX_WORKLOAD_LOG_ENTRIES 126
+#define MAX_WORKLOAD_LOG_ENTRY_SIZE 32
+#define MAX_FIELDS 15
+
+char const *samplet[] = {
+ "default",
+ "1ms",
+ "5ms",
+ "10ms",
+ "50ms",
+ "100ms",
+ "500ms",
+ "1s",
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "10m",
+ "30m",
+ "1h"
+};
+
+char const *trk_types[] = {
+ "Base",
+ "CmdQ",
+ "Pattern",
+ "RandSeq",
+ "Throttle",
+ "Power",
+ "Defrag"
+};
+
+struct field {
+ __u8 size;
+ char *name;
+ char *desc;
+};
+
+struct field group_fields[][MAX_FIELDS] = {
+{ // Base, group 0
+ {4, "hostReads", "Host Read Count in Sectors"},
+ {4, "hostWrites", "Host Write Count in Sectors"},
+ {4, "nandWrites", "Nand Write Count in Sectors"},
+ {1, "misalignment%", "% of Misaligned Sectors"},
+ {1, "collision%", "% of Colliding Sectors"},
+ {1, "randomWrite%", "% of Random Write Sectors vs. Sequential"},
+ {1, "randomRead%", "% of Random Read Sectors vs. Sequential"},
+ {4, "xorInvokedCount", "Count of XOR Operations Invoked"},
+ {4, "hostSoftReadSuccess", "Count of Soft Reads Completed Successfully."},
+ {4, "bandDefragRelocation", "Count of BDRs"},
+ {1, "pwrThrottle%", "% of Throttle Period due to Power Regulation"},
+ {1, "thmThrottle%", "% of Throttle Period due to Thermal Levels"},
+ {1, "tbufBg%", "% of Background TBUF Work vs. All Available Work"},
+ {1, "tbufHost%", "% of Host Requested TBUF Work vs. All Available Work"},
+ {0}
+},
+{ //CmdQ stats, group 1
+ {4, "CmdQ_InternalReadQDepth", "Snapshot of the Internal Read Queue Depth"},
+ {4, "CmdQ_DetectedWriteQDepth", "Snapshot of the Internal Write Queue Depth"},
+ {4, "CmdQ_ReadCmdsPending", "Snapshot of the Internal Read Commands Pending"},
+ {1, "misalignment%", "% of Misaligned Sectors"},
+ {1, "collision%", "% of Colliding Sectors"},
+ {1, "randomWrite%", "% of Random Write Sectors vs. Sequential"},
+ {1, "randomRead%", "% of Random Read Sectors vs. Sequential"},
+ {4, "CmdQ_WriteCmdsPending", "Snapshot of the Internal Write Commands Pending"},
+ {4, "CmdQ_ReadCmdsOutstanding", "Snapshot of the Internal Read Commands Outstanding"},
+ {4, "CmdQ_WriteCmdsOutstanding", "Snapshot of the Internal Read Commands Outstanding"},
+ {1, "pwrThrottle%", "% of Throttle Period due to Power Regulation"},
+ {1, "thmThrottle%", "% of Throttle Period due to Thermal Levels"},
+ {1, "tbufBg%", "% of Background TBUF Work vs. All Available Work"},
+ {1, "tbufHost%", "% of Host Requested TBUF Work vs. All Available Work"},
+ {0}
+},
+{ // test pattern, group 2
+ {4, "x11223300"},
+ {4, "x44556600_"},
+ {4, "x77889900_"},
+ {4, "xAABBCC00_"},
+ {2, "xDD00"},
+ {2, "xEE00"},
+ {2, "xFF00"},
+ {2, "x0_"},
+ {1, "x00"},
+ {1, "x80"},
+ {1, "x__"},
+ {1, "x8_"},
+ {4, "x33322100"},
+ {0}
+},
+{ // Random vs. Sequential Data, group 3
+ {4, "hostReads", "Host Read Count in Sectors"},
+ {4, "hostWrites", "Host Write Count in Sectors"},
+ {4, "nandWrites", "Nand Write Count in Sectors"},
+ {4, "randomReadCmd", "Count of Random Read Commands (vs. Sequential)"},
+ {4, "randomWriteCmd", "Count of Random Write Commands (vs. Sequential)"},
+ {4, "hostReadCmd", "Count of Total Host Read Commands (vs. Sequential)"},
+ {4, "hostWriteCmd", "Count of Total Host Read Commands (vs. Sequential)"},
+ {1, NULL},
+ {1, NULL},
+ {1, "randomWrite%", "% of Random Write Sectors vs. Sequential"},
+ {1, "randomThrottleRead%", "% of Random Read Sectors vs. Sequential"},
+ {0}
+},
+{ //Detailed Throttle Data, group 4
+ {4, "pwrThrottleOn_ms", "Duration of Power Throttling in mS."},
+ {4, "thmThrottleOn_ms", "Duration of Thermal Throttling in mS."},
+ {4, "powerOn_us", "Duration of Power-on in uS."},
+ {4, NULL},
+ {4, NULL},
+ {4, NULL},
+ {4, NULL},
+ {1, "pwrThrottle%", "% of Throttle Period due to Power Regulation"},
+ {1, "thmThrottle%", "% of Throttle Period due to Thermal Levels"},
+ {0}
+},
+{ // Detailed Power Data, group 5
+ // PMIC and/or Input Voltage Power
+ {4, "vin1Power", "in uW"},
+ {4, "vin2Power"},
+ // NAND Workload
+ {4, "nandWrites", "Nand Write Count in Sectors"},
+ {4, "nandReads", "Nand Read Count in Sectors"},
+ // Power Governor (if not enabled, all-0s)
+ {4, "lastNandAvgPwr"},
+ {4, "lastDriveAvgPwr"},
+ {4, "NscPwgSysCreditCnt"},
+ {4, "burstPowerBudget"},
+ {0}
+},
+{ // Defrag, group 6
+ {4, "hostReads", "Host Read Count in Sectors"},
+ {4, "hostWrites", "Host Write Count in Sectors"},
+ {4, "nandWrites", "Nand Write Count in Sectors"},
+ {4, "defragSlots", "Current defragSlots"},
+ {4, "hostSlots", "hostSlots"},
+ {4, "totalSlots", "Total slots"},
+ {1, "hostBufferUse%", "% of WCM_GetHostBuffersInUse to WCM_GetDesiredHostBuffer"},
+ {1, "defragBufferUse%", "% of defragBuffer to Desired defrag buffer %"},
+ {1, "defragSlotsUse%", "defragSlots to Total defrag slots %"},
+ {1, "hostSlotsUse%", "hostSlots to Total defrag slots %"},
+ {1, "aiuUse%", "% of AvailableIndirectionUnits to Start Setpoint IU"},
+ {1, "isImminentFRorWL", "defrag/Wear leveling is imminent"},
+ {1, "defragType", "defrag type"},
+ {0}
+}};
+
+#pragma pack(push, 1)
+union WorkloadLogEnable {
+ struct {
+ __u32 trackerEnable : 1;
+ __u32 triggerEnable : 1;
+ __u32 triggerSynchronous : 1; // trigger mode, 1=Synchronous,0=ASynchronous(Latency)
+ __u32 triggerDelta : 1; // trigger value mode, 1=delta, 0=current value
+ __u32 triggerDwordIndex : 3; // trigger dword index, 0~7 of a log entry
+ __u32 triggerByteWordIndex : 2; // trigger byte or word index,byte=0~3, word=0~1
+ __u32 triggerSize : 2; // trigger size, 1=byte, 2=word, 3=dword as a trigger
+ __u32 sampleTime : 4; // trigger sample time
+ __u32 contentGroup : 4; // content group select
+ __u32 stopCount : 12;// event limit,if<>0,stop tracker after stopCount events
+ __u32 eventDumpEnable : 1; // trigger event dump enable
+ } field;
+ __u32 dword;
+};
+
+struct workloadLogHeader {
+ __u16 majorVersion; // Major Version
+ __u16 minorVersion; // Minor Version
+ __u32 workloadLogCount; // Number of Entries in the Workload Log
+ __u32 reserved; // reserve for future
+ __u32 triggeredEvents; // Count of events triggered
+ __u32 samplePeriodInMilliseconds; // Sample Period In Milliseconds
+ __u64 timestamp_lastEntry; // Timestamp for the last full entry
+ __u64 timestamp_triggered; // Timestamp at the point of trigger
+ __u32 trackerEnable; // Workload trigger and enable settings
+ __u32 triggerthreshold; // Trigger threshold
+ __u32 triggeredValue; // Actual value fired the trigger
+};
+
+
+struct workloadLog { // Full WL Log Structure
+ struct workloadLogHeader header;
+ __u8 entry[MAX_WORKLOAD_LOG_ENTRIES][MAX_WORKLOAD_LOG_ENTRY_SIZE];
+};
+#pragma pack(pop)
+
+struct wltracker {
+ int fd;
+ struct workloadLog workload_log;
+ size_t entry_count;
+ unsigned int verbose;
+};
+
+static void wltracker_print_field_names(struct wltracker *wlt)
+{
+ struct workloadLog *log = &wlt->workload_log;
+ __u8 cnt = log->header.workloadLogCount;
+ union WorkloadLogEnable workloadEnable = (union WorkloadLogEnable)log->header.trackerEnable;
+ __u8 content_group = workloadEnable.field.contentGroup;
+
+ if (cnt == 0)
+ return;
+
+ printf("%-16s", "timestamp");
+
+ for (int i = 0 ; i < MAX_FIELDS; i++) {
+ struct field f = group_fields[content_group][i];
+
+ if (f.size == 0)
+ break;
+ if (f.name == NULL)
+ continue;
+ printf("%s ", f.name);
+ }
+
+ if (wlt->verbose > 1)
+ printf("%s", "entry#");
+
+ printf("\n");
+}
+
+static void wltracker_print_header(struct wltracker *wlt)
+{
+ struct workloadLog *log = &wlt->workload_log;
+ __u8 cnt = log->header.workloadLogCount;
+ union WorkloadLogEnable workloadEnable = (union WorkloadLogEnable)log->header.trackerEnable;
+ __u8 content_group = workloadEnable.field.contentGroup;
+
+ printf("%-20s %u.%u\n", "Log page version:", le16_to_cpu(log->header.majorVersion),
+ le16_to_cpu(log->header.minorVersion));
+ printf("%-20s %u\n", "Sample period(ms):",
+ le32_to_cpu(log->header.samplePeriodInMilliseconds));
+ printf("%-20s %lu\n", "timestamp_lastEntry:",
+ le64_to_cpu(log->header.timestamp_lastEntry) / WLT2MS);
+ printf("%-20s %lu\n", "timestamp_triggered:",
+ le64_to_cpu(log->header.timestamp_triggered/1000));
+ printf("%-20s 0x%x\n", "trackerEnable:", le32_to_cpu(log->header.trackerEnable));
+ printf("%-20s %u\n", "Triggerthreshold:",
+ le32_to_cpu(log->header.triggerthreshold));
+ printf("%-20s %u\n", "ValueTriggered:", le32_to_cpu(log->header.triggeredValue));
+ printf("%-20s %s\n", "Tracker Type:", trk_types[content_group]);
+ printf("%-30s %u\n", "Total workload log entries:", le16_to_cpu(cnt));
+ printf("%-20s %ld\n\n", "Sample count:", wlt->entry_count);
+ if (wlt->entry_count != 0)
+ wltracker_print_field_names(wlt);
+}
+
+static int wltracker_show_newer_entries(struct wltracker *wlt)
+{
+ struct workloadLog *log = &wlt->workload_log;
+ __u8 cnt;
+ __u8 content_group;
+ static __u64 last_timestamp_ms;
+ __u64 timestamp = 0;
+ union WorkloadLogEnable workloadEnable;
+
+ int err = nvme_get_log_simple(wlt->fd, LID, sizeof(struct workloadLog), log);
+
+ if (err > 0) {
+ nvme_show_status(err);
+ return err;
+ }
+ if (err < 0)
+ return err;
+
+ if (wlt->verbose)
+ wltracker_print_header(wlt);
+
+ cnt = log->header.workloadLogCount;
+ workloadEnable = (union WorkloadLogEnable)log->header.trackerEnable;
+ content_group = workloadEnable.field.contentGroup;
+
+ if (cnt == 0) {
+ nvme_show_error("Warning : No valid workload log data\n");
+ return 0;
+ }
+
+ timestamp = (le64_to_cpu(log->header.timestamp_lastEntry) / WLT2MS) -
+ (log->header.samplePeriodInMilliseconds * (cnt - 1));
+
+
+ if (wlt->entry_count == 0)
+ wltracker_print_field_names(wlt);
+
+ for (int i = cnt - 1; i >= 0; i--) {
+ int offset = 0;
+ __u8 *entry = (__u8 *) &log->entry[i];
+ bool is_old = timestamp <= last_timestamp_ms;
+
+ if (is_old) {
+ timestamp += log->header.samplePeriodInMilliseconds;
+ continue;
+ }
+ printf("%-16llu", timestamp);
+ for (int j = 0; j < MAX_FIELDS; j++) {
+ __u32 val = 0;
+ struct field f = group_fields[content_group][j];
+
+ if (f.size == 0) {
+ if (wlt->verbose > 1)
+ printf("%-*i", (int)sizeof("entry#"), i);
+ printf("\n");
+ break;
+ }
+ if (f.name == NULL)
+ continue;
+
+ switch (f.size) {
+ case 1:
+ val = *(entry+offset);
+ break;
+ case 2:
+ val = *(__u16 *)(entry + offset);
+ break;
+ case 4:
+ val = *(__u32 *)(entry + offset);
+ break;
+ default:
+ nvme_show_error("Bad field size");
+ }
+ offset += f.size;
+
+ printf("%-*u ", (int)strlen(f.name), val);
+ }
+ wlt->entry_count++;
+ timestamp += log->header.samplePeriodInMilliseconds;
+ }
+ last_timestamp_ms = log->header.timestamp_lastEntry / WLT2MS;
+ return 0;
+}
+
+int wltracker_config(struct wltracker *wlt, union WorkloadLogEnable *we)
+{
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = wlt->fd,
+ .fid = FID,
+ .cdw11 = we->dword,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ };
+
+ return nvme_set_features(&args);
+}
+
+static int stricmp(char const *a, char const *b)
+{
+ for (; *a || *b; a++, b++)
+ if (tolower((unsigned char)*a) != tolower((unsigned char)*b))
+ return 1;
+ return 0;
+}
+
+static int find_option(char const *list[], int size, const char *val)
+{
+ for (int i = 0; i < size; i++) {
+ if (!stricmp(val, list[i]))
+ return i;
+ }
+ return -EINVAL;
+}
+
+static void join(char *dest, char const *list[], size_t list_size)
+{
+ strcat(dest, list[0]);
+ for (int i = 1; i < list_size; i++) {
+ strcat(dest, "|");
+ strcat(dest, list[i]);
+ }
+}
+
+__u64 micros(void)
+{
+ struct timespec ts;
+ __u64 us;
+
+ clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+ us = (((__u64)ts.tv_sec)*1000000) + (((__u64)ts.tv_nsec)/1000);
+ return us;
+}
+
+int sldgm_get_workload_tracker(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct wltracker wlt = {0};
+ union WorkloadLogEnable we = {0};
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ const char *desc = "Real Time capture Workload Tracker samples";
+ const char *sample_interval = "Sample interval";
+ const char *run_time = "Limit runtime capture time in seconds";
+ const char *flush_frequency =
+ "Samples (1 to 126) to wait for extracting data. Default 100 samples";
+ char type_options[80] = {0};
+ char sample_options[80] = {0};
+ __u64 us_start;
+ __u64 run_time_us;
+ __u64 elapsed_run_time_us = 0;
+ __u64 next_sample_us = 0;
+ int opt;
+ int err;
+
+ struct config {
+ bool enable;
+ bool disable;
+ const char *tracker_type;
+ const char *sample_time;
+ int run_time_s;
+ int flush_frequency;
+ };
+
+ struct config cfg = {
+ .sample_time = samplet[0],
+ .flush_frequency = 100,
+ .tracker_type = trk_types[0],
+ };
+
+ join(type_options, trk_types, ARRAY_SIZE(trk_types));
+ join(sample_options, samplet, ARRAY_SIZE(samplet));
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("enable", 'e', &cfg.enable, "tracker enable"),
+ OPT_FLAG("disable", 'd', &cfg.disable, "tracker disable"),
+ OPT_STRING("sample-time", 's', sample_options, &cfg.sample_time, sample_interval),
+ OPT_STRING("type", 't', type_options, &cfg.tracker_type, "Tracker type"),
+ OPT_INT("run-time", 'r', &cfg.run_time_s, run_time),
+ OPT_INT("flush-freq", 'f', &cfg.flush_frequency, flush_frequency),
+ OPT_INCR("verbose", 'v', &wlt.verbose, "Increase logging verbosity"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ wlt.fd = dev_fd(dev);
+
+ if ((cfg.flush_frequency < 1) || (cfg.flush_frequency > MAX_WORKLOAD_LOG_ENTRIES)) {
+ nvme_show_error("Invalid number of samples: %s. Valid values: 1-%d",
+ cfg.flush_frequency, MAX_WORKLOAD_LOG_ENTRIES);
+ return -EINVAL;
+ }
+
+ opt = find_option(samplet, ARRAY_SIZE(samplet), cfg.sample_time);
+ if (opt < 0) {
+ nvme_show_error("invalid Sample interval: %s. Valid values: %s",
+ cfg.sample_time, sample_options);
+ return -EINVAL;
+ }
+ we.field.sampleTime = opt;
+
+ opt = find_option(trk_types, ARRAY_SIZE(trk_types), cfg.tracker_type);
+ if (opt < 0) {
+ nvme_show_error("Invalid tracker type: %s. Valid types: %s",
+ cfg.tracker_type, type_options);
+ return -EINVAL;
+ }
+ we.field.contentGroup = opt;
+
+ if (cfg.enable && cfg.disable) {
+ nvme_show_error("Can't enable disable simultaneously");
+ return -EINVAL;
+ }
+
+ if (cfg.enable || cfg.disable) {
+ we.field.trackerEnable = cfg.enable;
+ err = wltracker_config(&wlt, &we);
+ if (err < 0) {
+ nvme_show_error("tracker set-feature: %s", nvme_strerror(errno));
+ return err;
+ } else if (err > 0) {
+ nvme_show_status(err);
+ return err;
+ }
+ }
+
+ if (cfg.disable && !cfg.enable) {
+ printf("Tracker disabled\n");
+ return 0;
+ }
+
+ us_start = micros();
+ run_time_us = cfg.run_time_s * 1000000;
+ while (elapsed_run_time_us < run_time_us) {
+ __u64 interval;
+ __u64 elapsed;
+ __u64 prev_elapsed_run_time_us = elapsed_run_time_us;
+
+ err = wltracker_show_newer_entries(&wlt);
+
+ if (err > 0) {
+ nvme_show_status(err);
+ return err;
+ }
+ interval = ((__u64)wlt.workload_log.header.samplePeriodInMilliseconds) * 1000 *
+ cfg.flush_frequency;
+ next_sample_us += interval;
+ elapsed_run_time_us = micros() - us_start;
+ elapsed = elapsed_run_time_us - prev_elapsed_run_time_us;
+ if (wlt.verbose > 1)
+ printf("elapsed_run_time: %lluus\n", elapsed_run_time_us);
+ if (interval > elapsed) {
+ __u64 period_us = min(next_sample_us - elapsed_run_time_us,
+ run_time_us - elapsed_run_time_us);
+ if (wlt.verbose > 1)
+ printf("Sleeping %lluus..\n", period_us);
+ usleep(period_us);
+ }
+ elapsed_run_time_us = micros() - us_start;
+ }
+
+ err = wltracker_show_newer_entries(&wlt);
+
+ elapsed_run_time_us = micros() - us_start;
+ if (wlt.verbose > 0)
+ printf("elapsed_run_time: %lluus\n", elapsed_run_time_us);
+
+ if (err > 0) {
+ nvme_show_status(err);
+ return err;
+ }
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-workload-tracker.h b/plugins/solidigm/solidigm-workload-tracker.h
new file mode 100644
index 0000000..d3ecc16
--- /dev/null
+++ b/plugins/solidigm/solidigm-workload-tracker.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2024 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int sldgm_get_workload_tracker(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/ssstc/ssstc-nvme.c b/plugins/ssstc/ssstc-nvme.c
new file mode 100644
index 0000000..302df98
--- /dev/null
+++ b/plugins/ssstc/ssstc-nvme.c
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "ssstc-nvme.h"
+
+struct __packed nvme_additional_smart_log_item
+{
+ __u8 key;
+ __u8 norm;
+ union __packed {
+ __u8 raw[6];
+ struct __packed wear_level
+ {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+ } wear_level;
+ };
+ __u8 _rp[2];
+};
+
+struct nvme_additional_smart_log {
+ struct nvme_additional_smart_log_item program_fail_cnt;
+ struct nvme_additional_smart_log_item erase_fail_cnt;
+ struct nvme_additional_smart_log_item wear_leveling_cnt;
+ struct nvme_additional_smart_log_item e2e_err_cnt;
+ struct nvme_additional_smart_log_item crc_err_cnt;
+ struct nvme_additional_smart_log_item nand_bytes_written;
+ struct nvme_additional_smart_log_item host_bytes_written;
+ struct nvme_additional_smart_log_item reallocated_sector_count;
+ struct nvme_additional_smart_log_item uncorrectable_sector_count;
+ struct nvme_additional_smart_log_item NAND_ECC_Detection_Count;
+ struct nvme_additional_smart_log_item NAND_ECC_Correction_Count;
+ struct nvme_additional_smart_log_item Bad_Block_Failure_Rate;
+ struct nvme_additional_smart_log_item GC_Count;
+ struct nvme_additional_smart_log_item DRAM_UECC_Detection_Count;
+ struct nvme_additional_smart_log_item SRAM_UECC_Detection_Count;
+ struct nvme_additional_smart_log_item Raid_Recovery_Fail_Count;
+ struct nvme_additional_smart_log_item Inflight_Command;
+ struct nvme_additional_smart_log_item Internal_End_to_End_Dect_Count;
+ struct nvme_additional_smart_log_item PCIe_Correctable_Error_Count;
+ struct nvme_additional_smart_log_item die_fail_count;
+ struct nvme_additional_smart_log_item wear_leveling_exec_count;
+ struct nvme_additional_smart_log_item read_disturb_count;
+ struct nvme_additional_smart_log_item data_retention_count;
+};
+
+
+static
+void show_ssstc_add_smart_log_jsn(struct nvme_additional_smart_log *smart,
+ unsigned int nsid, const char *devname)
+{
+ struct json_object *root, *entry_stats, *dev_stats, *multi;
+ uint16_t wear_level_min = 0;
+ uint16_t wear_level_max = 0;
+ uint16_t wear_level_avg = 0;
+ uint64_t raw_val = 0;
+
+ root = json_create_object();
+ json_object_add_value_string(root, "SSSTC Smart log", devname);
+
+ dev_stats = json_create_object();
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->program_fail_cnt.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->program_fail_cnt.norm);
+ raw_val = int48_to_long(smart->program_fail_cnt.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "program_fail_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->erase_fail_cnt.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->erase_fail_cnt.norm);
+ raw_val = int48_to_long(smart->erase_fail_cnt.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "erase_fail_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->wear_leveling_cnt.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->wear_leveling_cnt.norm);
+ multi = json_create_object();
+ wear_level_min = le16_to_cpu(smart->wear_leveling_cnt.wear_level.min);
+ wear_level_max = le16_to_cpu(smart->wear_leveling_cnt.wear_level.max);
+ wear_level_avg = le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg);
+ json_object_add_value_int(multi, "min", wear_level_min);
+ json_object_add_value_int(multi, "max", wear_level_max);
+ json_object_add_value_int(multi, "avg", wear_level_avg);
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "wear_leveling", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->e2e_err_cnt.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->e2e_err_cnt.norm);
+ multi = json_create_object();
+ wear_level_min = le16_to_cpu(smart->e2e_err_cnt.wear_level.min);
+ wear_level_max = le16_to_cpu(smart->e2e_err_cnt.wear_level.max);
+ wear_level_avg = le16_to_cpu(smart->e2e_err_cnt.wear_level.avg);
+ json_object_add_value_int(multi, "guard check error", wear_level_min);
+ json_object_add_value_int(multi, "application tag check error", wear_level_max);
+ json_object_add_value_int(multi, "reference tag check error", wear_level_avg);
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "end_to_end_error_dect_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->crc_err_cnt.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->crc_err_cnt.norm);
+ raw_val = int48_to_long(smart->crc_err_cnt.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "crc_error_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->nand_bytes_written.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->nand_bytes_written.norm);
+ raw_val = int48_to_long(smart->nand_bytes_written.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "nand_bytes_written", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->host_bytes_written.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->host_bytes_written.norm);
+ raw_val = int48_to_long(smart->host_bytes_written.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "host_bytes_written", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->reallocated_sector_count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->reallocated_sector_count.norm);
+ raw_val = int48_to_long(smart->reallocated_sector_count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "reallocated_sector_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->uncorrectable_sector_count.key);
+ json_object_add_value_int(entry_stats, "normalized",
+ smart->uncorrectable_sector_count.norm);
+ raw_val = int48_to_long(smart->uncorrectable_sector_count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "uncorrectable_sector_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->NAND_ECC_Detection_Count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->NAND_ECC_Detection_Count.norm);
+ raw_val = int48_to_long(smart->NAND_ECC_Detection_Count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "NAND_ECC_detection_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->NAND_ECC_Correction_Count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->NAND_ECC_Correction_Count.norm);
+ raw_val = int48_to_long(smart->NAND_ECC_Correction_Count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "NAND_ECC_correction_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->GC_Count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->GC_Count.norm);
+ raw_val = int48_to_long(smart->GC_Count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "GC_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->DRAM_UECC_Detection_Count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->DRAM_UECC_Detection_Count.norm);
+ multi = json_create_object();
+ wear_level_max = le16_to_cpu(smart->DRAM_UECC_Detection_Count.wear_level.max);
+ wear_level_avg = le16_to_cpu(smart->DRAM_UECC_Detection_Count.wear_level.avg);
+ json_object_add_value_int(multi, "1-Bit Err", wear_level_max);
+ json_object_add_value_int(multi, "2-Bit Err", wear_level_avg);
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "DRAM_UECC_detection_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->SRAM_UECC_Detection_Count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->SRAM_UECC_Detection_Count.norm);
+ multi = json_create_object();
+ wear_level_min = le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.min);
+ wear_level_max = le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.max);
+ wear_level_avg = le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.avg);
+ json_object_add_value_int(multi, "parity error detected", wear_level_min);
+ json_object_add_value_int(multi, "ecc error detection", wear_level_max);
+ json_object_add_value_int(multi, "axi data parity errors", wear_level_avg);
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "SRAM_UECC_Detection_Count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->Raid_Recovery_Fail_Count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->Raid_Recovery_Fail_Count.norm);
+ raw_val = int48_to_long(smart->Raid_Recovery_Fail_Count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "raid_Recovery_fail_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->Inflight_Command.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->Inflight_Command.norm);
+ multi = json_create_object();
+ wear_level_min = le16_to_cpu(smart->Inflight_Command.wear_level.min);
+ wear_level_max = le16_to_cpu(smart->Inflight_Command.wear_level.max);
+ wear_level_avg = le16_to_cpu(smart->Inflight_Command.wear_level.avg);
+ json_object_add_value_int(multi, "Read Cmd", wear_level_min);
+ json_object_add_value_int(multi, "Write Cmd", wear_level_max);
+ json_object_add_value_int(multi, "Admin Cmd", wear_level_avg);
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "Inflight_Command", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->Internal_End_to_End_Dect_Count.key);
+ json_object_add_value_int(entry_stats, "normalized", 100);
+ multi = json_create_object();
+ wear_level_min = le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.min);
+ wear_level_max = le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.max);
+ wear_level_avg = le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.avg);
+ json_object_add_value_int(multi, "read hcrc", wear_level_min);
+ json_object_add_value_int(multi, "write hcrc", wear_level_max);
+ json_object_add_value_int(multi, "reserved", wear_level_avg);
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "internal_end_to_end_dect_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->die_fail_count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->die_fail_count.norm);
+ raw_val = int48_to_long(smart->die_fail_count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "die_fail_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->wear_leveling_exec_count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->wear_leveling_exec_count.norm);
+ raw_val = int48_to_long(smart->wear_leveling_exec_count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "wear_leveling_exec_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->read_disturb_count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->read_disturb_count.norm);
+ raw_val = int48_to_long(smart->read_disturb_count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "read_disturb_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "#id", smart->data_retention_count.key);
+ json_object_add_value_int(entry_stats, "normalized", smart->data_retention_count.norm);
+ raw_val = int48_to_long(smart->data_retention_count.raw);
+ json_object_add_value_int(entry_stats, "raw", raw_val);
+ json_object_add_value_object(dev_stats, "data_retention_count", entry_stats);
+
+ json_object_add_value_object(root, "Device stats", dev_stats);
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+}
+
+static
+void show_ssstc_add_smart_log(struct nvme_additional_smart_log *smart,
+ unsigned int nsid, const char *devname)
+{
+ printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
+ devname, nsid);
+ printf("key #id normalized raw\n");
+ printf("program_fail_count : %03d %3d%% %"PRIu64"\n",
+ smart->program_fail_cnt.key,
+ smart->program_fail_cnt.norm,
+ int48_to_long(smart->program_fail_cnt.raw));
+ printf("erase_fail_count : %03d %3d%% %"PRIu64"\n",
+ smart->erase_fail_cnt.key,
+ smart->erase_fail_cnt.norm,
+ int48_to_long(smart->erase_fail_cnt.raw));
+ printf("wear_leveling : %03d %3d%% min: %u, max: %u, avg: %u\n",
+ smart->wear_leveling_cnt.key,
+ smart->wear_leveling_cnt.norm,
+ le16_to_cpu(smart->wear_leveling_cnt.wear_level.min),
+ le16_to_cpu(smart->wear_leveling_cnt.wear_level.max),
+ le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg));
+ printf("end_to_end_error_dect_count : %03d %3d%% "
+ "guard check error: %u, "
+ "application tag check error: %u, "
+ "reference tag check error: %u\n",
+ smart->e2e_err_cnt.key,
+ smart->e2e_err_cnt.norm,
+ le16_to_cpu(smart->e2e_err_cnt.wear_level.min),
+ le16_to_cpu(smart->e2e_err_cnt.wear_level.max),
+ le16_to_cpu(smart->e2e_err_cnt.wear_level.avg));
+ printf("crc_error_count : %03d %3d%% %"PRIu64"\n",
+ smart->crc_err_cnt.key,
+ smart->crc_err_cnt.norm,
+ int48_to_long(smart->crc_err_cnt.raw));
+ printf("nand_bytes_written : %03d %3d%% sectors: %"PRIu64"\n",
+ smart->nand_bytes_written.key,
+ smart->nand_bytes_written.norm,
+ int48_to_long(smart->nand_bytes_written.raw));
+ printf("host_bytes_written : %3d %3d%% sectors: %"PRIu64"\n",
+ smart->host_bytes_written.key,
+ smart->host_bytes_written.norm,
+ int48_to_long(smart->host_bytes_written.raw));
+ printf("reallocated_sector_count : %03d %3d%% %"PRIu64"\n",
+ smart->reallocated_sector_count.key,
+ smart->reallocated_sector_count.norm,
+ int48_to_long(smart->reallocated_sector_count.raw));
+ printf("uncorrectable_sector_count : %03d %3d%% %"PRIu64"\n",
+ smart->uncorrectable_sector_count.key,
+ smart->uncorrectable_sector_count.norm,
+ int48_to_long(smart->uncorrectable_sector_count.raw));
+ printf("NAND_ECC_detection_count : %03d %3d%% %"PRIu64"\n",
+ smart->NAND_ECC_Detection_Count.key,
+ smart->NAND_ECC_Detection_Count.norm,
+ int48_to_long(smart->NAND_ECC_Detection_Count.raw));
+ printf("NAND_ECC_correction_count : %03d %3d%% %"PRIu64"\n",
+ smart->NAND_ECC_Correction_Count.key,
+ smart->NAND_ECC_Correction_Count.norm,
+ int48_to_long(smart->NAND_ECC_Correction_Count.raw));
+ printf("GC_count : %03d %3d%% %"PRIu64"\n",
+ smart->GC_Count.key,
+ smart->GC_Count.norm,
+ int48_to_long(smart->GC_Count.raw));
+ printf("DRAM_UECC_detection_count : %03d %3d%% 1-Bit Err: %u, 2-Bit Err: %u\n",
+ smart->DRAM_UECC_Detection_Count.key,
+ smart->DRAM_UECC_Detection_Count.norm,
+ le16_to_cpu(smart->DRAM_UECC_Detection_Count.wear_level.max),
+ le16_to_cpu(smart->DRAM_UECC_Detection_Count.wear_level.avg));
+ printf("SRAM_UECC_Detection_Count : %03d %3d%% "
+ "parity error detected: %u, "
+ "ecc error detection: %u, "
+ "axi data parity errors: %u\n",
+ smart->SRAM_UECC_Detection_Count.key,
+ smart->SRAM_UECC_Detection_Count.norm,
+ le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.min),
+ le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.max),
+ le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.avg));
+ printf("raid_recovery_fail_count : %03d %3d%% %"PRIu64"\n",
+ smart->Raid_Recovery_Fail_Count.key,
+ smart->Raid_Recovery_Fail_Count.norm,
+ int48_to_long(smart->Raid_Recovery_Fail_Count.raw));
+ printf("Inflight_Command : %03d %3d%% "
+ "Read Cmd: %u, Write Cmd: %u, Admin Cmd: %u\n",
+ smart->Inflight_Command.key,
+ smart->Inflight_Command.norm,
+ le16_to_cpu(smart->Inflight_Command.wear_level.min),
+ le16_to_cpu(smart->Inflight_Command.wear_level.max),
+ le16_to_cpu(smart->Inflight_Command.wear_level.avg));
+ printf("internal_end_to_end_dect_count : %03d %3d%% "
+ "read hcrc: %u, write hcrc: %u, reserved: %u\n",
+ smart->Internal_End_to_End_Dect_Count.key,
+ 100,
+ le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.min),
+ le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.max),
+ le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.avg));
+ printf("die_fail_count : %03d %3d%% %"PRIu64"\n",
+ smart->die_fail_count.key,
+ smart->die_fail_count.norm,
+ int48_to_long(smart->die_fail_count.raw));
+ printf("wear_leveling_exec_count : %03d %3d%% %"PRIu64"\n",
+ smart->wear_leveling_exec_count.key,
+ smart->wear_leveling_exec_count.norm,
+ int48_to_long(smart->wear_leveling_exec_count.raw));
+ printf("read_disturb_count : %03d %3d%% %"PRIu64"\n",
+ smart->read_disturb_count.key,
+ smart->read_disturb_count.norm,
+ int48_to_long(smart->read_disturb_count.raw));
+ printf("data_retention_count : %03d %3d%% %"PRIu64"\n",
+ smart->data_retention_count.key,
+ smart->data_retention_count.norm,
+ int48_to_long(smart->data_retention_count.raw));
+}
+
+static
+int ssstc_get_add_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+
+ const char *desc =
+ "Get SSSTC vendor specific additional smart log\n"
+ "(optionally, for the specified namespace), and show it.";
+ const char *namespace = "(optional) desired namespace";
+ const char *raw = "Dump output in binary format";
+ const char *json = "Dump output in json format";
+
+ struct nvme_additional_smart_log smart_log_add;
+ struct nvme_dev *dev;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ bool json;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_FLAG("json", 'j', &cfg.json, json),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xca, sizeof(smart_log_add),
+ &smart_log_add);
+ if (!err) {
+ if (cfg.json)
+ show_ssstc_add_smart_log_jsn(&smart_log_add, cfg.namespace_id,
+ dev->name);
+ else if (!cfg.raw_binary)
+ show_ssstc_add_smart_log(&smart_log_add, cfg.namespace_id,
+ dev->name);
+ else
+ d_raw((unsigned char *)&smart_log_add, sizeof(smart_log_add));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+ dev_close(dev);
+ return err;
+
+}
diff --git a/plugins/ssstc/ssstc-nvme.h b/plugins/ssstc/ssstc-nvme.h
new file mode 100644
index 0000000..e34fa50
--- /dev/null
+++ b/plugins/ssstc/ssstc-nvme.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/ssstc/ssstc-nvme
+
+#if !defined(SSSTC_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define SSSTC_NVME
+
+#include "cmd.h"
+PLUGIN(NAME("ssstc", "SSSTC vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve ssstc SMART Log, show it", ssstc_get_add_smart_log)
+ )
+);
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/virtium/virtium-nvme.c b/plugins/virtium/virtium-nvme.c
index 0ba4b15..ad9938d 100644
--- a/plugins/virtium/virtium-nvme.c
+++ b/plugins/virtium/virtium-nvme.c
@@ -32,14 +32,14 @@ static char vt_default_log_file_name[256];
struct vtview_log_header {
char path[256];
char test_name[256];
- long time_stamp;
+ time_t time_stamp;
struct nvme_id_ctrl raw_ctrl;
struct nvme_firmware_slot raw_fw;
};
struct vtview_smart_log_entry {
char path[256];
- long time_stamp;
+ time_t time_stamp;
struct nvme_id_ns raw_ns;
struct nvme_id_ctrl raw_ctrl;
struct nvme_smart_log raw_smart;
diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c
index 8cbcf2e..fa4157d 100644
--- a/plugins/wdc/wdc-nvme.c
+++ b/plugins/wdc/wdc-nvme.c
@@ -681,44 +681,6 @@ struct __packed wdc_nvme_ext_smart_log {
__u8 ext_smart_lpg[16]; /* 496 Log page GUID */
};
-enum {
- SCAO_PMUW = 0, /* Physical media units written */
- SCAO_PMUR = 16, /* Physical media units read */
- SCAO_BUNBR = 32, /* Bad user nand blocks raw */
- SCAO_BUNBN = 38, /* Bad user nand blocks normalized */
- SCAO_BSNBR = 40, /* Bad system nand blocks raw */
- SCAO_BSNBN = 46, /* Bad system nand blocks normalized */
- SCAO_XRC = 48, /* XOR recovery count */
- SCAO_UREC = 56, /* Uncorrectable read error count */
- SCAO_SEEC = 64, /* Soft ecc error count */
- SCAO_EECE = 72, /* End to end corrected errors */
- SCAO_EEDC = 76, /* End to end detected errors */
- SCAO_SDPU = 80, /* System data percent used */
- SCAO_RFSC = 81, /* Refresh counts */
- SCAO_MXUDEC = 88, /* Max User data erase counts */
- SCAO_MNUDEC = 92, /* Min User data erase counts */
- SCAO_NTTE = 96, /* Number of Thermal throttling events */
- SCAO_CTS = 97, /* Current throttling status */
- SCAO_EVF = 98, /* Errata Version Field */
- SCAO_PVF = 99, /* Point Version Field */
- SCAO_MIVF = 101, /* Minor Version Field */
- SCAO_MAVF = 103, /* Major Version Field */
- SCAO_PCEC = 104, /* PCIe correctable error count */
- SCAO_ICS = 112, /* Incomplete shutdowns */
- SCAO_PFB = 120, /* Percent free blocks */
- SCAO_CPH = 128, /* Capacitor health */
- SCAO_NEV = 130, /* NVMe Errata Version */
- SCAO_UIO = 136, /* Unaligned I/O */
- SCAO_SVN = 144, /* Security Version Number */
- SCAO_NUSE = 152, /* NUSE - Namespace utilization */
- SCAO_PSC = 160, /* PLP start count */
- SCAO_EEST = 176, /* Endurance estimate */
- SCAO_PLRC = 192, /* PCIe Link Retraining Count */
- SCAO_PSCC = 200, /* Power State Change Count */
- SCAO_LPV = 494, /* Log page version */
- SCAO_LPG = 496, /* Log page GUID */
-};
-
struct ocp_bad_nand_block_count {
__u64 raw : 48;
__u16 normalized : 16;
@@ -766,8 +728,9 @@ struct ocp_cloud_smart_log {
__u8 percent_free_blocks;
__u8 rsvd121[7];
__u16 capacitor_health;
- __u8 nvme_errata_ver;
- __u8 rsvd131[5];
+ __u8 nvme_base_errata_ver;
+ __u8 nvme_cmd_set_errata_ver;
+ __u8 rsvd132[4];
__u64 unaligned_io;
__u64 security_version_number;
__u64 total_nuse;
@@ -775,7 +738,8 @@ struct ocp_cloud_smart_log {
__u8 endurance_estimate[16];
__u64 pcie_link_retraining_cnt;
__u64 power_state_change_cnt;
- __u8 rsvd208[286];
+ char lowest_permitted_fw_rev[8];
+ __u8 rsvd216[278];
__u16 log_page_version;
__u8 log_page_guid[16];
};
@@ -1004,6 +968,13 @@ static int wdc_enc_submit_move_data(struct nvme_dev *dev, char *cmd, int len, in
static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev, __u8 log_id,
void **cbs_data);
static __u32 wdc_get_fw_cust_id(nvme_root_t r, struct nvme_dev *dev);
+static int wdc_print_c0_cloud_attr_log(void *data,
+ int fmt,
+ struct nvme_dev *dev);
+static int wdc_print_c0_eol_log(void *data, int fmt);
+static void wdc_show_cloud_smart_log_normal(struct ocp_cloud_smart_log *log,
+ struct nvme_dev *dev);
+static void wdc_show_cloud_smart_log_json(struct ocp_cloud_smart_log *log);
/* Drive log data size */
struct wdc_log_size {
@@ -1148,14 +1119,14 @@ struct __packed wdc_bd_ca_log_format {
__u8 raw_value[8];
};
-#define LATENCY_LOG_BUCKET_READ 3
-#define LATENCY_LOG_BUCKET_WRITE 2
-#define LATENCY_LOG_BUCKET_TRIM 1
-#define LATENCY_LOG_BUCKET_RESERVED 0
+#define WDC_LATENCY_LOG_BUCKET_READ 3
+#define WDC_LATENCY_LOG_BUCKET_WRITE 2
+#define WDC_LATENCY_LOG_BUCKET_TRIM 1
+#define WDC_LATENCY_LOG_BUCKET_RESERVED 0
-#define LATENCY_LOG_MEASURED_LAT_READ 2
-#define LATENCY_LOG_MEASURED_LAT_WRITE 1
-#define LATENCY_LOG_MEASURED_LAT_TRIM 0
+#define WDC_LATENCY_LOG_MEASURED_LAT_READ 2
+#define WDC_LATENCY_LOG_MEASURED_LAT_WRITE 1
+#define WDC_LATENCY_LOG_MEASURED_LAT_TRIM 0
struct __packed wdc_ssd_latency_monitor_log {
__u8 feature_status; /* 0x00 */
@@ -1180,8 +1151,9 @@ struct __packed wdc_ssd_latency_monitor_log {
__le64 static_latency_timestamp[4][3]; /* 0x130 - 0x18F */
__le16 static_measured_latency[4][3]; /* 0x190 - 0x1A7 */
__le16 static_latency_stamp_units; /* 0x1A8 */
- __u8 rsvd4[0x16]; /* 0x1AA */
+ __u8 rsvd4[10]; /* 0x1AA */
+ __u8 debug_telemetry_log_size[12]; /* 0x1B4 */
__le16 debug_log_trigger_enable; /* 0x1C0 */
__le16 debug_log_measured_latency; /* 0x1C2 */
__le64 debug_log_latency_stamp; /* 0x1C4 */
@@ -1249,25 +1221,29 @@ struct __packed wdc_ssd_d0_smart_log {
#define WDC_OCP_C1_GUID_LENGTH 16
#define WDC_ERROR_REC_LOG_BUF_LEN 512
#define WDC_ERROR_REC_LOG_ID 0xC1
-#define WDC_ERROR_REC_LOG_VERSION1 0001
-#define WDC_ERROR_REC_LOG_VERSION2 0002
struct __packed wdc_ocp_c1_error_recovery_log {
- __le16 panic_reset_wait_time; /* 000 - Panic Reset Wait Time */
- __u8 panic_reset_action; /* 002 - Panic Reset Action */
- __u8 dev_recovery_action1; /* 003 - Device Recovery Action 1 */
- __le64 panic_id; /* 004 - Panic ID */
- __le32 dev_capabilities; /* 012 - Device Capabilities */
- __u8 vs_recovery_opc; /* 016 - Vendor Specific Recovery Opcode */
- __u8 rsvd1[3]; /* 017 - 3 Reserved Bytes */
- __le32 vs_cmd_cdw12; /* 020 - Vendor Specific Command CDW12 */
- __le32 vs_cmd_cdw13; /* 024 - Vendor Specific Command CDW13 */
- __u8 vs_cmd_to; /* 028 - Vendor Specific Command Timeout V2 */
- __u8 dev_recovery_action2; /* 029 - Device Recovery Action 2 V2 */
- __u8 dev_recovery_action2_to; /* 030 - Device Recovery Action 2 Timeout V2 */
- __u8 rsvd2[463]; /* 031 - 463 Reserved Bytes */
- __le16 log_page_version; /* 494 - Log Page Version */
- __u8 log_page_guid[WDC_OCP_C1_GUID_LENGTH]; /* 496 - Log Page GUID */
+ __le16 panic_reset_wait_time; /* 000 - Panic Reset Wait Time */
+ __u8 panic_reset_action; /* 002 - Panic Reset Action */
+ __u8 dev_recovery_action1; /* 003 - Device Recovery Action 1 */
+ __le64 panic_id; /* 004 - Panic ID */
+ __le32 dev_capabilities; /* 012 - Device Capabilities */
+ __u8 vs_recovery_opc; /* 016 - Vendor Specific Recovery Opcode */
+ __u8 rsvd1[3]; /* 017 - 3 Reserved Bytes */
+ __le32 vs_cmd_cdw12; /* 020 - Vendor Specific Command CDW12 */
+ __le32 vs_cmd_cdw13; /* 024 - Vendor Specific Command CDW13 */
+ __u8 vs_cmd_to; /* 028 - Vendor Specific Command Timeout V2 */
+ __u8 dev_recovery_action2; /* 029 - Device Recovery Action 2 V2 */
+ __u8 dev_recovery_action2_to; /* 030 - Device Recovery Action 2 Timeout V2 */
+ __u8 panic_count; /* 031 - Number of panics encountered */
+ __le64 prev_panic_ids[4]; /* 032 - 063 Previous Panic ID's */
+ __u8 rsvd2[430]; /* 064 - 493 Reserved Bytes */
+ /* 430 reserved bytes aligns with the rest */
+ /* of the data structure. The size of 463 */
+ /* bytes mentioned in the OCP spec */
+ /* (version 2.5) would not fit here. */
+ __le16 log_page_version; /* 494 - Log Page Version */
+ __u8 log_page_guid[WDC_OCP_C1_GUID_LENGTH]; /* 496 - Log Page GUID */
};
static __u8 wdc_ocp_c1_guid[WDC_OCP_C1_GUID_LENGTH] = { 0x44, 0xD9, 0x31, 0x21, 0xFE, 0x30, 0x34, 0xAE,
@@ -1383,6 +1359,11 @@ struct __packed wdc_fw_act_history_log_format_c2 {
__u8 log_page_guid[WDC_C2_GUID_LENGTH];
};
+static __u8 ocp_C2_guid[WDC_C2_GUID_LENGTH] = {
+ 0x6D, 0x79, 0x9A, 0x76, 0xB4, 0xDA, 0xF6, 0xA3,
+ 0xE2, 0x4D, 0xB2, 0x8A, 0xAC, 0xF3, 0x1C, 0xD1
+};
+
#define WDC_OCP_C4_GUID_LENGTH 16
#define WDC_DEV_CAP_LOG_BUF_LEN 4096
#define WDC_DEV_CAP_LOG_ID 0xC4
@@ -1726,7 +1707,6 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
case WDC_NVME_VID_2:
switch (read_device_id) {
case WDC_NVME_SN630_DEV_ID:
- fallthrough;
case WDC_NVME_SN630_DEV_ID_1:
capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG |
WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT |
@@ -1743,19 +1723,12 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
break;
case WDC_NVME_SN640_DEV_ID:
- fallthrough;
case WDC_NVME_SN640_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN640_DEV_ID_2:
- fallthrough;
case WDC_NVME_SN640_DEV_ID_3:
- fallthrough;
case WDC_NVME_SN560_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN560_DEV_ID_2:
- fallthrough;
case WDC_NVME_SN560_DEV_ID_3:
- fallthrough;
case WDC_NVME_SN660_DEV_ID:
/* verify the 0xC0 log page is supported */
if (wdc_nvme_check_supported_log_page(r, dev,
@@ -1816,9 +1789,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
break;
case WDC_NVME_SN840_DEV_ID:
- fallthrough;
case WDC_NVME_SN840_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN860_DEV_ID:
/* verify the 0xC0 log page is supported */
if (wdc_nvme_check_supported_log_page(r, dev,
@@ -1826,7 +1797,6 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE;
fallthrough;
case WDC_NVME_ZN540_DEV_ID:
- fallthrough;
case WDC_NVME_SN540_DEV_ID:
capabilities |= (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG |
WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT |
@@ -1847,17 +1817,11 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
break;
case WDC_NVME_SN650_DEV_ID:
- fallthrough;
case WDC_NVME_SN650_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN650_DEV_ID_2:
- fallthrough;
case WDC_NVME_SN650_DEV_ID_3:
- fallthrough;
case WDC_NVME_SN650_DEV_ID_4:
- fallthrough;
case WDC_NVME_SN655_DEV_ID:
- fallthrough;
case WDC_NVME_SN550_DEV_ID:
/* verify the 0xC0 log page is supported */
if (wdc_nvme_check_supported_log_page(r, dev,
@@ -1907,7 +1871,6 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
break;
case WDC_NVME_SN861_DEV_ID:
- fallthrough;
case WDC_NVME_SN861_DEV_ID_1:
capabilities |= (WDC_DRIVE_CAP_C0_LOG_PAGE |
WDC_DRIVE_CAP_C3_LOG_PAGE |
@@ -1921,6 +1884,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
WDC_DRIVE_CAP_INFO |
WDC_DRIVE_CAP_CLOUD_SSD_VERSION |
WDC_DRIVE_CAP_LOG_PAGE_DIR |
+ WDC_DRIVE_CAP_DRIVE_STATUS |
WDC_DRIVE_CAP_SET_LATENCY_MONITOR);
break;
@@ -1936,11 +1900,8 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
break;
case WDC_NVME_SN520_DEV_ID:
- fallthrough;
case WDC_NVME_SN520_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN520_DEV_ID_2:
- fallthrough;
case WDC_NVME_SN810_DEV_ID:
capabilities = WDC_DRIVE_CAP_DUI_DATA;
break;
@@ -2010,19 +1971,14 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
case WDC_NVME_SN8000S_DEV_ID:
fallthrough;
case WDC_NVME_SN740_DEV_ID:
- fallthrough;
case WDC_NVME_SN740_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN740_DEV_ID_2:
- fallthrough;
case WDC_NVME_SN740_DEV_ID_3:
- fallthrough;
case WDC_NVME_SN340_DEV_ID:
capabilities = WDC_DRIVE_CAP_DUI;
break;
case WDC_NVME_ZN350_DEV_ID:
- fallthrough;
case WDC_NVME_ZN350_DEV_ID_1:
capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE |
WDC_DRIVE_CAP_C0_LOG_PAGE |
@@ -2450,23 +2406,32 @@ static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev,
uuid_index = index + 1;
}
- if (!uuid_index && needs_c2_log_page_check(device_id)) {
- /* In certain devices that don't support UUID lists, there are multiple
- * definitions of the C2 logpage. In those cases, the code
- * needs to try two UUID indexes and use an identification algorithm
- * to determine which is returning the correct log page data.
- */
- uuid_ix = 1;
- }
+ if (uuid_present) {
+ /* use the uuid index found above */
+ found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_index);
+ } else if (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) {
+ uuid_index = 0;
+ found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_index);
+ } else {
+ if (!uuid_index && needs_c2_log_page_check(device_id)) {
+ /* In certain devices that don't support UUID lists, there are multiple
+ * definitions of the C2 logpage. In those cases, the code
+ * needs to try two UUID indexes and use an identification algorithm
+ * to determine which is returning the correct log page data.
+ */
+ uuid_ix = 1;
+ }
- found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix);
+ found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix);
- if (!found) {
- /* not found with uuid = 1 try with uuid = 0 */
- uuid_ix = 0;
- fprintf(stderr, "Not found, requesting log page with uuid_index %d\n", uuid_index);
+ if (!found) {
+ /* not found with uuid = 1 try with uuid = 0 */
+ uuid_ix = 0;
+ fprintf(stderr, "Not found, requesting log page with uuid_index %d\n",
+ uuid_index);
- found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix);
+ found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix);
+ }
}
return found;
@@ -3722,7 +3687,7 @@ free_buf:
static int dump_internal_logs(struct nvme_dev *dev, char *dir_name, int verbose)
{
- char file_path[128];
+ char file_path[PATH_MAX];
void *telemetry_log;
const size_t bs = 512;
struct nvme_telemetry_log *hdr;
@@ -4692,20 +4657,30 @@ static int wdc_print_latency_monitor_log_normal(struct nvme_dev *dev,
printf(" Active Latency Minimum Window %d ms\n", 100*log_data->active_latency_min_window);
printf(" Active Latency Stamp Units %d\n", le16_to_cpu(log_data->active_latency_stamp_units));
printf(" Static Latency Stamp Units %d\n", le16_to_cpu(log_data->static_latency_stamp_units));
- printf(" Debug Log Trigger Enable %d\n", le16_to_cpu(log_data->debug_log_trigger_enable));
+ if (le16_to_cpu(log_data->log_page_version) >= 4)
+ printf(" Debug Telemetry Log Size %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)log_data->debug_telemetry_log_size));
+ printf(" Debug Log Trigger Enable %d\n",
+ le16_to_cpu(log_data->debug_log_trigger_enable));
+ printf(" Log Page Version %d\n",
+ le16_to_cpu(log_data->log_page_version));
+ printf(" Log page GUID 0x");
+ for (j = 0; j < WDC_C3_GUID_LENGTH; j++)
+ printf("%x", log_data->log_page_guid[j]);
+ printf("\n");
printf(" Read Write Deallocate/Trim\n");
for (i = 0; i <= 3; i++)
printf(" Active Bucket Counter: Bucket %d %27d %27d %27d\n",
- i, le32_to_cpu(log_data->active_bucket_counter[i][LATENCY_LOG_BUCKET_READ]),
- le32_to_cpu(log_data->active_bucket_counter[i][LATENCY_LOG_BUCKET_WRITE]),
- le32_to_cpu(log_data->active_bucket_counter[i][LATENCY_LOG_BUCKET_TRIM]));
+ i, le32_to_cpu(log_data->active_bucket_counter[i][WDC_LATENCY_LOG_BUCKET_READ]),
+ le32_to_cpu(log_data->active_bucket_counter[i][WDC_LATENCY_LOG_BUCKET_WRITE]),
+ le32_to_cpu(log_data->active_bucket_counter[i][WDC_LATENCY_LOG_BUCKET_TRIM]));
for (i = 3; i >= 0; i--)
printf(" Active Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n",
- 3-i, le16_to_cpu(log_data->active_measured_latency[i][LATENCY_LOG_MEASURED_LAT_READ]),
- le16_to_cpu(log_data->active_measured_latency[i][LATENCY_LOG_MEASURED_LAT_WRITE]),
- le16_to_cpu(log_data->active_measured_latency[i][LATENCY_LOG_MEASURED_LAT_TRIM]));
+ 3-i, le16_to_cpu(log_data->active_measured_latency[i][WDC_LATENCY_LOG_MEASURED_LAT_READ]),
+ le16_to_cpu(log_data->active_measured_latency[i][WDC_LATENCY_LOG_MEASURED_LAT_WRITE]),
+ le16_to_cpu(log_data->active_measured_latency[i][WDC_LATENCY_LOG_MEASURED_LAT_TRIM]));
for (i = 3; i >= 0; i--) {
printf(" Active Latency Time Stamp: Bucket %d ", 3-i);
@@ -4722,15 +4697,15 @@ static int wdc_print_latency_monitor_log_normal(struct nvme_dev *dev,
for (i = 0; i <= 3; i++)
printf(" Static Bucket Counter: Bucket %d %27d %27d %27d\n",
- i, le32_to_cpu(log_data->static_bucket_counter[i][LATENCY_LOG_BUCKET_READ]),
- le32_to_cpu(log_data->static_bucket_counter[i][LATENCY_LOG_BUCKET_WRITE]),
- le32_to_cpu(log_data->static_bucket_counter[i][LATENCY_LOG_BUCKET_TRIM]));
+ i, le32_to_cpu(log_data->static_bucket_counter[i][WDC_LATENCY_LOG_BUCKET_READ]),
+ le32_to_cpu(log_data->static_bucket_counter[i][WDC_LATENCY_LOG_BUCKET_WRITE]),
+ le32_to_cpu(log_data->static_bucket_counter[i][WDC_LATENCY_LOG_BUCKET_TRIM]));
for (i = 3; i >= 0; i--)
printf(" Static Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n",
- 3-i, le16_to_cpu(log_data->static_measured_latency[i][LATENCY_LOG_MEASURED_LAT_READ]),
- le16_to_cpu(log_data->static_measured_latency[i][LATENCY_LOG_MEASURED_LAT_WRITE]),
- le16_to_cpu(log_data->static_measured_latency[i][LATENCY_LOG_MEASURED_LAT_TRIM]));
+ 3-i, le16_to_cpu(log_data->static_measured_latency[i][WDC_LATENCY_LOG_MEASURED_LAT_READ]),
+ le16_to_cpu(log_data->static_measured_latency[i][WDC_LATENCY_LOG_MEASURED_LAT_WRITE]),
+ le16_to_cpu(log_data->static_measured_latency[i][WDC_LATENCY_LOG_MEASURED_LAT_TRIM]));
for (i = 3; i >= 0; i--) {
printf(" Static Latency Time Stamp: Bucket %d ", 3-i);
@@ -4766,7 +4741,22 @@ static void wdc_print_latency_monitor_log_json(struct wdc_ssd_latency_monitor_lo
json_object_add_value_int(root, "Active Lantency Minimum Window", 100*log_data->active_latency_min_window);
json_object_add_value_int(root, "Active Latency Stamp Units", le16_to_cpu(log_data->active_latency_stamp_units));
json_object_add_value_int(root, "Static Latency Stamp Units", le16_to_cpu(log_data->static_latency_stamp_units));
- json_object_add_value_int(root, "Debug Log Trigger Enable", le16_to_cpu(log_data->debug_log_trigger_enable));
+ if (le16_to_cpu(log_data->log_page_version) >= 4) {
+ json_object_add_value_int(root, "Debug Telemetry Log Size",
+ le64_to_cpu(*(uint64_t *)log_data->debug_telemetry_log_size));
+ }
+ json_object_add_value_int(root, "Debug Log Trigger Enable",
+ le16_to_cpu(log_data->debug_log_trigger_enable));
+ json_object_add_value_int(root, "Log Page Version",
+ le16_to_cpu(log_data->log_page_version));
+
+ char guid[40];
+
+ memset((void *)guid, 0, 40);
+ sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0]));
+ json_object_add_value_string(root, "Log page GUID", guid);
for (i = 0; i <= 3; i++) {
for (j = 2; j >= 0; j--) {
@@ -4825,13 +4815,20 @@ static void wdc_print_error_rec_log_normal(struct wdc_ocp_c1_error_recovery_log
printf(" Vendor Specific Recovery Opcode : 0x%x\n", log_data->vs_recovery_opc);
printf(" Vendor Specific Command CDW12 : 0x%x\n", le32_to_cpu(log_data->vs_cmd_cdw12));
printf(" Vendor Specific Command CDW13 : 0x%x\n", le32_to_cpu(log_data->vs_cmd_cdw13));
- if (le16_to_cpu(log_data->log_page_version) == WDC_ERROR_REC_LOG_VERSION2) {
+ if (le16_to_cpu(log_data->log_page_version) >= 2) {
printf(" Vendor Specific Command Timeout : 0x%x\n", log_data->vs_cmd_to);
printf(" Device Recovery Action 2 : 0x%x\n", log_data->dev_recovery_action2);
printf(" Device Recovery Action 2 Timeout : 0x%x\n", log_data->dev_recovery_action2_to);
}
- printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version));
- printf(" Log page GUID : 0x");
+ if (le16_to_cpu(log_data->log_page_version) >= 3) {
+ printf(" Panic Count : 0x%x\n", log_data->panic_count);
+ for (j = 0; j < 4; j++)
+ printf(" Previous Panic ID N-%d : 0x%"PRIx64"\n",
+ j+1, le64_to_cpu(log_data->prev_panic_ids[j]));
+ }
+ printf(" Log Page Version : 0x%x\n",
+ le16_to_cpu(log_data->log_page_version));
+ printf(" Log page GUID : 0x");
for (j = 0; j < WDC_OCP_C1_GUID_LENGTH; j++)
printf("%x", log_data->log_page_guid[j]);
printf("\n");
@@ -4839,6 +4836,8 @@ static void wdc_print_error_rec_log_normal(struct wdc_ocp_c1_error_recovery_log
static void wdc_print_error_rec_log_json(struct wdc_ocp_c1_error_recovery_log *log_data)
{
+ int j;
+ char buf[128];
struct json_object *root = json_create_object();
json_object_add_value_int(root, "Panic Reset Wait Time", le16_to_cpu(log_data->panic_reset_wait_time));
@@ -4849,12 +4848,21 @@ static void wdc_print_error_rec_log_json(struct wdc_ocp_c1_error_recovery_log *l
json_object_add_value_int(root, "Vendor Specific Recovery Opcode", log_data->vs_recovery_opc);
json_object_add_value_int(root, "Vendor Specific Command CDW12", le32_to_cpu(log_data->vs_cmd_cdw12));
json_object_add_value_int(root, "Vendor Specific Command CDW13", le32_to_cpu(log_data->vs_cmd_cdw13));
- if (le16_to_cpu(log_data->log_page_version) == WDC_ERROR_REC_LOG_VERSION2) {
+ if (le16_to_cpu(log_data->log_page_version) >= 2) {
json_object_add_value_int(root, "Vendor Specific Command Timeout", log_data->vs_cmd_to);
json_object_add_value_int(root, "Device Recovery Action 2", log_data->dev_recovery_action2);
json_object_add_value_int(root, "Device Recovery Action 2 Timeout", log_data->dev_recovery_action2_to);
}
- json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+ if (le16_to_cpu(log_data->log_page_version) >= 3) {
+ json_object_add_value_int(root, "Panic Count", log_data->panic_count);
+ for (j = 0; j < 4; j++) {
+ sprintf(buf, "Previous Panic ID N-%d", j+1);
+ json_object_add_value_int(root, buf,
+ le64_to_cpu(log_data->prev_panic_ids[j]));
+ }
+ }
+ json_object_add_value_int(root, "Log Page Version",
+ le16_to_cpu(log_data->log_page_version));
char guid[40];
@@ -5538,17 +5546,18 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries,
char previous_fw[9];
char new_fw[9];
char commit_action_bin[8];
- char time_str[11];
+ char time_str[100];
__u16 oldestEntryIdx = 0, entryIdx = 0;
+ uint64_t timestamp;
+ __u64 timestamp_sec;
char *null_fw = "--------";
- memset((void *)time_str, 0, 11);
+ memset((void *)time_str, '\0', 100);
if (data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
printf(" Firmware Activate History Log\n");
if (cust_id == WDC_CUSTOMER_ID_0x1005 ||
- vendor_id == WDC_NVME_SNDK_VID ||
- wdc_is_sn861(device_id)) {
+ vendor_id == WDC_NVME_SNDK_VID) {
printf(" Power on Hour Power Cycle Previous New\n");
printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result\n");
printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n");
@@ -5589,48 +5598,33 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries,
memcpy(new_fw, null_fw, 8);
printf("%5"PRIu16"", (uint16_t)le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries));
+
+ timestamp = (0x0000FFFFFFFFFFFF &
+ le64_to_cpu(
+ fw_act_history_entry->entry[entryIdx].timestamp));
+ timestamp_sec = timestamp / 1000;
if (cust_id == WDC_CUSTOMER_ID_0x1005) {
printf(" ");
memset((void *)time_str, 0, 9);
- sprintf((char *)time_str, "%04d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)/3600),
- (int)((le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp%3600)/60)),
- (int)(le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp%60)));
+ sprintf((char *)time_str, "%"PRIu32":%u:%u",
+ (__u32)(timestamp_sec/3600),
+ (__u8)(timestamp_sec%3600/60),
+ (__u8)(timestamp_sec%60));
printf("%s", time_str);
printf(" ");
} else if (vendor_id == WDC_NVME_SNDK_VID) {
printf(" ");
- uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
memset((void *)time_str, 0, 9);
- sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60),
- (int)((timestamp/1000)%60));
+ sprintf((char *)time_str, "%"PRIu32":%u:%u",
+ (__u32)((timestamp_sec/3600)%24),
+ (__u8)((timestamp_sec/60)%60),
+ (__u8)(timestamp_sec%60));
printf("%s", time_str);
printf(" ");
- } else if (wdc_is_sn861(device_id)) {
- printf(" ");
- char timestamp[20];
- __u64 hour;
- __u8 min;
- __u8 sec;
- __u64 timestamp_sec;
-
- timestamp_sec =
- le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)
- / 1000;
- hour = timestamp_sec / 3600;
- min = (timestamp_sec % 3600) / 60;
- sec = timestamp_sec % 60;
-
- sprintf(timestamp,
- "%"PRIu64":%02"PRIu8":%02"PRIu8,
- (uint64_t)hour, min, sec);
- printf("%-11s", timestamp);
- printf(" ");
} else {
printf(" ");
- uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
-
printf("%16"PRIu64"", timestamp);
printf(" ");
}
@@ -5735,13 +5729,15 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries,
char new_fw[9];
char commit_action_bin[8];
char fail_str[32];
- char time_str[11];
+ char time_str[100];
char ext_time_str[20];
+ uint64_t timestamp;
+ __u64 timestamp_sec;
memset((void *)previous_fw, 0, 9);
memset((void *)new_fw, 0, 9);
memset((void *)commit_action_bin, 0, 8);
- memset((void *)time_str, 0, 11);
+ memset((void *)time_str, '\0', 100);
memset((void *)ext_time_str, 0, 20);
memset((void *)fail_str, 0, 11);
char *null_fw = "--------";
@@ -5781,33 +5777,25 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries,
json_object_add_value_int(root, "Entry",
le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries));
+ timestamp = (0x0000FFFFFFFFFFFF &
+ le64_to_cpu(
+ fw_act_history_entry->entry[entryIdx].timestamp));
+ timestamp_sec = timestamp / 1000;
if (cust_id == WDC_CUSTOMER_ID_0x1005) {
- sprintf((char *)time_str, "%04d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)/3600),
- (int)((le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp%3600)/60)),
- (int)(le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp%60)));
+ sprintf((char *)time_str, "%"PRIu32":%u:%u",
+ (__u32)(timestamp_sec/3600),
+ (__u8)(timestamp_sec%3600/60),
+ (__u8)(timestamp_sec%60));
json_object_add_value_string(root, "Power on Hour", time_str);
} else if (vendor_id == WDC_NVME_SNDK_VID) {
- uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
-
- sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60),
- (int)((timestamp/1000)%60));
+ sprintf((char *)time_str, "%"PRIu32":%u:%u",
+ (__u32)((timestamp_sec/3600)%24),
+ (__u8)((timestamp_sec/60)%60),
+ (__u8)(timestamp_sec%60));
json_object_add_value_string(root, "Power on Hour", time_str);
- } else if (wdc_is_sn861(device_id)) {
- __u64 timestamp_sec =
- le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)
- / 1000;
-
- sprintf((char *)ext_time_str,
- "%"PRIu64":%02"PRIu8":%02"PRIu8,
- (uint64_t)(__u64)(timestamp_sec/3600),
- (__u8)((timestamp_sec%3600)/60),
- (__u8)(timestamp_sec%60));
- json_object_add_value_string(root, "Power on Hour", ext_time_str);
} else {
- uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
-
json_object_add_value_uint64(root, "Timestamp", timestamp);
}
@@ -5906,6 +5894,141 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries,
json_free_object(root);
}
+static int nvme_get_print_ocp_cloud_smart_log(struct nvme_dev *dev,
+ int uuid_index,
+ __u32 namespace_id,
+ int fmt)
+{
+ struct ocp_cloud_smart_log *log_ptr = NULL;
+ int ret, i;
+ __u32 length = WDC_NVME_SMART_CLOUD_ATTR_LEN;
+ int fd = dev_fd(dev);
+
+ log_ptr = (struct ocp_cloud_smart_log *)malloc(sizeof(__u8) * length);
+ if (!log_ptr) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (namespace_id == NVME_NSID_ALL) {
+ ret = nvme_get_nsid(fd, &namespace_id);
+ if (ret < 0)
+ namespace_id = NVME_NSID_ALL;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .lid = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
+ .nsid = namespace_id,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = length,
+ .log = log_ptr,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (fmt == JSON)
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* Verify GUID matches */
+ for (i = 0; i < 16; i++) {
+ if (scao_guid[i] != log_ptr->log_page_guid[i]) {
+ fprintf(stderr, "ERROR: WDC: Unknown GUID in C0 Log Page data\n");
+ int j;
+
+ fprintf(stderr, "ERROR: WDC: Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", scao_guid[j]);
+ fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_ptr->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ break;
+ }
+ }
+
+ if (!ret)
+ /* parse the data */
+ wdc_print_c0_cloud_attr_log(log_ptr, fmt, dev);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data\n");
+ ret = -1;
+ }
+
+ free(log_ptr);
+ return ret;
+}
+
+static int nvme_get_print_c0_eol_log(struct nvme_dev *dev,
+ int uuid_index,
+ __u32 namespace_id,
+ int fmt)
+{
+ void *log_ptr = NULL;
+ int ret;
+ __u32 length = WDC_NVME_EOL_STATUS_LOG_LEN;
+ int fd = dev_fd(dev);
+
+ log_ptr = (void *)malloc(sizeof(__u8) * length);
+ if (!log_ptr) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (namespace_id == NVME_NSID_ALL) {
+ ret = nvme_get_nsid(fd, &namespace_id);
+ if (ret < 0)
+ namespace_id = NVME_NSID_ALL;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .lid = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE,
+ .nsid = namespace_id,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = length,
+ .log = log_ptr,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (fmt == JSON)
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ wdc_print_c0_eol_log(log_ptr, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data ");
+ fprintf(stderr, "with uuid index %d\n", uuid_index);
+ ret = -1;
+ }
+
+ free(log_ptr);
+ return ret;
+}
+
static int nvme_get_ext_smart_cloud_log(int fd, __u8 **data, int uuid_index, __u32 namespace_id)
{
int ret, i;
@@ -6587,177 +6710,6 @@ static void wdc_print_ext_smart_cloud_log_json(void *data, int mask)
json_free_object(root);
}
-static void wdc_print_smart_cloud_attr_C0_normal(void *data)
-{
- __u8 *log_data = (__u8 *)data;
- uint16_t smart_log_ver = 0;
-
- printf(" SMART Cloud Attributes :-\n");
-
- printf(" Physical media units written : %s\n",
- uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PMUW])));
- printf(" Physical media units read : %s\n",
- uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PMUR])));
- printf(" Bad user nand blocks Raw : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF));
- printf(" Bad user nand blocks Normalized : %d\n",
- (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN]));
- printf(" Bad system nand blocks Raw : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF));
- printf(" Bad system nand blocks Normalized : %d\n",
- (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN]));
- printf(" XOR recovery count : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC]));
- printf(" Uncorrectable read error count : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC]));
- printf(" Soft ecc error count : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC]));
- printf(" End to end corrected errors : %"PRIu32"\n",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE]));
- printf(" End to end detected errors : %"PRIu32"\n",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC]));
- printf(" System data percent used : %d\n", (__u8)log_data[SCAO_SDPU]);
- printf(" Refresh counts : %"PRIu64"\n",
- (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC]) & 0x00FFFFFFFFFFFFFF));
- printf(" Max User data erase counts : %"PRIu32"\n",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC]));
- printf(" Min User data erase counts : %"PRIu32"\n",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC]));
- printf(" Number of Thermal throttling events : %d\n", (__u8)log_data[SCAO_NTTE]);
- printf(" Current throttling status : 0x%x\n", (__u8)log_data[SCAO_CTS]);
- printf(" PCIe correctable error count : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC]));
- printf(" Incomplete shutdowns : %"PRIu32"\n",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS]));
- printf(" Percent free blocks : %d\n", (__u8)log_data[SCAO_PFB]);
- printf(" Capacitor health : %"PRIu16"\n",
- (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH]));
- printf(" Unaligned I/O : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO]));
- printf(" Security Version Number : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
- printf(" NUSE Namespace utilization : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
- printf(" PLP start count : %s\n",
- uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PSC])));
- printf(" Endurance estimate : %s\n",
- uint128_t_to_string(le128_to_cpu(&log_data[SCAO_EEST])));
- smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]);
- printf(" Log page version : %"PRIu16"\n", smart_log_ver);
- printf(" Log page GUID : 0x");
- printf("%"PRIx64"%"PRIx64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
- if (smart_log_ver > 2) {
- printf(" Errata Version Field : %d\n",
- (__u8)log_data[SCAO_EVF]);
- printf(" Point Version Field : %"PRIu16"\n",
- (uint16_t)log_data[SCAO_PVF]);
- printf(" Minor Version Field : %"PRIu16"\n",
- (uint16_t)log_data[SCAO_MIVF]);
- printf(" Major Version Field : %d\n",
- (__u8)log_data[SCAO_MAVF]);
- printf(" NVMe Errata Version : %d\n",
- (__u8)log_data[SCAO_NEV]);
- printf(" PCIe Link Retraining Count : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC]));
- }
- if (smart_log_ver > 3) {
- printf(" Power State Change Count : %"PRIu64"\n",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
- }
- printf("\n");
-}
-
-static void wdc_print_smart_cloud_attr_C0_json(void *data)
-{
- __u8 *log_data = (__u8 *)data;
- struct json_object *root = json_create_object();
- uint16_t smart_log_ver = 0;
-
- json_object_add_value_uint128(root, "Physical media units written",
- le128_to_cpu(&log_data[SCAO_PMUW]));
- json_object_add_value_uint128(root, "Physical media units read",
- le128_to_cpu(&log_data[SCAO_PMUR]));
- json_object_add_value_uint64(root, "Bad user nand blocks - Raw",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF));
- json_object_add_value_uint(root, "Bad user nand blocks - Normalized",
- (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN]));
- json_object_add_value_uint64(root, "Bad system nand blocks - Raw",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF));
- json_object_add_value_uint(root, "Bad system nand blocks - Normalized",
- (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN]));
- json_object_add_value_uint64(root, "XOR recovery count",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC]));
- json_object_add_value_uint64(root, "Uncorrectable read error count",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC]));
- json_object_add_value_uint64(root, "Soft ecc error count",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC]));
- json_object_add_value_uint(root, "End to end corrected errors",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE]));
- json_object_add_value_uint(root, "End to end detected errors",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC]));
- json_object_add_value_uint(root, "System data percent used",
- (__u8)log_data[SCAO_SDPU]);
- json_object_add_value_uint64(root, "Refresh counts",
- (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC]) & 0x00FFFFFFFFFFFFFF));
- json_object_add_value_uint(root, "Max User data erase counts",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC]));
- json_object_add_value_uint(root, "Min User data erase counts",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC]));
- json_object_add_value_uint(root, "Number of Thermal throttling events",
- (__u8)log_data[SCAO_NTTE]);
- json_object_add_value_uint(root, "Current throttling status",
- (__u8)log_data[SCAO_CTS]);
- json_object_add_value_uint64(root, "PCIe correctable error count",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC]));
- json_object_add_value_uint(root, "Incomplete shutdowns",
- (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS]));
- json_object_add_value_uint(root, "Percent free blocks",
- (__u8)log_data[SCAO_PFB]);
- json_object_add_value_uint(root, "Capacitor health",
- (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH]));
- json_object_add_value_uint64(root, "Unaligned I/O",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO]));
- json_object_add_value_uint64(root, "Security Version Number",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
- json_object_add_value_uint64(root, "NUSE - Namespace utilization",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
- json_object_add_value_uint128(root, "PLP start count",
- le128_to_cpu(&log_data[SCAO_PSC]));
- json_object_add_value_uint128(root, "Endurance estimate",
- le128_to_cpu(&log_data[SCAO_EEST]));
- smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]);
- json_object_add_value_uint(root, "Log page version", smart_log_ver);
- char guid[40];
-
- memset((void *)guid, 0, 40);
- sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
- json_object_add_value_string(root, "Log page GUID", guid);
- if (smart_log_ver > 2) {
- json_object_add_value_uint(root, "Errata Version Field",
- (__u8)log_data[SCAO_EVF]);
- json_object_add_value_uint(root, "Point Version Field",
- (uint16_t)log_data[SCAO_PVF]);
- json_object_add_value_uint(root, "Minor Version Field",
- (uint16_t)log_data[SCAO_MIVF]);
- json_object_add_value_uint(root, "Major Version Field",
- (__u8)log_data[SCAO_MAVF]);
- json_object_add_value_uint(root, "NVMe Errata Version",
- (__u8)log_data[SCAO_NEV]);
- json_object_add_value_uint64(root, "PCIe Link Retraining Count",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC]));
- }
- if (smart_log_ver > 3) {
- json_object_add_value_uint64(root, "Power State Change Count",
- (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
- }
- json_print_object(root, NULL);
- printf("\n");
- json_free_object(root);
-}
static void wdc_print_eol_c0_normal(void *data)
{
@@ -6825,18 +6777,26 @@ static int wdc_print_ext_smart_cloud_log(void *data, int fmt)
return 0;
}
-static int wdc_print_c0_cloud_attr_log(void *data, int fmt)
+static int wdc_print_c0_cloud_attr_log(void *data,
+ int fmt,
+ struct nvme_dev *dev)
{
+ struct ocp_cloud_smart_log *log = (struct ocp_cloud_smart_log *)data;
+
if (!data) {
fprintf(stderr, "ERROR: WDC: Invalid buffer to read 0xC0 log\n");
return -1;
}
+
switch (fmt) {
+ case BINARY:
+ d_raw((unsigned char *)log, sizeof(struct ocp_cloud_smart_log));
+ break;
case NORMAL:
- wdc_print_smart_cloud_attr_C0_normal(data);
+ wdc_show_cloud_smart_log_normal(log, dev);
break;
case JSON:
- wdc_print_smart_cloud_attr_C0_json(data);
+ wdc_show_cloud_smart_log_json(log);
break;
}
return 0;
@@ -6849,6 +6809,9 @@ static int wdc_print_c0_eol_log(void *data, int fmt)
return -1;
}
switch (fmt) {
+ case BINARY:
+ d_raw((unsigned char *)data, WDC_NVME_EOL_STATUS_LOG_LEN);
+ break;
case NORMAL:
wdc_print_eol_c0_normal(data);
break;
@@ -6863,113 +6826,17 @@ static int wdc_get_c0_log_page_sn_customer_id_0x100X(struct nvme_dev *dev, int u
char *format, __u32 namespace_id, int fmt)
{
int ret;
- __u8 *data;
- int i;
if (!uuid_index) {
- data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN);
- if (!data) {
- fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
- return -1;
- }
-
- if (namespace_id == NVME_NSID_ALL) {
- ret = nvme_get_nsid(dev_fd(dev), &namespace_id);
- if (ret < 0)
- namespace_id = NVME_NSID_ALL;
- }
-
- /* Get the 0xC0 log data */
- struct nvme_get_log_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
- .lid = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
- .nsid = namespace_id,
- .lpo = 0,
- .lsp = NVME_LOG_LSP_NONE,
- .lsi = 0,
- .rae = false,
- .uuidx = uuid_index,
- .csi = NVME_CSI_NVM,
- .ot = false,
- .len = WDC_NVME_SMART_CLOUD_ATTR_LEN,
- .log = data,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .result = NULL,
- };
- ret = nvme_get_log(&args);
-
- if (strcmp(format, "json"))
- nvme_show_status(ret);
-
- if (!ret) {
- /* Verify GUID matches */
- for (i = 0; i < 16; i++) {
- if (scao_guid[i] != data[SCAO_LPG + i]) {
- fprintf(stderr, "ERROR: WDC: Unknown GUID in C0 Log Page data\n");
- int j;
-
- fprintf(stderr, "ERROR: WDC: Expected GUID: 0x");
- for (j = 0; j < 16; j++)
- fprintf(stderr, "%x", scao_guid[j]);
- fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x");
- for (j = 0; j < 16; j++)
- fprintf(stderr, "%x", data[SCAO_LPG + j]);
- fprintf(stderr, "\n");
-
- ret = -1;
- break;
- }
- }
-
- if (!ret)
- /* parse the data */
- wdc_print_c0_cloud_attr_log(data, fmt);
- } else {
- fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data\n");
- ret = -1;
- }
-
- free(data);
+ ret = nvme_get_print_ocp_cloud_smart_log(dev,
+ uuid_index,
+ namespace_id,
+ fmt);
} else if (uuid_index == 1) {
- data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_EOL_STATUS_LOG_LEN);
- if (!data) {
- fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
- return -1;
- }
-
- /* Get the 0xC0 log data */
- struct nvme_get_log_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
- .lid = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE,
- .nsid = NVME_NSID_ALL,
- .lpo = 0,
- .lsp = NVME_LOG_LSP_NONE,
- .lsi = 0,
- .rae = false,
- .uuidx = uuid_index,
- .csi = NVME_CSI_NVM,
- .ot = false,
- .len = WDC_NVME_EOL_STATUS_LOG_LEN,
- .log = data,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .result = NULL,
- };
- ret = nvme_get_log(&args);
-
- if (strcmp(format, "json"))
- nvme_show_status(ret);
-
- if (!ret) {
- /* parse the data */
- wdc_print_c0_eol_log(data, fmt);
- } else {
- fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data\n");
- ret = -1;
- }
-
- free(data);
+ ret = nvme_get_print_c0_eol_log(dev,
+ uuid_index,
+ namespace_id,
+ fmt);
} else {
fprintf(stderr, "ERROR: WDC: Unknown uuid index\n");
ret = -1;
@@ -6983,7 +6850,6 @@ static int wdc_get_c0_log_page_sn(nvme_root_t r, struct nvme_dev *dev, int uuid_
{
int ret = 0;
__u32 cust_id;
- __u8 *data;
cust_id = wdc_get_fw_cust_id(r, dev);
if (cust_id == WDC_INVALID_CUSTOMER_ID) {
@@ -6996,30 +6862,10 @@ static int wdc_get_c0_log_page_sn(nvme_root_t r, struct nvme_dev *dev, int uuid_
ret = wdc_get_c0_log_page_sn_customer_id_0x100X(dev, uuid_index, format,
namespace_id, fmt);
} else {
- data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_EOL_STATUS_LOG_LEN);
- if (!data) {
- fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
- return -1;
- }
-
- /* Get the 0xC0 log data */
- ret = nvme_get_log_simple(dev_fd(dev),
- WDC_NVME_GET_EOL_STATUS_LOG_OPCODE,
- WDC_NVME_EOL_STATUS_LOG_LEN,
- data);
-
- if (strcmp(format, "json"))
- nvme_show_status(ret);
-
- if (!ret) {
- /* parse the data */
- wdc_print_c0_eol_log(data, fmt);
- } else {
- fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data\n");
- ret = -1;
- }
-
- free(data);
+ ret = nvme_get_print_c0_eol_log(dev,
+ 0,
+ namespace_id,
+ fmt);
}
return ret;
@@ -7029,11 +6875,9 @@ static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format
__u32 namespace_id)
{
uint32_t device_id, read_vendor_id;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
int ret;
__u8 *data;
- __u8 log_id;
- __u32 length;
if (!wdc_check_device(r, dev))
return -1;
@@ -7047,123 +6891,42 @@ static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format
switch (device_id) {
case WDC_NVME_SN640_DEV_ID:
- fallthrough;
case WDC_NVME_SN640_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN640_DEV_ID_2:
- fallthrough;
case WDC_NVME_SN640_DEV_ID_3:
- fallthrough;
case WDC_NVME_SN840_DEV_ID:
- fallthrough;
case WDC_NVME_SN840_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN860_DEV_ID:
- fallthrough;
case WDC_NVME_SN560_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN560_DEV_ID_2:
- fallthrough;
case WDC_NVME_SN560_DEV_ID_3:
- fallthrough;
case WDC_NVME_SN550_DEV_ID:
ret = wdc_get_c0_log_page_sn(r, dev, uuid_index, format, namespace_id, fmt);
break;
-
case WDC_NVME_SN650_DEV_ID:
- fallthrough;
case WDC_NVME_SN650_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN650_DEV_ID_2:
- fallthrough;
case WDC_NVME_SN650_DEV_ID_3:
- fallthrough;
case WDC_NVME_SN650_DEV_ID_4:
- fallthrough;
case WDC_NVME_SN655_DEV_ID:
if (uuid_index == 0) {
- log_id = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID;
- length = WDC_NVME_SMART_CLOUD_ATTR_LEN;
- } else {
- log_id = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE;
- length = WDC_NVME_EOL_STATUS_LOG_LEN;
- }
-
- data = (__u8 *)malloc(sizeof(__u8) * length);
- if (!data) {
- fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
- return -1;
- }
-
- if (namespace_id == NVME_NSID_ALL) {
- ret = nvme_get_nsid(dev_fd(dev), &namespace_id);
- if (ret < 0)
- namespace_id = NVME_NSID_ALL;
- }
-
- /* Get the 0xC0 log data */
- struct nvme_get_log_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
- .lid = log_id,
- .nsid = namespace_id,
- .lpo = 0,
- .lsp = NVME_LOG_LSP_NONE,
- .lsi = 0,
- .rae = false,
- .uuidx = uuid_index,
- .csi = NVME_CSI_NVM,
- .ot = false,
- .len = length,
- .log = data,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .result = NULL,
- };
- ret = nvme_get_log(&args);
-
- if (strcmp(format, "json"))
- nvme_show_status(ret);
-
- if (!ret) {
- /* parse the data */
- if (uuid_index == 0)
- wdc_print_c0_cloud_attr_log(data, fmt);
- else
- wdc_print_c0_eol_log(data, fmt);
+ ret = nvme_get_print_ocp_cloud_smart_log(dev,
+ uuid_index,
+ namespace_id,
+ fmt);
} else {
- fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data ");
- fprintf(stderr, "with uuid index %d\n", uuid_index);
- ret = -1;
+ ret = nvme_get_print_c0_eol_log(dev,
+ uuid_index,
+ namespace_id,
+ fmt);
}
- free(data);
break;
-
case WDC_NVME_ZN350_DEV_ID:
- fallthrough;
case WDC_NVME_ZN350_DEV_ID_1:
- data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN);
- if (!data) {
- fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
- return -1;
- }
-
- /* Get the 0xC0 log data */
- ret = nvme_get_log_simple(dev_fd(dev),
- WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
- WDC_NVME_SMART_CLOUD_ATTR_LEN, data);
-
- if (strcmp(format, "json"))
- nvme_show_status(ret);
-
- if (!ret) {
- /* parse the data */
- wdc_print_c0_cloud_attr_log(data, fmt);
- } else {
- fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data\n");
- ret = -1;
- }
-
- free(data);
+ ret = nvme_get_print_ocp_cloud_smart_log(dev,
+ 0,
+ NVME_NSID_ALL,
+ fmt);
break;
case WDC_NVME_SN820CL_DEV_ID:
/* Get the 0xC0 Extended Smart Cloud Attribute log data */
@@ -7345,7 +7108,7 @@ static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format
{
uint32_t read_device_id, read_vendor_id;
struct wdc_ssd_ca_perf_stats *perf;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
__u32 cust_id;
__u8 *data;
int ret;
@@ -7405,17 +7168,11 @@ static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format
}
break;
case WDC_NVME_SN640_DEV_ID:
- fallthrough;
case WDC_NVME_SN640_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN640_DEV_ID_2:
- fallthrough;
case WDC_NVME_SN640_DEV_ID_3:
- fallthrough;
case WDC_NVME_SN840_DEV_ID:
- fallthrough;
case WDC_NVME_SN840_DEV_ID_1:
- fallthrough;
case WDC_NVME_SN860_DEV_ID:
if (cust_id == WDC_CUSTOMER_ID_0x1005) {
data = (__u8 *)malloc(sizeof(__u8) * WDC_FB_CA_LOG_BUF_LEN);
@@ -7482,7 +7239,7 @@ static int wdc_get_c1_log_page(nvme_root_t r, struct nvme_dev *dev,
struct wdc_log_page_subpage_header *sph;
struct wdc_ssd_perf_stats *perf;
struct wdc_log_page_header *l;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
int total_subpages;
int skip_cnt = 4;
__u8 *data;
@@ -7539,7 +7296,7 @@ static int wdc_get_c1_log_page(nvme_root_t r, struct nvme_dev *dev,
static int wdc_get_c3_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
struct wdc_ssd_latency_monitor_log *log_data;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
__u8 *data;
int ret;
int i;
@@ -7611,7 +7368,7 @@ out:
static int wdc_get_ocp_c1_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
struct wdc_ocp_c1_error_recovery_log *log_data;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
__u8 *data;
int ret;
int i;
@@ -7642,9 +7399,10 @@ static int wdc_get_ocp_c1_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo
log_data = (struct wdc_ocp_c1_error_recovery_log *)data;
/* check log page version */
- if ((log_data->log_page_version != WDC_ERROR_REC_LOG_VERSION1) &&
- (log_data->log_page_version != WDC_ERROR_REC_LOG_VERSION2)) {
- fprintf(stderr, "ERROR: WDC: invalid error recovery log version - %d\n", log_data->log_page_version);
+ if ((log_data->log_page_version < 1) ||
+ (log_data->log_page_version > 3)) {
+ fprintf(stderr, "ERROR: WDC: invalid error recovery log version - %d\n",
+ log_data->log_page_version);
ret = -1;
goto out;
}
@@ -7682,7 +7440,7 @@ out:
static int wdc_get_ocp_c4_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
struct wdc_ocp_C4_dev_cap_log *log_data;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
__u8 *data;
int ret;
int i;
@@ -7752,7 +7510,7 @@ out:
static int wdc_get_ocp_c5_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
struct wdc_ocp_C5_unsupported_reqs *log_data;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
int ret;
__u8 *data;
int i;
@@ -7822,7 +7580,7 @@ out:
static int wdc_get_d0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
{
struct wdc_ssd_d0_smart_log *perf;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
int ret = 0;
__u8 *data;
@@ -7907,7 +7665,7 @@ static const char *stringify_cloud_smart_log_thermal_status(__u8 status)
return "unrecognized";
}
-static void show_cloud_smart_log_json(struct ocp_cloud_smart_log *log)
+static void wdc_show_cloud_smart_log_json(struct ocp_cloud_smart_log *log)
{
struct json_object *root;
struct json_object *bad_user_nand_blocks;
@@ -7917,6 +7675,8 @@ static void show_cloud_smart_log_json(struct ocp_cloud_smart_log *log)
struct json_object *thermal_status;
struct json_object *dssd_specific_ver;
char buf[2 * sizeof(log->log_page_guid) + 3];
+ char lowest_fr[sizeof(log->lowest_permitted_fw_rev) + 1];
+ uint16_t smart_log_ver = (uint16_t)le16_to_cpu(log->log_page_version);
bad_user_nand_blocks = json_create_object();
json_object_add_value_uint(bad_user_nand_blocks, "normalized",
@@ -7982,7 +7742,8 @@ static void show_cloud_smart_log_json(struct ocp_cloud_smart_log *log)
json_object_add_value_object(root, "user_data_erase_counts",
user_data_erase_counts);
json_object_add_value_object(root, "thermal_status", thermal_status);
- json_object_add_value_object(root, "dssd_specific_ver",
+ if (smart_log_ver >= 3)
+ json_object_add_value_object(root, "dssd_specific_ver",
dssd_specific_ver);
json_object_add_value_uint(root, "pcie_correctable_error_count",
le64_to_cpu(log->pcie_correctable_error_count));
@@ -7992,8 +7753,18 @@ static void show_cloud_smart_log_json(struct ocp_cloud_smart_log *log)
log->percent_free_blocks);
json_object_add_value_uint(root, "capacitor_health",
le16_to_cpu(log->capacitor_health));
- sprintf(buf, "%c", log->nvme_errata_ver);
- json_object_add_value_string(root, "nvme_errata_version", buf);
+ if (smart_log_ver >= 3) {
+ if (smart_log_ver >= 4) {
+ sprintf(buf, "%c", log->nvme_base_errata_ver);
+ json_object_add_value_string(root, "nvme_base_errata_version", buf);
+ sprintf(buf, "%c", log->nvme_cmd_set_errata_ver);
+ json_object_add_value_string(root, "nvme_cmd_set_errata_version", buf);
+ } else {
+ sprintf(buf, "%c", log->nvme_base_errata_ver);
+ json_object_add_value_string(root, "nvme_errata_version", buf);
+ }
+ }
+
json_object_add_value_uint(root, "unaligned_io",
le64_to_cpu(log->unaligned_io));
json_object_add_value_uint(root, "security_version_number",
@@ -8004,12 +7775,22 @@ static void show_cloud_smart_log_json(struct ocp_cloud_smart_log *log)
le_to_float(log->plp_start_count, 16));
json_object_add_value_uint64(root, "endurance_estimate",
le_to_float(log->endurance_estimate, 16));
- json_object_add_value_uint(root, "pcie_link_retraining_count",
- le64_to_cpu(log->pcie_link_retraining_cnt));
- json_object_add_value_uint(root, "power_state_change_count",
- le64_to_cpu(log->power_state_change_cnt));
+ if (smart_log_ver >= 3) {
+ json_object_add_value_uint(root, "pcie_link_retraining_count",
+ le64_to_cpu(log->pcie_link_retraining_cnt));
+ json_object_add_value_uint(root, "power_state_change_count",
+ le64_to_cpu(log->power_state_change_cnt));
+ if (smart_log_ver >= 4) {
+ snprintf(lowest_fr, sizeof(lowest_fr), "%-.*s",
+ (int)sizeof(log->lowest_permitted_fw_rev),
+ log->lowest_permitted_fw_rev);
+ json_object_add_value_string(root, "lowest_permitted_fw_rev", lowest_fr);
+ } else
+ json_object_add_value_uint128(root, "hardware_revision",
+ le128_to_cpu((__u8 *)&log->lowest_permitted_fw_rev[0]));
+ }
json_object_add_value_uint(root, "log_page_version",
- le16_to_cpu(log->log_page_version));
+ smart_log_ver);
stringify_log_page_guid(log->log_page_guid, buf);
json_object_add_value_string(root, "log_page_guid", buf);
@@ -8018,11 +7799,13 @@ static void show_cloud_smart_log_json(struct ocp_cloud_smart_log *log)
json_free_object(root);
}
-static void show_cloud_smart_log_normal(struct ocp_cloud_smart_log *log, struct nvme_dev *dev)
+static void wdc_show_cloud_smart_log_normal(struct ocp_cloud_smart_log *log,
+ struct nvme_dev *dev)
{
char buf[2 * sizeof(log->log_page_guid) + 3];
+ uint16_t smart_log_ver = (uint16_t)le16_to_cpu(log->log_page_version);
- printf("Smart Extended Log for NVME device:%s\n", dev->name);
+ printf("SMART Cloud Attributes for NVMe device : %s\n", dev->name);
printf("Physical Media Units Written : %'.0Lf\n",
le_to_float(log->physical_media_units_written, 16));
printf("Physical Media Units Read : %'.0Lf\n",
@@ -8057,14 +7840,16 @@ static void show_cloud_smart_log_normal(struct ocp_cloud_smart_log *log, struct
stringify_cloud_smart_log_thermal_status(log->thermal_status.current_status));
printf("Thermal Throttling Status (Number of Events) : %" PRIu8 "\n",
log->thermal_status.num_events);
- printf("NVMe Major Version : %" PRIu8 "\n",
- log->dssd_specific_ver.major_ver);
- printf(" Minor Version : %" PRIu16 "\n",
- le16_to_cpu(log->dssd_specific_ver.minor_ver));
- printf(" Point Version : %" PRIu16 "\n",
- le16_to_cpu(log->dssd_specific_ver.point_ver));
- printf(" Errata Version : %" PRIu8 "\n",
- log->dssd_specific_ver.errata_ver);
+ if (smart_log_ver >= 3) {
+ printf("NVMe Major Version : %" PRIu8 "\n",
+ log->dssd_specific_ver.major_ver);
+ printf(" Minor Version : %" PRIu16 "\n",
+ le16_to_cpu(log->dssd_specific_ver.minor_ver));
+ printf(" Point Version : %" PRIu16 "\n",
+ le16_to_cpu(log->dssd_specific_ver.point_ver));
+ printf(" Errata Version : %" PRIu8 "\n",
+ log->dssd_specific_ver.errata_ver);
+ }
printf("PCIe Correctable Error Count : %" PRIu64 "\n",
le64_to_cpu(log->pcie_correctable_error_count));
printf("Incomplete Shutdowns : %" PRIu32 "\n",
@@ -8073,8 +7858,17 @@ static void show_cloud_smart_log_normal(struct ocp_cloud_smart_log *log, struct
log->percent_free_blocks);
printf("Capacitor Health : %" PRIu16 "%%\n",
le16_to_cpu(log->capacitor_health));
- printf("NVMe Errata Version : %c\n",
- log->nvme_errata_ver);
+ if (smart_log_ver >= 3) {
+ if (smart_log_ver >= 4) {
+ printf("NVMe Base Errata Version : %c\n",
+ log->nvme_base_errata_ver);
+ printf("NVMe Command Set Errata Version : %c\n",
+ log->nvme_cmd_set_errata_ver);
+ } else {
+ printf("NVMe Errata Version : %c\n",
+ log->nvme_base_errata_ver);
+ }
+ }
printf("Unaligned IO : %" PRIu64 "\n",
le64_to_cpu(log->unaligned_io));
printf("Security Version Number : %" PRIu64 "\n",
@@ -8085,12 +7879,22 @@ static void show_cloud_smart_log_normal(struct ocp_cloud_smart_log *log, struct
le_to_float(log->plp_start_count, 16));
printf("Endurance Estimate : %'.0Lf\n",
le_to_float(log->endurance_estimate, 16));
- printf("PCIe Link Retraining Count : %" PRIu64 "\n",
- le64_to_cpu(log->pcie_link_retraining_cnt));
- printf("Power State Change Count : %" PRIu64 "\n",
- le64_to_cpu(log->power_state_change_cnt));
+ if (smart_log_ver >= 3) {
+ printf("PCIe Link Retraining Count : %" PRIu64 "\n",
+ le64_to_cpu(log->pcie_link_retraining_cnt));
+ printf("Power State Change Count : %" PRIu64 "\n",
+ le64_to_cpu(log->power_state_change_cnt));
+ if (smart_log_ver >= 4)
+ printf("Lowest Permitted FW Revision : %-.*s\n",
+ (int)sizeof(log->lowest_permitted_fw_rev),
+ log->lowest_permitted_fw_rev);
+ else
+ printf("Hardware Revision : %s\n",
+ uint128_t_to_string(le128_to_cpu(
+ (__u8 *)&log->lowest_permitted_fw_rev[0])));
+ }
printf("Log Page Version : %" PRIu16 "\n",
- le16_to_cpu(log->log_page_version));
+ smart_log_ver);
stringify_log_page_guid(log->log_page_guid, buf);
printf("Log Page GUID : %s\n", buf);
printf("\n\n");
@@ -8104,7 +7908,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
const char *log_page_version = "Log Page Version: 0 = vendor, 1 = WDC";
const char *log_page_mask = "Log Page Mask, comma separated list: 0xC0, 0xC1, 0xCA, 0xD0";
const char *namespace_id = "desired namespace id";
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
struct nvme_dev *dev;
nvme_root_t r;
int ret = 0;
@@ -8200,43 +8004,16 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
"ERROR: WDC: Failure reading the C0 Log Page, ret = %d\n",
ret);
} else {
- struct ocp_cloud_smart_log log;
- char buf[2 * sizeof(log.log_page_guid) + 3];
-
ret = validate_output_format(cfg.output_format, &fmt);
if (ret < 0) {
fprintf(stderr, "Invalid output format: %s\n", cfg.output_format);
goto out;
}
- ret = nvme_get_log_simple(dev_fd(dev),
- WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
- sizeof(log), &log);
- if (!ret) {
- char *ptr = buf;
- int i;
- __u8 *guid = log.log_page_guid;
-
- memset(buf, 0, sizeof(char) * 19);
-
- ptr += sprintf(ptr, "0x");
- for (i = 0; i < 16; i++)
- ptr += sprintf(ptr, "%x", guid[15 - i]);
- if (strcmp(buf, "0xafd514c97c6f4f9ca4f2bfea2810afc5"))
- fprintf(stderr, "Invalid GUID: %s\n", buf);
- else {
- if (fmt == BINARY)
- d_raw((unsigned char *)&log, sizeof(log));
- else if (fmt == JSON)
- show_cloud_smart_log_json(&log);
- else
- show_cloud_smart_log_normal(&log, dev);
- }
- } else if (ret > 0) {
- nvme_show_status(ret);
- } else {
- perror("vs-smart-add-log");
- }
+ ret = nvme_get_print_ocp_cloud_smart_log(dev,
+ 0,
+ NVME_NSID_ALL,
+ fmt);
}
}
if (((capabilities & (WDC_DRIVE_CAP_CA_LOG_PAGE)) == (WDC_DRIVE_CAP_CA_LOG_PAGE)) &&
@@ -8274,7 +8051,7 @@ static int wdc_vs_cloud_log(int argc, char **argv, struct command *command,
{
const char *desc = "Retrieve Cloud Log Smart/Health Information";
const char *namespace_id = "desired namespace id";
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
__u64 capabilities = 0;
struct nvme_dev *dev;
nvme_root_t r;
@@ -8345,7 +8122,7 @@ static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command,
{
const char *desc = "Retrieve Hardware Revision Log Information";
const char *namespace_id = "desired namespace id";
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
__u64 capabilities = 0;
struct nvme_dev *dev;
int ret;
@@ -8430,7 +8207,7 @@ static int wdc_vs_device_waf(int argc, char **argv, struct command *command,
const char *desc = "Retrieve Device Write Amplication Factor";
const char *namespace_id = "desired namespace id";
struct nvme_smart_log smart_log;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
struct nvme_dev *dev;
__u8 *data;
nvme_root_t r;
@@ -8987,7 +8764,7 @@ static int wdc_get_fw_act_history(nvme_root_t r, struct nvme_dev *dev,
char *format)
{
struct wdc_fw_act_history_log_hdr *fw_act_history_hdr;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
int ret;
__u8 *data;
@@ -9071,9 +8848,10 @@ static int wdc_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev,
__u32 tot_entries = 0, num_entries = 0;
__u32 vendor_id = 0, device_id = 0;
__u32 cust_id = 0;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
__u8 *data;
int ret;
+ bool c2GuidMatch = false;
if (!wdc_check_device(r, dev))
return -1;
@@ -9102,29 +8880,40 @@ static int wdc_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev,
nvme_show_status(ret);
if (!ret) {
- /* parse the data */
+ /* Get the log page data and verify the GUID */
fw_act_history_log = (struct wdc_fw_act_history_log_format_c2 *)(data);
- tot_entries = le32_to_cpu(fw_act_history_log->num_entries);
- if (tot_entries > 0) {
- /* get the FW customer id */
- if (!wdc_is_sn861(device_id)) {
- cust_id = wdc_get_fw_cust_id(r, dev);
- if (cust_id == WDC_INVALID_CUSTOMER_ID) {
- fprintf(stderr,
- "%s: ERROR: WDC: invalid customer id\n",
- __func__);
- ret = -1;
- goto freeData;
+ c2GuidMatch = !memcmp(ocp_C2_guid,
+ fw_act_history_log->log_page_guid,
+ WDC_C2_GUID_LENGTH);
+
+ if (c2GuidMatch) {
+ /* parse the data */
+ tot_entries = le32_to_cpu(fw_act_history_log->num_entries);
+
+ if (tot_entries > 0) {
+ /* get the FW customer id */
+ if (!wdc_is_sn861(device_id)) {
+ cust_id = wdc_get_fw_cust_id(r, dev);
+ if (cust_id == WDC_INVALID_CUSTOMER_ID) {
+ fprintf(stderr,
+ "%s: ERROR: WDC: invalid customer id\n",
+ __func__);
+ ret = -1;
+ goto freeData;
+ }
}
+ num_entries = (tot_entries < WDC_MAX_NUM_ACT_HIST_ENTRIES) ?
+ tot_entries : WDC_MAX_NUM_ACT_HIST_ENTRIES;
+ ret = wdc_print_fw_act_history_log(data, num_entries,
+ fmt, cust_id, vendor_id, device_id);
+ } else {
+ fprintf(stderr, "INFO: WDC: No entries found.\n");
+ ret = 0;
}
- num_entries = (tot_entries < WDC_MAX_NUM_ACT_HIST_ENTRIES) ? tot_entries :
- WDC_MAX_NUM_ACT_HIST_ENTRIES;
- ret = wdc_print_fw_act_history_log(data, num_entries,
- fmt, cust_id, vendor_id, device_id);
- } else {
- fprintf(stderr, "INFO: WDC: No FW Activate History entries found.\n");
- ret = 0;
+ } else {
+ fprintf(stderr, "ERROR: WDC: Invalid C2 log page GUID\n");
+ ret = -1;
}
} else {
fprintf(stderr, "ERROR: WDC: Unable to read FW Activate History Log Page data\n");
@@ -9143,7 +8932,7 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com
__u64 capabilities = 0;
struct nvme_dev *dev;
nvme_root_t r;
- int ret;
+ int ret = -1;
struct config {
char *output_format;
@@ -9171,61 +8960,23 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com
}
if (capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY) {
- int uuid_index = 0;
- bool c0GuidMatch = false;
- __u8 *data;
- int i;
-
- /*
- * check for the GUID in the 0xC0 log page to determine which log page to use to
- * retrieve fw activate history data
- */
- data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN);
- if (!data) {
- fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ __u32 cust_fw_id = 0;
+ /* get the FW customer id */
+ cust_fw_id = wdc_get_fw_cust_id(r, dev);
+ if (cust_fw_id == WDC_INVALID_CUSTOMER_ID) {
+ fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__);
ret = -1;
goto out;
}
- /* Get the 0xC0 log data */
- struct nvme_get_log_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
- .lid = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
- .nsid = 0xFFFFFFFF,
- .lpo = 0,
- .lsp = NVME_LOG_LSP_NONE,
- .lsi = 0,
- .rae = false,
- .uuidx = uuid_index,
- .csi = NVME_CSI_NVM,
- .ot = false,
- .len = WDC_NVME_SMART_CLOUD_ATTR_LEN,
- .log = data,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .result = NULL,
- };
- ret = nvme_get_log(&args);
-
- if (!ret) {
- /* Verify GUID matches */
- for (i = 0; i < 16; i++) {
- if (scao_guid[i] != data[SCAO_LPG + i]) {
- c0GuidMatch = false;
- break;
- }
- }
-
- if (i == 16)
- c0GuidMatch = true;
- }
-
- free(data);
- if (c0GuidMatch)
+ if ((cust_fw_id == WDC_CUSTOMER_ID_0x1004) ||
+ (cust_fw_id == WDC_CUSTOMER_ID_0x1008) ||
+ (cust_fw_id == WDC_CUSTOMER_ID_0x1005) ||
+ (cust_fw_id == WDC_CUSTOMER_ID_0x1304))
ret = wdc_get_fw_act_history_C2(r, dev, cfg.output_format);
else
ret = wdc_get_fw_act_history(r, dev, cfg.output_format);
- } else {
+ } else if (capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2) {
ret = wdc_get_fw_act_history_C2(r, dev, cfg.output_format);
}
@@ -9648,10 +9399,10 @@ static int wdc_fetch_log_file_from_device(struct nvme_dev *dev, __u32 fileId,
__u16 spiDestn, __u64 fileSize, __u8 *dataBuffer)
{
int ret = WDC_STATUS_FAILURE;
- __u32 chunckSize = WDC_DE_VU_READ_BUFFER_STANDARD_OFFSET;
- __u32 maximumTransferLength = 0;
- __u32 buffSize = 0;
- __u64 offsetIdx = 0;
+ __u32 chunckSize = WDC_DE_VU_READ_BUFFER_STANDARD_OFFSET;
+ __u32 maximumTransferLength = 0;
+ __u32 buffSize = 0;
+ __u64 offsetIdx = 0;
if (!dev || !dataBuffer || !fileSize) {
ret = WDC_STATUS_INVALID_PARAMETER;
@@ -9699,18 +9450,17 @@ end:
static int wdc_de_get_dump_trace(struct nvme_dev *dev, char *filePath, __u16 binFileNameLen, char *binFileName)
{
- int ret = WDC_STATUS_FAILURE;
- __u8 *readBuffer = NULL;
- __u32 readBufferLen = 0;
- __u32 lastPktReadBufferLen = 0;
- __u32 maxTransferLen = 0;
- __u32 dumptraceSize = 0;
- __u32 chunkSize = 0;
- __u32 chunks = 0;
- __u32 offset = 0;
- __u8 loop = 0;
- __u16 i = 0;
- __u32 maximumTransferLength = 0;
+ int ret = WDC_STATUS_FAILURE;
+ __u8 *readBuffer = NULL;
+ __u32 readBufferLen = 0;
+ __u32 lastPktReadBufferLen = 0;
+ __u32 maxTransferLen = 0;
+ __u32 dumptraceSize = 0;
+ __u32 chunkSize;
+ __u32 chunks;
+ __u32 offset;
+ __u32 i;
+ __u32 maximumTransferLength = 0;
if (!dev || !binFileName || !filePath) {
ret = WDC_STATUS_INVALID_PARAMETER;
@@ -9759,7 +9509,7 @@ static int wdc_de_get_dump_trace(struct nvme_dev *dev, char *filePath, __u16 bin
}
for (i = 0; i < chunks; i++) {
- offset = ((i*chunkSize) / 4);
+ offset = (i * chunkSize) / 4;
/* Last loop call, Assign readBufferLen to read only left over bytes */
if (i == (chunks - 1))
@@ -9774,7 +9524,7 @@ static int wdc_de_get_dump_trace(struct nvme_dev *dev, char *filePath, __u16 bin
break;
}
}
- } while (loop);
+ } while (0);
if (ret == WDC_STATUS_SUCCESS) {
ret = wdc_WriteToFile(binFileName, (char *)readBuffer, dumptraceSize);
@@ -10580,7 +10330,7 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command
struct plugin *plugin)
{
const char *desc = "Retrieve Log Page Directory.";
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
struct nvme_dev *dev;
int ret = 0;
nvme_root_t r;
@@ -11240,7 +10990,7 @@ static void wdc_print_pcie_stats_json(struct wdc_vs_pcie_stats *pcie_stats)
static int wdc_do_vs_nand_stats_sn810_2(struct nvme_dev *dev, char *format)
{
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
uint8_t *data = NULL;
int ret;
@@ -11279,7 +11029,7 @@ out:
static int wdc_do_vs_nand_stats(struct nvme_dev *dev, char *format)
{
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
uint8_t *output = NULL;
__u16 version = 0;
int ret;
@@ -11403,7 +11153,7 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
const char *desc = "Retrieve PCIE statistics.";
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
struct nvme_dev *dev;
nvme_root_t r;
int ret;
@@ -11478,7 +11228,7 @@ static int wdc_vs_drive_info(int argc, char **argv,
struct command *command, struct plugin *plugin)
{
const char *desc = "Send a vs-drive-info command.";
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
nvme_root_t r;
uint64_t capabilities = 0;
struct nvme_dev *dev;
@@ -11678,7 +11428,6 @@ static int wdc_vs_drive_info(int argc, char **argv,
break;
case WDC_NVME_SN861_DEV_ID:
- fallthrough;
case WDC_NVME_SN861_DEV_ID_1:
data_len = sizeof(info);
num_dwords = data_len / 4;
@@ -11746,7 +11495,7 @@ static int wdc_vs_temperature_stats(int argc, char **argv,
const char *desc = "Send a vs-temperature-stats command.";
struct nvme_smart_log smart_log;
struct nvme_id_ctrl id_ctrl;
- enum nvme_print_flags fmt;
+ nvme_print_flags_t fmt;
struct nvme_dev *dev;
nvme_root_t r;
uint64_t capabilities = 0;
diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h
index d3692bc..a18da16 100644
--- a/plugins/wdc/wdc-nvme.h
+++ b/plugins/wdc/wdc-nvme.h
@@ -5,7 +5,7 @@
#if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ)
#define WDC_NVME
-#define WDC_PLUGIN_VERSION "2.7.0"
+#define WDC_PLUGIN_VERSION "2.9.1"
#include "cmd.h"
PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION),
diff --git a/plugins/wdc/wdc-utils.c b/plugins/wdc/wdc-utils.c
index 414a06a..1b52e7c 100644
--- a/plugins/wdc/wdc-utils.c
+++ b/plugins/wdc/wdc-utils.c
@@ -192,5 +192,5 @@ bool wdc_CheckUuidListSupport(struct nvme_dev *dev, struct nvme_id_uuid_list *uu
bool wdc_UuidEqual(struct nvme_id_uuid_list_entry *entry1, struct nvme_id_uuid_list_entry *entry2)
{
- return !memcmp(entry1, entry2, NVME_UUID_LEN);
+ return !memcmp(entry1->uuid, entry2->uuid, NVME_UUID_LEN);
}
diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c
index a7a3766..94336d7 100644
--- a/plugins/zns/zns.c
+++ b/plugins/zns/zns.c
@@ -114,7 +114,7 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
"the given device and report information about the specified\n"
"controller in various formats.";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_zns_id_ctrl ctrl;
struct nvme_dev *dev;
int err = -1;
@@ -160,7 +160,7 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
const char *vendor_specific = "dump binary vendor fields";
const char *human_readable = "show identify in readable format";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_zns_id_ns ns;
struct nvme_id_ns id_ns;
struct nvme_dev *dev;
@@ -732,7 +732,7 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu
const char *partial = "Zone Receive Action Specific Features(Partial Report)";
const char *data_len = "length of data in bytes";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_dev *dev;
void *data = NULL;
int err = -1;
@@ -830,7 +830,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
const char *part = "set to use the partial report";
const char *verbose = "show report zones verbosity";
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
int zdes = 0, err = -1;
struct nvme_dev *dev;
__u32 report_size;
@@ -1222,7 +1222,7 @@ static int changed_zone_list(int argc, char **argv, struct command *cmd, struct
const char *rae = "retain an asynchronous event";
struct nvme_zns_changed_zone_log log;
- enum nvme_print_flags flags;
+ nvme_print_flags_t flags;
struct nvme_dev *dev;
int err = -1;