summaryrefslogtreecommitdiffstats
path: root/plugins/memblaze/memblaze-nvme.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/memblaze/memblaze-nvme.c')
-rw-r--r--plugins/memblaze/memblaze-nvme.c781
1 files changed, 586 insertions, 195 deletions
diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c
index c75f49c..d330835 100644
--- a/plugins/memblaze/memblaze-nvme.c
+++ b/plugins/memblaze/memblaze-nvme.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <time.h>
#include "linux/nvme_ioctl.h"
@@ -19,9 +20,23 @@
#include "memblaze-utils.h"
enum {
- MB_FEAT_POWER_MGMT = 0xc6,
+ // feature id
+ MB_FEAT_POWER_MGMT = 0x02,
+ MB_FEAT_HIGH_LATENCY = 0xE1,
+ // log id
+ GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM = 0xC1,
+ GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM = 0xC2,
+ GLP_ID_VU_GET_HIGH_LATENCY_LOG = 0xC3,
+ MB_FEAT_CLEAR_ERRORLOG = 0xF7,
};
+#define LOG_PAGE_SIZE (0x1000)
+#define DO_PRINT_FLAG (1)
+#define NOT_PRINT_FLAG (0)
+#define FID_C1_LOG_FILENAME "log_c1.csv"
+#define FID_C2_LOG_FILENAME "log_c2.csv"
+#define FID_C3_LOG_FILENAME "log_c3.csv"
+
/*
* Return -1 if @fw1 < @fw2
* Return 0 if @fw1 == @fw2
@@ -53,18 +68,26 @@ static int compare_fw_version(const char *fw1, const char *fw2)
#define MEMBLAZE_FORMAT (0)
#define INTEL_FORMAT (1)
-// 2.83 = raisin
-#define IS_RAISIN(str) (!strcmp(str, "2.83"))
// 2.13 = papaya
#define IS_PAPAYA(str) (!strcmp(str, "2.13"))
-#define STR_VER_SIZE 5
+// 2.83 = raisin
+#define IS_RAISIN(str) (!strcmp(str, "2.83"))
+// 2.94 = kumquat
+#define IS_KUMQUAT(str) (!strcmp(str, "2.94"))
+// 0.60 = loquat
+#define IS_LOQUAT(str) (!strcmp(str, "0.60"))
+
+#define STR_VER_SIZE (5)
int getlogpage_format_type(char *fw_ver)
{
char fw_ver_local[STR_VER_SIZE];
strncpy(fw_ver_local, fw_ver, STR_VER_SIZE);
*(fw_ver_local + STR_VER_SIZE - 1) = '\0';
- if ( IS_RAISIN(fw_ver_local) )
+ if ( IS_RAISIN(fw_ver_local)
+ || IS_KUMQUAT(fw_ver_local)
+ || IS_LOQUAT(fw_ver_local)
+ )
{
return INTEL_FORMAT;
}
@@ -128,7 +151,7 @@ static __u64 raw_2_u64(const __u8 *buf, size_t len)
#define STR17_04 ", min: "
#define STR17_05 ", curr: "
#define STR18_01 "power_loss_protection"
-#define STR19_01 "read_fail"
+#define STR19_01 "read_fail_count"
#define STR20_01 "thermal_throttle_time"
#define STR21_01 "flash_media_error"
@@ -380,7 +403,42 @@ static int show_memblaze_smart_log(int fd, __u32 nsid, const char *devname,
return err;
}
-static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+int parse_params(char *str, int number, ...)
+{
+ va_list argp;
+ int *param;
+ char *c;
+ int value;
+
+ va_start(argp, number);
+
+ while (number > 0) {
+ c = strtok(str, ",");
+ if ( c == NULL) {
+ printf("No enough parameters. abort...\n");
+ exit(EINVAL);
+ }
+
+ if (isalnum(*c) == 0) {
+ printf("%s is not a valid number\n", c);
+ return 1;
+ }
+ value = atoi(c);
+ param = va_arg(argp, int *);
+ *param = value;
+
+ if (str) {
+ str = strchr(str, ',');
+ if (str) { str++; }
+ }
+ number--;
+ }
+ va_end(argp);
+
+ return 0;
+}
+
+static int mb_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
struct nvme_memblaze_smart_log smart_log;
int err, fd;
@@ -408,7 +466,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
return fd;
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
- sizeof(smart_log), &smart_log);
+ NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log);
if (!err) {
if (!cfg.raw_binary)
err = show_memblaze_smart_log(fd, cfg.namespace_id, devicename, &smart_log);
@@ -423,213 +481,262 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
static char *mb_feature_to_string(int feature)
{
- switch (feature) {
- case MB_FEAT_POWER_MGMT: return "Memblaze power management";
- default: return "Unknown";
- }
+ switch (feature) {
+ case MB_FEAT_POWER_MGMT: return "Memblaze power management";
+ case MB_FEAT_HIGH_LATENCY: return "Memblaze high latency log";
+ case MB_FEAT_CLEAR_ERRORLOG: return "Memblaze clear error log";
+ default: return "Unknown";
+ }
}
-static int get_additional_feature(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 = "Read operating parameters of the "\
- "specified controller. Operating parameters are grouped "\
- "and identified by Feature Identifiers; each Feature "\
- "Identifier contains one or more attributes that may affect "\
- "behaviour of the feature. Each Feature has three possible "\
- "settings: default, saveable, and current. If a Feature is "\
- "saveable, it may be modified by set-feature. Default values "\
- "are vendor-specific and not changeable. Use set-feature to "\
- "change saveable Features.\n\n"\
- "Available additional feature id:\n"\
- "0xc6: Memblaze power management\n"\
- " (value 0 - 25w, 1 - 20w, 2 - 15w)";
- const char *raw = "show feature in binary format";
- const char *namespace_id = "identifier of desired namespace";
- const char *feature_id = "hexadecimal feature name";
- const char *sel = "[0-3]: curr./default/saved/supp.";
- const char *data_len = "buffer len (if) data is returned";
- const char *cdw11 = "dword 11 for interrupt vector config";
- const char *human_readable = "show infos in readable format";
- int err, fd;
- __u32 result;
- void *buf = NULL;
-
- struct config {
- __u32 namespace_id;
- __u32 feature_id;
- __u8 sel;
- __u32 cdw11;
- __u32 data_len;
- int raw_binary;
- int human_readable;
- };
+ const char *desc = "Get Memblaze power management ststus\n (value 0 - 25w, 1 - 20w, 2 - 15w)";
+ int err, fd;
+ __u32 result;
+ __u32 feature_id = MB_FEAT_POWER_MGMT;
- struct config cfg = {
- .namespace_id = 1,
- .feature_id = 0,
- .sel = 0,
- .cdw11 = 0,
- .data_len = 0,
- };
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
- OPT_ARGS(opts) = {
- OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
- OPT_BYTE("sel", 's', &cfg.sel, sel),
- OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
- OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
- OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
- OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
- OPT_END()
- };
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) return fd;
- fd = parse_and_open(argc, argv, desc, opts);
- if (fd < 0)
- return fd;
+ err = nvme_get_feature(fd, 0, feature_id, 0, 0, 0, NULL, &result);
+ if (err < 0) {
+ perror("get-feature");
+ }
+ if (!err) {
+ printf("get-feature:0x%02x (%s), %s value: %#08x\n", feature_id,
+ mb_feature_to_string(feature_id),
+ nvme_select_to_string(0), result);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+ return err;
+}
- if (cfg.sel > 7) {
- fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
- return EINVAL;
- }
- if (!cfg.feature_id) {
- fprintf(stderr, "feature-id required param\n");
- return EINVAL;
- }
- if (cfg.data_len) {
- if (posix_memalign(&buf, getpagesize(), cfg.data_len))
- exit(ENOMEM);
- memset(buf, 0, cfg.data_len);
- }
+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";
+ int err, fd;
+ __u32 result;
+
+ struct config {
+ __u32 feature_id;
+ __u32 value;
+ int save;
+ };
+
+ struct config cfg = {
+ .feature_id = MB_FEAT_POWER_MGMT,
+ .value = 0,
+ .save = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("value", 'v', &cfg.value, value),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) return fd;
+
+ err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, NULL, &result);
+ 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);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
- err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11,
- cfg.data_len, buf, &result);
- if (!err) {
- printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id,
- mb_feature_to_string(cfg.feature_id),
- nvme_select_to_string(cfg.sel), result);
- if (cfg.human_readable)
- nvme_feature_show_fields(cfg.feature_id, result, buf);
- else {
- if (buf) {
- if (!cfg.raw_binary)
- d(buf, cfg.data_len, 16, 1);
- else
- d_raw(buf, cfg.data_len);
- }
- }
- } else if (err > 0)
- fprintf(stderr, "NVMe Status:%s(%x)\n",
- nvme_status_to_string(err), err);
- if (buf)
- free(buf);
- return err;
+ return err;
}
-static int set_additional_feature(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 = "Modify the saveable or changeable "\
- "current operating parameters of the controller. Operating "\
- "parameters are grouped and identified by Feature "\
- "Identifiers. Feature settings can be applied to the entire "\
- "controller and all associated namespaces, or to only a few "\
- "namespace(s) associated with the controller. Default values "\
- "for each Feature are vendor-specific and may not be modified."\
- "Use get-feature to determine which Features are supported by "\
- "the controller and are saveable/changeable.\n\n"\
- "Available additional feature id:\n"\
- "0xc6: Memblaze power management\n"\
- " (value 0 - 25w, 1 - 20w, 2 - 15w)";
- const char *namespace_id = "desired namespace";
- const char *feature_id = "hex feature name (required)";
- const char *data_len = "buffer length if data required";
- const char *data = "optional file for feature data (default stdin)";
- const char *value = "new value of feature (required)";
- const char *save = "specifies that the controller shall save the attribute";
- int err, fd;
- __u32 result;
- void *buf = NULL;
- int ffd = STDIN_FILENO;
+ const char *desc = "Set Memblaze high latency log\n"\
+ " input parameter p1,p2\n"\
+ " p1 value: 0 is disable, 1 is enable\n"\
+ " p2 value: 1 .. 5000 ms";
+ const char *param = "input parameters";
+ int err, fd;
+ __u32 result;
+ int param1 = 0, param2 = 0;
+
+ struct config {
+ __u32 feature_id;
+ char * param;
+ __u32 value;
+ };
+
+ struct config cfg = {
+ .feature_id = MB_FEAT_HIGH_LATENCY,
+ .param = "0,0",
+ .value = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_LIST("param", 'p', &cfg.param, param),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) return fd;
+
+ if (parse_params(cfg.param, 2, &param1, &param2)) {
+ printf("setfeature: invalid formats %s\n", cfg.param);
+ exit(EINVAL);
+ }
+ if ((param1 == 1) && (param2 < P2MIN || param2 > P2MAX)) {
+ printf("setfeature: invalid high io latency threshold %d\n", param2);
+ exit(EINVAL);
+ }
+ cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2;
- struct config {
- char *file;
- __u32 namespace_id;
- __u32 feature_id;
- __u32 value;
- __u32 data_len;
- int save;
- };
+ err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, 0, 0, NULL, &result);
+ if (err < 0) {
+ perror("set-feature");
+ }
+ if (!err) {
+ printf("set-feature:0x%02X (%s), value:%#08x\n", cfg.feature_id,
+ mb_feature_to_string(cfg.feature_id), cfg.value);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
- struct config cfg = {
- .file = "",
- .namespace_id = 0,
- .feature_id = 0,
- .value = 0,
- .data_len = 0,
- .save = 0,
- };
+ return err;
+}
- OPT_ARGS(opts) = {
- OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
- OPT_UINT("value", 'v', &cfg.value, value),
- OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
- OPT_FILE("data", 'd', &cfg.file, data),
- OPT_FLAG("save", 's', &cfg.save, save),
- OPT_END()
- };
+static int glp_high_latency_show_bar(FILE *fdi, int print)
+{
+ fPRINT_PARAM1("Memblaze High Latency Log\n");
+ fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n");
+ fPRINT_PARAM1("Timestamp Type QID CID NSID StartLBA NumLBA Latency\n");
+ fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n");
+ return 0;
+}
- fd = parse_and_open(argc, argv, desc, opts);
- if (fd < 0)
- return fd;
+/* High latency log page definiton
+ * Total 32 bytes
+ */
+typedef struct
+{
+ __u8 port;
+ __u8 revision;
+ __u16 rsvd;
+ __u8 opcode;
+ __u8 sqe;
+ __u16 cid;
+ __u32 nsid;
+ __u32 latency;
+ __u64 sLBA;
+ __u16 numLBA;
+ __u16 timestampH;
+ __u32 timestampL;
+} log_page_high_latency_t; /* total 32 bytes */
+
+static int find_deadbeef(char *buf)
+{
+ if (((*(buf + 0) & 0xff) == 0xef) && ((*(buf + 1) & 0xff) == 0xbe) && \
+ ((*(buf + 2) & 0xff) == 0xad) && ((*(buf + 3) & 0xff) == 0xde))
+ {
+ return 1;
+ }
+ return 0;
+}
- if (!cfg.feature_id) {
- fprintf(stderr, "feature-id required param\n");
- return EINVAL;
- }
+#define TIME_STR_SIZE (44)
+static int glp_high_latency(FILE *fdi, char *buf, int buflen, int print)
+{
+ log_page_high_latency_t *logEntry;
+ char string[TIME_STR_SIZE];
+ int i, entrySize;
+ __u64 timestamp;
+ time_t tt = 0;
+ struct tm *t = NULL;
+ int millisec = 0;
+
+ if (find_deadbeef(buf)) return 0;
+
+ entrySize = sizeof(log_page_high_latency_t);
+ for (i = 0; i < buflen; i += entrySize)
+ {
+ logEntry = (log_page_high_latency_t *)(buf + i);
- if (cfg.data_len) {
- if (posix_memalign(&buf, getpagesize(), cfg.data_len))
- exit(ENOMEM);
- memset(buf, 0, cfg.data_len);
- }
+ if (logEntry->latency == 0 && logEntry->revision == 0)
+ {
+ return 1;
+ }
+
+ if (0 == logEntry->timestampH) // generate host time string
+ {
+ snprintf(string, sizeof(string), "%d", logEntry->timestampL);
+ }
+ else // sort
+ {
+ timestamp = logEntry->timestampH - 1;
+ timestamp = timestamp << 32;
+ timestamp += logEntry->timestampL;
+ tt = timestamp / 1000;
+ millisec = timestamp % 1000;
+ t = gmtime(&tt);
+ snprintf(string, sizeof(string), "%4d%02d%02d--%02d:%02d:%02d.%03d UTC",
+ 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, millisec);
+ }
+
+ fprintf(fdi, "%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n",
+ string, logEntry->opcode, logEntry->sqe, logEntry->cid, logEntry->nsid,
+ (__u32)(logEntry->sLBA >> 32), (__u32)logEntry->sLBA, logEntry->numLBA, logEntry->latency);
+ if (print)
+ {
+ printf("%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n",
+ string, logEntry->opcode, logEntry->sqe, logEntry->cid, logEntry->nsid,
+ (__u32)(logEntry->sLBA >> 32), (__u32)logEntry->sLBA, logEntry->numLBA, logEntry->latency);
+ }
+ }
+ return 1;
+}
- if (buf) {
- if (strlen(cfg.file)) {
- ffd = open(cfg.file, O_RDONLY);
- if (ffd <= 0) {
- fprintf(stderr, "no firmware file provided\n");
- err = EINVAL;
- goto free;
- }
- }
- if (read(ffd, (void *)buf, cfg.data_len) < 0) {
- fprintf(stderr, "failed to read data buffer from input file\n");
- err = EINVAL;
- goto free;
- }
- }
+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";
+ int err, fd;
+ char buf[LOG_PAGE_SIZE];
+ FILE *fdi = NULL;
+
+ fdi = fopen(FID_C3_LOG_FILENAME, "w+");
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) return fd;
+
+ glp_high_latency_show_bar(fdi, DO_PRINT_FLAG);
+ err = nvme_get_log(fd, NVME_NSID_ALL, GLP_ID_VU_GET_HIGH_LATENCY_LOG, 0, NVME_NO_LOG_LSP, sizeof(buf), &buf);
+
+ while ( 1) {
+ if (!glp_high_latency(fdi, buf, LOG_PAGE_SIZE, DO_PRINT_FLAG)) break;
+ err = nvme_get_log(fd, NVME_NSID_ALL, GLP_ID_VU_GET_HIGH_LATENCY_LOG, 0, NVME_NO_LOG_LSP, sizeof(buf), &buf);
+ if ( err) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+ break;
+ }
+ }
- err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
- 0, cfg.save, cfg.data_len, buf, &result);
- if (err < 0) {
- perror("set-feature");
- goto free;
- }
- if (!err) {
- printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
- mb_feature_to_string(cfg.feature_id), cfg.value);
- if (buf)
- d(buf, cfg.data_len, 16, 1);
- } else if (err > 0)
- fprintf(stderr, "NVMe Status:%s(%x)\n",
- nvme_status_to_string(err), err);
-
-free:
- if (buf)
- free(buf);
- return err;
+ if (NULL != fdi) fclose(fdi);
+ return err;
}
+
static int memblaze_fw_commit(int fd, int select)
{
struct nvme_admin_cmd cmd = {
@@ -641,7 +748,7 @@ static int memblaze_fw_commit(int fd, int select)
return nvme_submit_admin_passthru(fd, &cmd);
}
-static int memblaze_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int mb_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc =
"This performs a selective firmware download, which allows the user to "
@@ -757,3 +864,287 @@ out:
return err;
}
+static void ioLatencyHistogramOutput(FILE *fd, int index, int start, int end, char *unit0,
+ char *unit1, unsigned int *pHistogram, int print)
+{
+ int len;
+ char string[64], subString0[12], subString1[12];
+
+ len = snprintf(subString0, sizeof(subString0), "%d%s", start, unit0);
+ if (end != 0x7FFFFFFF)
+ {
+ len = snprintf(subString1, sizeof(subString1), "%d%s", end, unit1);
+ }
+ else
+ {
+ len = snprintf(subString1, sizeof(subString1), "%s", "+INF");
+ }
+ len = snprintf(string, sizeof(string), "%-11d %-11s %-11s %-11u\n", index, subString0, subString1,
+ pHistogram[index]);
+ fwrite(string, 1, len, fd);
+ if (print)
+ {
+ printf("%s", string);
+ }
+}
+
+int io_latency_histogram(char *file, char *buf, int print, int logid)
+{
+ FILE *fdi = fopen(file, "w+");
+ int i, index;
+ char unit[2][3];
+ unsigned int *revision = (unsigned int *)buf;
+
+ if (logid == GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM)
+ {
+ fPRINT_PARAM1("Memblaze IO Read Command Latency Histogram\n");
+ }
+ else if (logid == GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM)
+ {
+ fPRINT_PARAM1("Memblaze IO Write Command Latency Histogram\n");
+ }
+ fPRINT_PARAM2("Major Revision : %d\n", revision[1]);
+ fPRINT_PARAM2("Minor Revision : %d\n", revision[0]);
+ buf += 8;
+
+ if (revision[1] == 1 && revision[0] == 0)
+ {
+ fPRINT_PARAM1("--------------------------------------------------\n");
+ fPRINT_PARAM1("Bucket Start End Value \n");
+ fPRINT_PARAM1("--------------------------------------------------\n");
+ index = 0;
+ strcpy(unit[0], "us");
+ strcpy(unit[1], "us");
+ for (i = 0; i < 32; i++, index++)
+ {
+ if (i == 31)
+ {
+ strcpy(unit[1], "ms");
+ ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], (unsigned int *)buf, print);
+ }
+ else
+ {
+ ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], unit[1], (unsigned int *)buf,
+ print);
+ }
+ }
+
+ 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);
+ }
+
+ for (i = 1; i < 32; i++, index++)
+ {
+ if (i == 31)
+ {
+ strcpy(unit[1], "s");
+ ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], (unsigned int *)buf, print);
+ }
+ else
+ {
+ ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], unit[1], (unsigned int *)buf,
+ print);
+ }
+ }
+
+ 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, 0x7FFFFFFF, unit[0], unit[1], (unsigned int *)buf, print);
+ }
+ else
+ {
+ fPRINT_PARAM1("Unsupported io latency histogram revision\n");
+ }
+
+ fclose(fdi);
+ return 1;
+}
+
+static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char stats[LOG_PAGE_SIZE];
+ int err = 0;
+ int fd;
+ char f1[] = FID_C1_LOG_FILENAME;
+ char f2[] = FID_C2_LOG_FILENAME;
+
+ const char *desc = "Get Latency Statistics log and show it.";
+ const char *write = "Get write statistics (read default)";
+
+ struct config {
+ int write;
+ };
+ struct config cfg = {
+ .write = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("write", 'w', &cfg.write, write),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) return fd;
+
+ err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1, false, NVME_NO_LOG_LSP, 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 : GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM);
+ else
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+
+ close(fd);
+ return err;
+}
+
+#define OP 0xFC
+#define FID 0x68
+static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err, fd;
+ char *desc = "Clear Memblaze devices error log.";
+
+ //const char *value = "new value of feature (required)";
+ //const char *save = "specifies that the controller shall save the attribute";
+ __u32 result;
+
+ struct config {
+ __u32 feature_id;
+ __u32 value;
+ int save;
+ };
+
+ struct config cfg = {
+ .feature_id = 0xf7,
+ .value = 0x534d0001,
+ .save = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+
+
+ err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, NULL, &result);
+ 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);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+/*
+ struct nvme_admin_cmd admin_cmd = {
+ .opcode = OP,
+ .cdw10 = FID,
+ };
+
+ err = nvme_submit_admin_passthru(fd, &admin_cmd);
+
+ if (!err) {
+ printf("OP(0x%2X) FID(0x%2X) Clear error log success.\n", OP, FID);
+ } else {
+ printf("NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+ };
+*/
+ return err;
+}
+
+static int mb_set_lat_stats(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ int err, fd;
+ const char *desc = (
+ "Enable/Disable Latency Statistics Tracking.\n"
+ "No argument prints current status.");
+ const char *enable_desc = "Enable LST";
+ const char *disable_desc = "Disable LST";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xe2;
+ const __u8 sel = 0;
+ const __u32 cdw11 = 0x0;
+ const __u32 cdw12 = 0x0;
+ const __u32 data_len = 32;
+ const __u32 save = 0;
+ __u32 result;
+ void *buf = NULL;
+
+ struct config {
+ bool enable, disable;
+ };
+
+ struct config cfg = {
+ .enable = false,
+ .disable = false,
+ };
+
+ const struct argconfig_commandline_options command_line_options[] = {
+ {"enable", 'e', "", CFG_NONE, &cfg.enable, no_argument, enable_desc},
+ {"disable", 'd', "", CFG_NONE, &cfg.disable, no_argument, disable_desc},
+ {NULL}
+ };
+
+ fd = parse_and_open(argc, argv, desc, command_line_options);
+
+ enum Option {
+ None = -1,
+ True = 1,
+ False = 0,
+ };
+ enum Option option = None;
+
+ if (cfg.enable && cfg.disable)
+ printf("Cannot enable and disable simultaneously.");
+ else if (cfg.enable || cfg.disable)
+ option = cfg.enable;
+
+ if (fd < 0)
+ return fd;
+ switch (option) {
+ case None:
+ err = nvme_get_feature(fd, nsid, fid, sel, cdw11, data_len, buf,
+ &result);
+ if (!err) {
+ printf(
+ "Latency Statistics Tracking (FID 0x%X) is currently (%i).\n",
+ fid, result);
+ } else {
+ printf("Could not read feature id 0xE2.\n");
+ return err;
+ }
+ break;
+ case True:
+ case False:
+ err = nvme_set_feature(fd, nsid, fid, option, cdw12, save,
+ data_len, buf, &result);
+ if (err > 0) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ } else if (err < 0) {
+ perror("Enable latency tracking");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully set enable bit for FID (0x%X) to %i.\n",
+ fid, option);
+ }
+ break;
+ default:
+ printf("%d not supported.\n", option);
+ return EINVAL;
+ }
+ return fd;
+}
+