From f2c543b4ccad3b9f8871d952cddf66b3b438595b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 2 Jul 2021 22:49:35 +0200 Subject: Merging upstream version 1.14. Signed-off-by: Daniel Baumann --- plugins/memblaze/memblaze-nvme.c | 781 ++++++++++++++++++++++++++++---------- plugins/memblaze/memblaze-nvme.h | 13 +- plugins/memblaze/memblaze-utils.h | 63 +++ 3 files changed, 658 insertions(+), 199 deletions(-) (limited to 'plugins/memblaze') 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 #include #include +#include #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, ¶m1, ¶m2)) { + 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; +} + diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h index 8f7024d..043d0a8 100644 --- a/plugins/memblaze/memblaze-nvme.h +++ b/plugins/memblaze/memblaze-nvme.h @@ -14,10 +14,15 @@ PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions"), COMMAND_LIST( - ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", get_additional_smart_log) - ENTRY("get-feature-add", "Get Memblaze feature and show the resulting value", get_additional_feature) - ENTRY("set-feature-add", "Set a Memblaze feature and show the resulting value", set_additional_feature) - ENTRY("select-download", "Selective Firmware Download", memblaze_selective_download) + 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) ) ); diff --git a/plugins/memblaze/memblaze-utils.h b/plugins/memblaze/memblaze-utils.h index a67ee5e..6fdee39 100644 --- a/plugins/memblaze/memblaze-utils.h +++ b/plugins/memblaze/memblaze-utils.h @@ -160,5 +160,68 @@ struct nvme_p4_smart_log u8 resv[SMART_INFO_NEW_SIZE - sizeof(struct nvme_p4_smart_log_item) * NR_SMART_ITEMS]; }; +// base +#define DD do{ printf("=Memblaze= %s[%d]-%s():\n", __FILE__, __LINE__, __func__); }while(0) +#define DE(str) do{ printf("===ERROR!=== %s[%d]-%s():str=%s\n", __FILE__, __LINE__, __func__, \ + str); }while(0) +// integer +#define DI(i) do{ printf("=Memblaze= %s[%d]-%s():int=%d\n", __FILE__, __LINE__, __func__, \ + (int)i); } while(0) +#define DPI(prompt, i) do{ printf("=Memblaze= %s[%d]-%s():%s=%d\n", __FILE__, __LINE__, __func__, \ + prompt, i); }while(0) +#define DAI(prompt, i, arr, max) do{ printf("=Memblaze= %s[%d]-%s():%s", __FILE__, __LINE__, __func__, prompt); \ + for(i=0;i