--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "nvme.h"
+#include "plugin.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "feat-nvme.h"
+
+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 int power_mgmt_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", power_mgmt_feat);
+ }
+
+ return err;
+}
+
+static int power_mgmt_set(struct nvme_dev *dev, const __u8 fid, __u8 ps, __u8 wh, 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(ps, FEAT_PWRMGMT_PS) | NVME_SET(wh, FEAT_PWRMGMT_WH),
+ .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", power_mgmt_feat);
+ } else {
+ nvme_show_result("Set %s: 0x%04x (%s)", power_mgmt_feat, args.cdw11,
+ save ? "Save" : "Not save");
+ nvme_feature_show_fields(fid, args.cdw11, NULL);
+ }
+
+ nvme_show_finish();
+
+ return err;
+}
+
+static int feat_power_mgmt(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *ps = "power state";
+ const char *wh = "workload hint";
+ const __u8 fid = NVME_FEAT_FID_POWER_MGMT;
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ __u8 ps;
+ __u8 wh;
+ bool save;
+ __u8 sel;
+ };
+
+ struct config cfg = { 0 };
+
+ NVME_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));
+
+ 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);
+ else
+ err = power_mgmt_get(dev, fid, cfg.sel);
+
+ return err;
+}
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "cmd.h"
+
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/feat/feat-nvme
+
+#include "define_cmd.h"
+
+#if !defined(FEAT_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define FEAT_NVME
+
+#define FEAT_PLUGIN_VERSION "1.0"
+#define POWER_MGMT_DESC "Get and set power management feature"
+
+PLUGIN(NAME("feat", "NVMe feature extensions", FEAT_PLUGIN_VERSION),
+ COMMAND_LIST(
+ ENTRY("power-mgmt", POWER_MGMT_DESC, feat_power_mgmt)
+ )
+);
+#endif /* !FEAT_NVME || CMD_HEADER_MULTI_READ */
+
+#ifndef FEAT_NVME_H
+#define FEAT_NVME_H
+
+#endif /* FEAT_NVME_H */