diff --git a/plugins/feat/feat-nvme.c b/plugins/feat/feat-nvme.c index 2330c18372..54346dce27 100644 --- a/plugins/feat/feat-nvme.c +++ b/plugins/feat/feat-nvme.c @@ -8,6 +8,9 @@ #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; @@ -24,6 +27,7 @@ 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 int power_mgmt_get(struct nvme_dev *dev, const __u8 fid, __u8 sel) { @@ -258,3 +262,98 @@ static int feat_perfc(int argc, char **argv, struct command *cmd, struct plugin return err; } + +static int hctm_get(struct nvme_dev *dev, const __u8 fid, __u8 sel) +{ + __u32 result; + int err; + + 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, + }; + + err = nvme_get_features(&args); + if (!err) { + if (NVME_CHECK(sel, GET_FEATURES_SEL, SUPPORTED)) + nvme_show_select_result(fid, result); + else + nvme_feature_show_fields(fid, result, NULL); + } else { + nvme_show_error("Get %s", hctm_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; + bool save; + __u8 sel; + }; + + struct config cfg = { 0 }; + + NVME_ARGS(opts, + OPT_SHRT("tmt1", 't', &cfg.tmt1, TMT(1)), + OPT_SHRT("tmt2", 'T', &cfg.tmt2, TMT(2)), + OPT_FLAG("save", 's', &cfg.save, save), + OPT_BYTE("sel", 'S', &cfg.sel, sel)); + + 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, cfg.save); + else + err = hctm_get(dev, fid, cfg.sel); + + return err; +} diff --git a/plugins/feat/feat-nvme.h b/plugins/feat/feat-nvme.h index 1e2b778c33..491a3c7d6e 100644 --- a/plugins/feat/feat-nvme.h +++ b/plugins/feat/feat-nvme.h @@ -12,11 +12,13 @@ #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" 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) ) ); #endif /* !FEAT_NVME || CMD_HEADER_MULTI_READ */