From 3c0ccd4e69d068df1c2cdb129e7c17abc10135a3 Mon Sep 17 00:00:00 2001 From: Wenwei Tao Date: Thu, 7 Jul 2016 17:38:32 +0800 Subject: [PATCH] Add memblaze get/set feature support Signed-off-by: Wenwei Tao --- argconfig.c | 4 + memblaze-nvme.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++ memblaze-nvme.h | 2 + 3 files changed, 211 insertions(+) diff --git a/argconfig.c b/argconfig.c index b5447fa..41bb6d9 100644 --- a/argconfig.c +++ b/argconfig.c @@ -64,6 +64,9 @@ void print_word_wrapped(const char *s, int indent, int start) } for (c = s; *c != 0; c++) { + if (*c == '\n') + goto new_line; + if (*c == ' ' || next_space < 0) { next_space = 0; for (t = c + 1; *t != 0 && *t != ' '; t++) @@ -71,6 +74,7 @@ void print_word_wrapped(const char *s, int indent, int start) if (((int)(c - s) + start + next_space) > (last_line - indent + width)) { int i; +new_line: last_line = (int) (c-s) + start; putc('\n', stderr); for (i = 0; i < indent; i++) diff --git a/memblaze-nvme.c b/memblaze-nvme.c index 8496b56..3dc8c03 100644 --- a/memblaze-nvme.c +++ b/memblaze-nvme.c @@ -28,6 +28,10 @@ enum { NR_SMART_ITEMS, }; +enum { + MB_FEAT_POWER_MGMT = 0Xc6, +}; + #pragma pack(push, 1) struct nvme_memblaze_smart_log_item { __u8 id[3]; @@ -170,3 +174,204 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, return err; } + +static char *mb_feature_to_string(int feature) +{ + switch (feature) { + case MB_FEAT_POWER_MGMT: return "Memblaze power management"; + default: return "Unknown"; + } +} + +static int get_additional_feature(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_binary = "show infos 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; + }; + + struct config cfg = { + .namespace_id = 1, + .feature_id = 0, + .sel = 0, + .cdw11 = 0, + .data_len = 0, + }; + + const struct argconfig_commandline_options command_line_options[] = { + {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id, required_argument, namespace_id}, + {"feature-id", 'f', "NUM", CFG_POSITIVE, &cfg.feature_id, required_argument, feature_id}, + {"sel", 's', "NUM", CFG_BYTE, &cfg.sel, required_argument, sel}, + {"data-len", 'l', "NUM", CFG_POSITIVE, &cfg.data_len, required_argument, data_len}, + {"raw-binary", 'b', "FLAG", CFG_NONE, &cfg.raw_binary, no_argument, raw_binary}, + {"cdw11", 'c', "NUM", CFG_POSITIVE, &cfg.cdw11, required_argument, cdw11}, + {"human-readable", 'H', "FLAG", CFG_NONE, &cfg.human_readable, no_argument, human_readable}, + {0} + }; + + fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg)); + + 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); + } + + 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; +} + +static int set_additional_feature(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; + + struct config { + char *file; + __u32 namespace_id; + __u32 feature_id; + __u32 value; + __u32 data_len; + int save; + }; + + struct config cfg = { + .file = "", + .namespace_id = 0, + .feature_id = 0, + .value = 0, + .data_len = 0, + .save = 0, + }; + + const struct argconfig_commandline_options command_line_options[] = { + {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id, required_argument, namespace_id}, + {"feature-id", 'f', "NUM", CFG_POSITIVE, &cfg.feature_id, required_argument, feature_id}, + {"value", 'v', "NUM", CFG_POSITIVE, &cfg.value, required_argument, value}, + {"data-len", 'l', "NUM", CFG_POSITIVE, &cfg.data_len, required_argument, data_len}, + {"data", 'd', "FILE", CFG_STRING, &cfg.file, required_argument, data}, + {"save", 's', "FLAG", CFG_NONE, &cfg.save, no_argument, save}, + {0} + }; + + fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg)); + + 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); + } + + if (buf) { + if (strlen(cfg.file)) { + ffd = open(cfg.file, O_RDONLY); + if (ffd <= 0) { + fprintf(stderr, "no firmware file provided\n"); + return -EINVAL; + } + } + if (read(ffd, (void *)buf, cfg.data_len) < 0) { + fprintf(stderr, "failed to read data buffer from input file\n"); + return EINVAL; + } + } + + err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value, cfg.save, + cfg.data_len, buf, &result); + if (err < 0) { + perror("set-feature"); + return errno; + } + 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); + if (buf) + free(buf); + return err; +} diff --git a/memblaze-nvme.h b/memblaze-nvme.h index f921df4..82a0449 100644 --- a/memblaze-nvme.h +++ b/memblaze-nvme.h @@ -9,6 +9,8 @@ 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) ) ); -- 2.49.0