Merging upstream version 2.14.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
0d9181726f
commit
f268303a51
572 changed files with 4636 additions and 1730 deletions
|
@ -1,27 +1,70 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include "nvme.h"
|
||||
#include "plugin.h"
|
||||
#include "nvme-print.h"
|
||||
#include "common.h"
|
||||
|
||||
#define CREATE_CMD
|
||||
#include "feat-nvme.h"
|
||||
|
||||
#define STR(x) #x
|
||||
#define TMT(n) "thermal management temperature " STR(n)
|
||||
|
||||
struct perfc_config {
|
||||
__u32 namespace_id;
|
||||
__u8 attri;
|
||||
bool rvspa;
|
||||
__u8 r4karl;
|
||||
char *paid;
|
||||
__u16 attrl;
|
||||
char *vs_data;
|
||||
__u8 sel;
|
||||
};
|
||||
|
||||
struct temp_thresh_config {
|
||||
__u16 tmpth;
|
||||
__u8 tmpsel;
|
||||
__u8 thsel;
|
||||
__u8 tmpthh;
|
||||
__u8 sel;
|
||||
};
|
||||
|
||||
static const char *power_mgmt_feat = "power management feature";
|
||||
static const char *sel = "[0-3]: current/default/saved/supported";
|
||||
static const char *save = "Specifies that the controller shall save the attribute";
|
||||
static const char *perfc_feat = "performance characteristics feature";
|
||||
static const char *hctm_feat = "host controlled thermal management feature";
|
||||
static const char *timestamp_feat = "timestamp feature";
|
||||
|
||||
static int power_mgmt_get(struct nvme_dev *dev, const __u8 fid, __u8 sel)
|
||||
static int feat_get(struct nvme_dev *dev, const __u8 fid, __u32 cdw11, __u8 sel, const char *feat)
|
||||
{
|
||||
__u32 result;
|
||||
int err;
|
||||
__u32 len = 0;
|
||||
|
||||
_cleanup_free_ void *buf = NULL;
|
||||
|
||||
if (!NVME_CHECK(sel, GET_FEATURES_SEL, SUPPORTED))
|
||||
nvme_get_feature_length(fid, cdw11, &len);
|
||||
|
||||
if (len) {
|
||||
buf = nvme_alloc(len - 1);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
struct nvme_get_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = fid,
|
||||
.sel = sel,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = &result,
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = fid,
|
||||
.sel = sel,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = &result,
|
||||
.cdw11 = cdw11,
|
||||
.data = buf,
|
||||
.data_len = len,
|
||||
};
|
||||
|
||||
err = nvme_get_features(&args);
|
||||
|
@ -29,9 +72,11 @@ static int power_mgmt_get(struct nvme_dev *dev, const __u8 fid, __u8 sel)
|
|||
if (NVME_CHECK(sel, GET_FEATURES_SEL, SUPPORTED))
|
||||
nvme_show_select_result(fid, result);
|
||||
else
|
||||
nvme_feature_show_fields(fid, result, NULL);
|
||||
nvme_feature_show_fields(fid, result, buf);
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
} else {
|
||||
nvme_show_error("Get %s", power_mgmt_feat);
|
||||
nvme_show_error("Get %s: %s", feat, nvme_strerror(errno));
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -83,26 +128,343 @@ static int feat_power_mgmt(int argc, char **argv, struct command *cmd, struct pl
|
|||
struct config {
|
||||
__u8 ps;
|
||||
__u8 wh;
|
||||
bool save;
|
||||
__u8 sel;
|
||||
};
|
||||
|
||||
struct config cfg = { 0 };
|
||||
|
||||
NVME_ARGS(opts,
|
||||
FEAT_ARGS(opts,
|
||||
OPT_BYTE("ps", 'p', &cfg.ps, ps),
|
||||
OPT_BYTE("wh", 'w', &cfg.wh, wh),
|
||||
OPT_FLAG("save", 's', &cfg.save, save),
|
||||
OPT_BYTE("sel", 'S', &cfg.sel, sel));
|
||||
OPT_BYTE("wh", 'w', &cfg.wh, wh));
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, POWER_MGMT_DESC, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (argconfig_parse_seen(opts, "ps"))
|
||||
err = power_mgmt_set(dev, fid, cfg.ps, cfg.wh, cfg.save);
|
||||
err = power_mgmt_set(dev, fid, cfg.ps, cfg.wh, argconfig_parse_seen(opts, "save"));
|
||||
else
|
||||
err = power_mgmt_get(dev, fid, cfg.sel);
|
||||
err = feat_get(dev, fid, 0, cfg.sel, power_mgmt_feat);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int perfc_set(struct nvme_dev *dev, __u8 fid, __u32 cdw11, struct perfc_config *cfg,
|
||||
bool save)
|
||||
{
|
||||
__u32 result;
|
||||
int err;
|
||||
|
||||
_cleanup_fd_ int ffd = STDIN_FILENO;
|
||||
|
||||
struct nvme_perf_characteristics data = {
|
||||
.attr_buf = { 0 },
|
||||
};
|
||||
|
||||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = fid,
|
||||
.cdw11 = cdw11,
|
||||
.save = save,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = &result,
|
||||
.data = &data,
|
||||
.data_len = sizeof(data),
|
||||
};
|
||||
|
||||
switch (cfg->attri) {
|
||||
case NVME_FEAT_PERFC_ATTRI_STD:
|
||||
data.std_perf->r4karl = cfg->r4karl;
|
||||
break;
|
||||
case NVME_FEAT_PERFC_ATTRI_VS_MIN ... NVME_FEAT_PERFC_ATTRI_VS_MAX:
|
||||
nvme_uuid_from_string(cfg->paid, data.vs_perf->paid);
|
||||
data.vs_perf->attrl = cfg->attrl;
|
||||
if (data.vs_perf->attrl && strlen(cfg->vs_data)) {
|
||||
ffd = open(cfg->vs_data, O_RDONLY);
|
||||
if (ffd < 0) {
|
||||
nvme_show_error("Failed to open file %s: %s", cfg->vs_data,
|
||||
strerror(errno));
|
||||
return -EINVAL;
|
||||
}
|
||||
err = read(ffd, data.vs_perf->vs, data.vs_perf->attrl);
|
||||
if (err < 0) {
|
||||
nvme_show_error("failed to read data buffer from input file: %s",
|
||||
strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
err = nvme_set_features(&args);
|
||||
|
||||
nvme_show_init();
|
||||
|
||||
if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
} else if (err < 0) {
|
||||
nvme_show_perror("Set %s", perfc_feat);
|
||||
} else {
|
||||
nvme_show_result("Set %s: 0x%04x (%s)", perfc_feat, args.cdw11,
|
||||
save ? "Save" : "Not save");
|
||||
nvme_feature_show_fields(args.fid, args.cdw11, NULL);
|
||||
}
|
||||
|
||||
nvme_show_finish();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int feat_perfc(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
const char *namespace_id_optional = "optional namespace attached to controller";
|
||||
const char *attri = "attribute index";
|
||||
const char *rvspa = "revert vendor specific performance attribute";
|
||||
const char *r4karl = "random 4 kib average read latency";
|
||||
const char *paid = "performance attribute identifier";
|
||||
const char *attrl = "attribute length";
|
||||
const char *vs_data = "vendor specific data";
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
int err;
|
||||
__u8 fid = NVME_FEAT_FID_PERF_CHARACTERISTICS;
|
||||
__u32 cdw11;
|
||||
|
||||
struct perfc_config cfg = { 0 };
|
||||
|
||||
FEAT_ARGS(opts,
|
||||
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_optional),
|
||||
OPT_BYTE("attri", 'a', &cfg.attri, attri),
|
||||
OPT_FLAG("rvspa", 'r', &cfg.rvspa, rvspa),
|
||||
OPT_BYTE("r4karl", 'R', &cfg.r4karl, r4karl),
|
||||
OPT_STR("paid", 'p', &cfg.paid, paid),
|
||||
OPT_SHRT("attrl", 'A', &cfg.attrl, attrl),
|
||||
OPT_FILE("vs-data", 'V', &cfg.vs_data, vs_data));
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, PERFC_DESC, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cdw11 = NVME_SET(cfg.attri, FEAT_PERFC_ATTRI) | NVME_SET(cfg.rvspa, FEAT_PERFC_RVSPA);
|
||||
|
||||
if (argconfig_parse_seen(opts, "rvspa") || argconfig_parse_seen(opts, "r4karl") ||
|
||||
argconfig_parse_seen(opts, "paid"))
|
||||
err = perfc_set(dev, fid, cdw11, &cfg, argconfig_parse_seen(opts, "save"));
|
||||
else
|
||||
err = feat_get(dev, fid, cdw11, cfg.sel, perfc_feat);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hctm_set(struct nvme_dev *dev, const __u8 fid, __u16 tmt1, __u16 tmt2, bool save)
|
||||
{
|
||||
__u32 result;
|
||||
int err;
|
||||
|
||||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = fid,
|
||||
.cdw11 = NVME_SET(tmt1, FEAT_HCTM_TMT1) | NVME_SET(tmt2, FEAT_HCTM_TMT2),
|
||||
.save = save,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = &result,
|
||||
};
|
||||
|
||||
err = nvme_set_features(&args);
|
||||
|
||||
nvme_show_init();
|
||||
|
||||
if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
} else if (err < 0) {
|
||||
nvme_show_perror("Set %s", hctm_feat);
|
||||
} else {
|
||||
nvme_show_result("Set %s: 0x%04x (%s)", hctm_feat, args.cdw11,
|
||||
save ? "Save" : "Not save");
|
||||
nvme_feature_show_fields(fid, args.cdw11, NULL);
|
||||
}
|
||||
|
||||
nvme_show_finish();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int feat_hctm(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
const __u8 fid = NVME_FEAT_FID_HCTM;
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
int err;
|
||||
|
||||
struct config {
|
||||
__u16 tmt1;
|
||||
__u16 tmt2;
|
||||
__u8 sel;
|
||||
};
|
||||
|
||||
struct config cfg = { 0 };
|
||||
|
||||
FEAT_ARGS(opts,
|
||||
OPT_SHRT("tmt1", 't', &cfg.tmt1, TMT(1)),
|
||||
OPT_SHRT("tmt2", 'T', &cfg.tmt2, TMT(2)));
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, HCTM_DESC, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (argconfig_parse_seen(opts, "tmt1") || argconfig_parse_seen(opts, "tmt2"))
|
||||
err = hctm_set(dev, fid, cfg.tmt1, cfg.tmt2, argconfig_parse_seen(opts, "save"));
|
||||
else
|
||||
err = feat_get(dev, fid, 0, cfg.sel, hctm_feat);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int timestamp_set(struct nvme_dev *dev, const __u8 fid, __u64 tstmp, bool save)
|
||||
{
|
||||
__u32 result;
|
||||
int err;
|
||||
struct nvme_timestamp ts;
|
||||
__le64 timestamp = cpu_to_le64(tstmp);
|
||||
|
||||
struct nvme_set_features_args args = {
|
||||
.args_size = sizeof(args),
|
||||
.fd = dev_fd(dev),
|
||||
.fid = fid,
|
||||
.save = save,
|
||||
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
||||
.result = &result,
|
||||
.data = &ts,
|
||||
.data_len = sizeof(ts),
|
||||
};
|
||||
|
||||
memcpy(ts.timestamp, ×tamp, sizeof(ts.timestamp));
|
||||
|
||||
err = nvme_set_features(&args);
|
||||
|
||||
nvme_show_init();
|
||||
|
||||
if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
} else if (err < 0) {
|
||||
nvme_show_perror("Set %s", timestamp_feat);
|
||||
} else {
|
||||
nvme_show_result("Set %s: (%s)", timestamp_feat, save ? "Save" : "Not save");
|
||||
nvme_feature_show_fields(fid, args.cdw11, args.data);
|
||||
}
|
||||
|
||||
nvme_show_finish();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int feat_timestamp(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
const __u8 fid = NVME_FEAT_FID_TIMESTAMP;
|
||||
const char *tstmp = "timestamp";
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
int err;
|
||||
|
||||
struct config {
|
||||
__u64 tstmp;
|
||||
__u8 sel;
|
||||
};
|
||||
|
||||
struct config cfg = { 0 };
|
||||
|
||||
FEAT_ARGS(opts, OPT_LONG("tstmp", 't', &cfg.tstmp, tstmp));
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, TIMESTAMP_DESC, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (argconfig_parse_seen(opts, "tstmp"))
|
||||
err = timestamp_set(dev, fid, cfg.tstmp, argconfig_parse_seen(opts, "save"));
|
||||
else
|
||||
err = feat_get(dev, fid, 0, cfg.sel, timestamp_feat);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int temp_thresh_set(int fd, const __u8 fid, struct argconfig_commandline_options *opts,
|
||||
struct temp_thresh_config *cfg)
|
||||
{
|
||||
__u32 result;
|
||||
int err;
|
||||
enum nvme_get_features_sel sel = NVME_GET_FEATURES_SEL_CURRENT;
|
||||
__u16 tmpth;
|
||||
__u8 tmpsel;
|
||||
__u8 thsel;
|
||||
__u8 tmpthh;
|
||||
bool save = argconfig_parse_seen(opts, "save");
|
||||
|
||||
if (save)
|
||||
sel = NVME_GET_FEATURES_SEL_SAVED;
|
||||
|
||||
err = nvme_get_features_temp_thresh2(fd, sel, cfg->tmpsel, cfg->thsel, &result);
|
||||
if (!err) {
|
||||
nvme_feature_decode_temp_threshold(result, &tmpth, &tmpsel, &thsel, &tmpthh);
|
||||
if (!argconfig_parse_seen(opts, "tmpth"))
|
||||
cfg->tmpth = tmpth;
|
||||
if (!argconfig_parse_seen(opts, "tmpthh"))
|
||||
cfg->tmpthh = tmpthh;
|
||||
}
|
||||
|
||||
err = nvme_set_features_temp_thresh2(fd, cfg->tmpth, cfg->tmpsel, cfg->thsel, cfg->tmpthh,
|
||||
save, &result);
|
||||
|
||||
nvme_show_init();
|
||||
|
||||
if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
} else if (err < 0) {
|
||||
nvme_show_perror("Set %s", timestamp_feat);
|
||||
} else {
|
||||
nvme_show_result("Set %s: (%s)", timestamp_feat, save ? "Save" : "Not save");
|
||||
nvme_feature_show_fields(fid, NVME_SET(cfg->tmpth, FEAT_TT_TMPTH) |
|
||||
NVME_SET(cfg->tmpsel, FEAT_TT_TMPSEL) |
|
||||
NVME_SET(cfg->thsel, FEAT_TT_THSEL) |
|
||||
NVME_SET(cfg->tmpthh, FEAT_TT_TMPTHH), NULL);
|
||||
}
|
||||
|
||||
nvme_show_finish();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int feat_temp_thresh(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
const __u8 fid = NVME_FEAT_FID_TEMP_THRESH;
|
||||
const char *tmpth = "temperature threshold";
|
||||
const char *tmpsel = "threshold temperature select";
|
||||
const char *thsel = "threshold type select";
|
||||
const char *tmpthh = "temperature threshold hysteresis";
|
||||
|
||||
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
||||
int err;
|
||||
|
||||
struct temp_thresh_config cfg = { 0 };
|
||||
|
||||
FEAT_ARGS(opts,
|
||||
OPT_SHRT("tmpth", 'T', &cfg.tmpth, tmpth),
|
||||
OPT_BYTE("tmpsel", 'm', &cfg.tmpsel, tmpsel),
|
||||
OPT_BYTE("thsel", 'H', &cfg.thsel, thsel),
|
||||
OPT_BYTE("tmpthh", 'M', &cfg.tmpthh, tmpthh));
|
||||
|
||||
err = parse_and_open(&dev, argc, argv, TEMP_THRESH_DESC, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (argconfig_parse_seen(opts, "tmpth") || argconfig_parse_seen(opts, "tmpthh"))
|
||||
err = temp_thresh_set(dev_fd(dev), fid, opts, &cfg);
|
||||
else
|
||||
err = feat_get(dev, fid, NVME_SET(cfg.tmpsel, FEAT_TT_TMPSEL) |
|
||||
NVME_SET(cfg.thsel, FEAT_TT_THSEL), cfg.sel, timestamp_feat);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -11,10 +11,22 @@
|
|||
|
||||
#define FEAT_PLUGIN_VERSION "1.0"
|
||||
#define POWER_MGMT_DESC "Get and set power management feature"
|
||||
#define PERFC_DESC "Get and set perf characteristics feature"
|
||||
#define HCTM_DESC "Get and set host controlled thermal management feature"
|
||||
#define TIMESTAMP_DESC "Get and set timestamp feature"
|
||||
#define TEMP_THRESH_DESC "Get and set temperature threshold feature"
|
||||
|
||||
#define FEAT_ARGS(n, ...) \
|
||||
NVME_ARGS(n, ##__VA_ARGS__, OPT_FLAG("save", 's', NULL, save), \
|
||||
OPT_BYTE("sel", 'S', &cfg.sel, sel))
|
||||
|
||||
PLUGIN(NAME("feat", "NVMe feature extensions", FEAT_PLUGIN_VERSION),
|
||||
COMMAND_LIST(
|
||||
ENTRY("power-mgmt", POWER_MGMT_DESC, feat_power_mgmt)
|
||||
ENTRY("perf-characteristics", PERFC_DESC, feat_perfc)
|
||||
ENTRY("hctm", HCTM_DESC, feat_hctm)
|
||||
ENTRY("timestamp", TIMESTAMP_DESC, feat_timestamp)
|
||||
ENTRY("temp-thresh", TEMP_THRESH_DESC, feat_temp_thresh)
|
||||
)
|
||||
);
|
||||
#endif /* !FEAT_NVME || CMD_HEADER_MULTI_READ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue