2025-02-16 12:20:48 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
#include "nvme.h"
|
|
|
|
#include "libnvme.h"
|
|
|
|
#include "nvme-print.h"
|
|
|
|
|
|
|
|
#define CREATE_CMD
|
|
|
|
#include "fdp.h"
|
|
|
|
|
|
|
|
static int fdp_configs(int argc, char **argv, struct command *cmd,
|
|
|
|
struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Get Flexible Data Placement Configurations";
|
|
|
|
const char *egid = "Endurance group identifier";
|
|
|
|
const char *human_readable = "show log in readable format";
|
|
|
|
const char *raw = "use binary output";
|
|
|
|
|
|
|
|
enum nvme_print_flags flags;
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
struct nvme_fdp_config_log hdr;
|
|
|
|
void *log = NULL;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u16 egid;
|
|
|
|
char *output_format;
|
|
|
|
bool human_readable;
|
|
|
|
bool raw_binary;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.egid = 0,
|
|
|
|
.output_format = "normal",
|
|
|
|
.raw_binary = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("endgrp-id", 'e', &cfg.egid, egid),
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
|
|
|
OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2025-02-16 12:25:41 +01:00
|
|
|
err = validate_output_format(cfg.output_format, &flags);
|
2025-02-16 12:20:48 +01:00
|
|
|
if (flags < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (cfg.raw_binary)
|
|
|
|
flags = BINARY;
|
|
|
|
|
|
|
|
if (cfg.human_readable)
|
|
|
|
flags |= VERBOSE;
|
|
|
|
|
|
|
|
if (!cfg.egid) {
|
|
|
|
fprintf(stderr, "endurance group identifier required\n");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0,
|
|
|
|
sizeof(hdr), &hdr);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(errno);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
log = malloc(hdr.size);
|
|
|
|
if (!log) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0,
|
|
|
|
hdr.size, log);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(errno);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
nvme_show_fdp_configs(log, hdr.size, flags);
|
|
|
|
|
|
|
|
out:
|
|
|
|
dev_close(dev);
|
|
|
|
free(log);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fdp_usage(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Get Flexible Data Placement Reclaim Unit Handle Usage";
|
|
|
|
const char *egid = "Endurance group identifier";
|
|
|
|
const char *raw = "use binary output";
|
|
|
|
|
|
|
|
enum nvme_print_flags flags;
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
struct nvme_fdp_ruhu_log hdr;
|
|
|
|
size_t len;
|
|
|
|
void *log = NULL;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u16 egid;
|
|
|
|
char *output_format;
|
|
|
|
bool raw_binary;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
2025-02-16 12:24:13 +01:00
|
|
|
.egid = 0,
|
2025-02-16 12:20:48 +01:00
|
|
|
.output_format = "normal",
|
|
|
|
.raw_binary = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("endgrp-id", 'e', &cfg.egid, egid),
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2025-02-16 12:25:41 +01:00
|
|
|
err = validate_output_format(cfg.output_format, &flags);
|
2025-02-16 12:20:48 +01:00
|
|
|
if (flags < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (cfg.raw_binary)
|
|
|
|
flags = BINARY;
|
|
|
|
|
|
|
|
err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid,
|
|
|
|
0, sizeof(hdr), &hdr);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = sizeof(hdr) + le16_to_cpu(hdr.nruh) * sizeof(struct nvme_fdp_ruhu_desc);
|
|
|
|
log = malloc(len);
|
|
|
|
if (!log) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid,
|
|
|
|
0, len, log);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
nvme_show_fdp_usage(log, len, flags);
|
|
|
|
|
|
|
|
out:
|
|
|
|
dev_close(dev);
|
|
|
|
free(log);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fdp_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Get Flexible Data Placement Statistics";
|
|
|
|
const char *egid = "Endurance group identifier";
|
|
|
|
const char *raw = "use binary output";
|
|
|
|
|
|
|
|
enum nvme_print_flags flags;
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
struct nvme_fdp_stats_log stats;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u16 egid;
|
|
|
|
char *output_format;
|
|
|
|
bool raw_binary;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
2025-02-16 12:24:13 +01:00
|
|
|
.egid = 0,
|
2025-02-16 12:20:48 +01:00
|
|
|
.output_format = "normal",
|
|
|
|
.raw_binary = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("endgrp-id", 'e', &cfg.egid, egid),
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2025-02-16 12:25:41 +01:00
|
|
|
err = validate_output_format(cfg.output_format, &flags);
|
2025-02-16 12:20:48 +01:00
|
|
|
if (flags < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (cfg.raw_binary)
|
|
|
|
flags = BINARY;
|
|
|
|
|
|
|
|
memset(&stats, 0x0, sizeof(stats));
|
|
|
|
|
|
|
|
err = nvme_get_log_fdp_stats(dev->direct.fd, cfg.egid, 0, sizeof(stats), &stats);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
nvme_show_fdp_stats(&stats, flags);
|
|
|
|
|
|
|
|
out:
|
|
|
|
dev_close(dev);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fdp_events(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Get Flexible Data Placement Events";
|
|
|
|
const char *egid = "Endurance group identifier";
|
|
|
|
const char *host_events = "Get host events";
|
|
|
|
const char *raw = "use binary output";
|
|
|
|
|
|
|
|
enum nvme_print_flags flags;
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
struct nvme_fdp_events_log events;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u16 egid;
|
|
|
|
bool host_events;
|
|
|
|
char *output_format;
|
|
|
|
bool raw_binary;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
2025-02-16 12:24:13 +01:00
|
|
|
.egid = 0,
|
|
|
|
.host_events = false,
|
2025-02-16 12:20:48 +01:00
|
|
|
.output_format = "normal",
|
|
|
|
.raw_binary = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("endgrp-id", 'e', &cfg.egid, egid),
|
|
|
|
OPT_FLAG("host-events", 'E', &cfg.host_events, host_events),
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2025-02-16 12:25:41 +01:00
|
|
|
err = validate_output_format(cfg.output_format, &flags);
|
2025-02-16 12:20:48 +01:00
|
|
|
if (flags < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (cfg.raw_binary)
|
|
|
|
flags = BINARY;
|
|
|
|
|
|
|
|
memset(&events, 0x0, sizeof(events));
|
|
|
|
|
|
|
|
err = nvme_get_log_fdp_events(dev->direct.fd, cfg.egid,
|
|
|
|
cfg.host_events, 0, sizeof(events), &events);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
nvme_show_fdp_events(&events, flags);
|
|
|
|
|
|
|
|
out:
|
|
|
|
dev_close(dev);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fdp_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Reclaim Unit Handle Status";
|
|
|
|
const char *namespace_id = "Namespace identifier";
|
|
|
|
const char *raw = "use binary output";
|
|
|
|
|
|
|
|
enum nvme_print_flags flags;
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
struct nvme_fdp_ruh_status hdr;
|
|
|
|
size_t len;
|
|
|
|
void *buf = NULL;
|
|
|
|
int err = -1;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u32 namespace_id;
|
|
|
|
char *output_format;
|
|
|
|
bool raw_binary;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.output_format = "normal",
|
|
|
|
.raw_binary = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
|
|
|
|
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
|
|
|
|
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2025-02-16 12:25:41 +01:00
|
|
|
err = validate_output_format(cfg.output_format, &flags);
|
2025-02-16 12:20:48 +01:00
|
|
|
if (flags < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (cfg.raw_binary)
|
|
|
|
flags = BINARY;
|
|
|
|
|
|
|
|
if (!cfg.namespace_id) {
|
|
|
|
err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
|
|
|
|
if (err < 0) {
|
|
|
|
perror("get-namespace-id");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev),
|
|
|
|
cfg.namespace_id, sizeof(hdr), &hdr);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:23:16 +01:00
|
|
|
len = sizeof(struct nvme_fdp_ruh_status) +
|
|
|
|
le16_to_cpu(hdr.nruhsd) * sizeof(struct nvme_fdp_ruh_status_desc);
|
2025-02-16 12:20:48 +01:00
|
|
|
buf = malloc(len);
|
|
|
|
if (!buf) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev),
|
|
|
|
cfg.namespace_id, len, buf);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
nvme_show_fdp_ruh_status(buf, len, flags);
|
|
|
|
|
|
|
|
out:
|
|
|
|
free(buf);
|
|
|
|
dev_close(dev);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fdp_update(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Reclaim Unit Handle Update";
|
|
|
|
const char *namespace_id = "Namespace identifier";
|
|
|
|
const char *_pids = "Comma-separated list of placement identifiers to update";
|
|
|
|
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
unsigned short pids[256];
|
|
|
|
__u16 buf[256];
|
|
|
|
int npids;
|
|
|
|
int err = -1;
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u32 namespace_id;
|
|
|
|
char *pids;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
|
|
|
.pids = "",
|
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
|
|
|
|
OPT_LIST("pids", 'p', &cfg.pids, _pids),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
npids = argconfig_parse_comma_sep_array_short(cfg.pids, pids, ARRAY_SIZE(pids));
|
|
|
|
if (npids < 0) {
|
|
|
|
perror("could not parse pids");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
} else if (npids == 0) {
|
|
|
|
fprintf(stderr, "no placement identifiers set\n");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cfg.namespace_id) {
|
|
|
|
err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
|
|
|
|
if (err < 0) {
|
|
|
|
perror("get-namespace-id");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:24:13 +01:00
|
|
|
for (unsigned int i = 0; i < npids; i++)
|
2025-02-16 12:20:48 +01:00
|
|
|
buf[i] = cpu_to_le16(pids[i]);
|
|
|
|
|
|
|
|
err = nvme_fdp_reclaim_unit_handle_update(dev_fd(dev), cfg.namespace_id, npids, buf);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("update: Success\n");
|
|
|
|
|
|
|
|
out:
|
|
|
|
dev_close(dev);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fdp_set_events(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
|
|
|
{
|
|
|
|
const char *desc = "Enable or disable FDP events";
|
|
|
|
const char *namespace_id = "Namespace identifier";
|
|
|
|
const char *enable = "Enable/disable event";
|
|
|
|
const char *event_types = "Comma-separated list of event types";
|
|
|
|
const char *ph = "Placement Handle";
|
2025-02-16 12:24:13 +01:00
|
|
|
const char *save = "specifies that the controller shall save the attribute";
|
2025-02-16 12:20:48 +01:00
|
|
|
|
|
|
|
struct nvme_dev *dev;
|
|
|
|
int err = -1;
|
|
|
|
unsigned short evts[255];
|
|
|
|
int nev;
|
|
|
|
__u8 buf[255];
|
|
|
|
|
|
|
|
struct config {
|
|
|
|
__u32 namespace_id;
|
2025-02-16 12:24:13 +01:00
|
|
|
__u16 ph;
|
|
|
|
char *event_types;
|
|
|
|
bool enable;
|
|
|
|
bool save;
|
2025-02-16 12:20:48 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct config cfg = {
|
2025-02-16 12:24:13 +01:00
|
|
|
.enable = false,
|
|
|
|
.save = false,
|
2025-02-16 12:20:48 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
OPT_ARGS(opts) = {
|
|
|
|
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
|
|
|
|
OPT_SHRT("placement-handle", 'p', &cfg.ph, ph),
|
|
|
|
OPT_FLAG("enable", 'e', &cfg.enable, enable),
|
2025-02-16 12:24:13 +01:00
|
|
|
OPT_FLAG("save", 's', &cfg.save, save),
|
2025-02-16 12:20:48 +01:00
|
|
|
OPT_LIST("event-types", 't', &cfg.event_types, event_types),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
err = parse_and_open(&dev, argc, argv, desc, opts);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
nev = argconfig_parse_comma_sep_array_short(cfg.event_types, evts, ARRAY_SIZE(evts));
|
|
|
|
if (nev < 0) {
|
|
|
|
perror("could not parse event types");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
} else if (nev == 0) {
|
|
|
|
fprintf(stderr, "no event types set\n");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
} else if (nev > 255) {
|
|
|
|
fprintf(stderr, "too many event types (max 255)\n");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cfg.namespace_id) {
|
|
|
|
err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
|
|
|
|
if (err < 0) {
|
|
|
|
if (errno != ENOTTY) {
|
|
|
|
fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg.namespace_id = NVME_NSID_ALL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-16 12:24:13 +01:00
|
|
|
for (unsigned int i = 0; i < nev; i++)
|
2025-02-16 12:20:48 +01:00
|
|
|
buf[i] = (__u8)evts[i];
|
|
|
|
|
|
|
|
struct nvme_set_features_args args = {
|
|
|
|
.args_size = sizeof(args),
|
|
|
|
.fd = dev_fd(dev),
|
|
|
|
.fid = NVME_FEAT_FID_FDP_EVENTS,
|
2025-02-16 12:24:13 +01:00
|
|
|
.save = cfg.save,
|
2025-02-16 12:20:48 +01:00
|
|
|
.nsid = cfg.namespace_id,
|
|
|
|
.cdw11 = (nev << 16) | cfg.ph,
|
|
|
|
.cdw12 = cfg.enable ? 0x1 : 0x0,
|
|
|
|
.data_len = sizeof(buf),
|
|
|
|
.data = buf,
|
|
|
|
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
|
|
|
|
.result = NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
err = nvme_set_features(&args);
|
|
|
|
if (err) {
|
|
|
|
nvme_show_status(err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("set-events: Success\n");
|
|
|
|
|
|
|
|
out:
|
|
|
|
dev_close(dev);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|