Identify for NVM Set List has been added and it can be found in TP 4018.
This identify CNS 0x4 uses CDW11 as a NVM Set Identify(NVMSETID).
Currently nvme-cli is not using cdw11 for the identify command.
Therefore make it available for cdw11 to be passed to ioctl command by
adding nvme_identify13() to support the new CNS.
Signed-off-by: Minwoo Im <minwoo.im.dev@gmail.com>
NVME_ID_CNS_CTRL = 0x01,
NVME_ID_CNS_NS_ACTIVE_LIST = 0x02,
NVME_ID_CNS_NS_DESC_LIST = 0x03,
+ NVME_ID_CNS_NVMSET_LIST = 0x04,
NVME_ID_CNS_NS_PRESENT_LIST = 0x10,
NVME_ID_CNS_NS_PRESENT = 0x11,
NVME_ID_CNS_CTRL_NS_LIST = 0x12,
NVME_NIDT_UUID = 0x03,
};
+#define NVME_MAX_NVMSET 31
+
+struct nvme_nvmset_attr_entry {
+ __le16 id;
+ __le16 endurance_group_id;
+ __u8 rsvd4[4];
+ __le32 random_4k_read_typical;
+ __le32 opt_write_size;
+ __u8 total_nvmset_cap[16];
+ __u8 unalloc_nvmset_cap[16];
+ __u8 rsvd48[80];
+};
+
+struct nvme_id_nvmset {
+ __u8 nid;
+ __u8 rsvd1[127];
+ struct nvme_nvmset_attr_entry ent[NVME_MAX_NVMSET];
+};
+
/* Derived from 1.3a Figure 101: Get Log Page – Telemetry Host
* -Initiated Log (Log Identifier 07h)
*/
ENTRY("id-ns", "Send NVMe Identify Namespace, display structure", id_ns)
ENTRY("list-ns", "Send NVMe Identify List, display structure", list_ns)
ENTRY("ns-descs", "Send NVMe Namespace Descriptor List, display structure", ns_descs)
+ ENTRY("id-nvmset", "Sned NVMe Identify NVM Set List, display structure", id_nvmset)
ENTRY("create-ns", "Creates a namespace with the provided parameters", create_ns)
ENTRY("delete-ns", "Deletes a namespace from the controller", delete_ns)
ENTRY("attach-ns", "Attaches a namespace to requested controller(s)", attach_ns)
metadata, timeout_ms, NULL);
}
-int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data)
+int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data)
{
struct nvme_admin_cmd cmd = {
.opcode = nvme_admin_identify,
.addr = (__u64)(uintptr_t) data,
.data_len = NVME_IDENTIFY_DATA_SIZE,
.cdw10 = cdw10,
+ .cdw11 = cdw11,
};
return nvme_submit_admin_passthru(fd, &cmd);
}
+int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data)
+{
+ return nvme_identify13(fd, nsid, cdw10, 0, data);
+}
+
int nvme_identify_ctrl(int fd, void *data)
{
return nvme_identify(fd, 0, 1, data);
return nvme_identify(fd, nsid, NVME_ID_CNS_NS_DESC_LIST, data);
}
+int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data)
+{
+ return nvme_identify13(fd, 0, NVME_ID_CNS_NVMSET_LIST, nvmset_id, data);
+}
+
int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
__u16 lsi, __u32 data_len, void *data)
{
__u32 data_len, void *data, __u32 metadata_len,
void *metadata, __u32 timeout);
+int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data);
int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data);
int nvme_identify_ctrl(int fd, void *data);
int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data);
int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data);
int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
int nvme_identify_ns_descs(int fd, __u32 nsid, void *data);
+int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data);
int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
__u16 group_id, __u32 data_len, void *data);
int nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data);
__show_nvme_id_ctrl(ctrl, mode, NULL);
}
+void show_nvme_id_nvmset(struct nvme_id_nvmset *nvmset)
+{
+ int i;
+
+ printf("nid : %d\n", nvmset->nid);
+ printf(".................\n");
+ for (i = 0; i < nvmset->nid; i++) {
+ printf(" NVM Set Attribute Entry[%2d]\n", i);
+ printf(".................\n");
+ printf("nvmset_id : %d\n",
+ le16_to_cpu(nvmset->ent[i].id));
+ printf("enduracne_group_id : %d\n",
+ le16_to_cpu(nvmset->ent[i].endurance_group_id));
+ printf("random_4k_read_typical : %u\n",
+ le32_to_cpu(nvmset->ent[i].random_4k_read_typical));
+ printf("optimal_write_size : %u\n",
+ le32_to_cpu(nvmset->ent[i].opt_write_size));
+ printf("total_nvmset_cap : %.0Lf\n",
+ int128_to_double(nvmset->ent[i].total_nvmset_cap));
+ printf("unalloc_nvmset_cap : %.0Lf\n",
+ int128_to_double(nvmset->ent[i].unalloc_nvmset_cap));
+ printf(".................\n");
+ }
+}
+
+void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset, const char *devname)
+{
+ struct json_object *root;
+ struct json_array *entries;
+ __u32 nent = le32_to_cpu(nvmset->nid);
+ int i;
+
+ root = json_create_object();
+
+ json_object_add_value_int(root, "nid", nent);
+
+ entries = json_create_array();
+ for (i = 0; i < nent; i++) {
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_int(entry, "nvmset_id", le16_to_cpu(nvmset->ent[i].id));
+ json_object_add_value_int(entry, "endurance_group_id", le16_to_cpu(nvmset->ent[i].endurance_group_id));
+ json_object_add_value_int(entry, "random_4k_read_typical", le32_to_cpu(nvmset->ent[i].random_4k_read_typical));
+ json_object_add_value_int(entry, "optimal_write_size", le32_to_cpu(nvmset->ent[i].opt_write_size));
+ json_object_add_value_float(entry, "total_nvmset_cap", int128_to_double(nvmset->ent[i].total_nvmset_cap));
+ json_object_add_value_float(entry, "unalloc_nvmset_cap", int128_to_double(nvmset->ent[i].unalloc_nvmset_cap));
+
+ json_array_add_value_object(entries, entry);
+ }
+
+ json_object_add_value_array(root, "NVMSet", entries);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
void show_error_log(struct nvme_error_log_page *err_log, int entries, const char *devname)
{
int i;
void show_nvme_id_ns_descs(void *data);
void show_list_items(struct list_item *list_items, unsigned len);
void show_nvme_subsystem_list(struct subsys_list_item *slist, int n);
+void show_nvme_id_nvmset(struct nvme_id_nvmset *nvmset);
void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf);
void nvme_directive_show_fields(__u8 dtype, __u8 doper, unsigned int result, unsigned char *buf);
void json_nvme_id_ns_descs(void *data);
void json_print_nvme_subsystem_list(struct subsys_list_item *slist, int n);
void json_self_test_log(struct nvme_self_test_log *self_test, const char *devname);
+void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset, const char *devname);
#endif
return err;
}
+static int id_nvmset(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify NVM Set List command to the "\
+ "given device, returns entries for NVM Set identifiers greater "\
+ "than or equal to the value specified CDW11.NVMSETID "\
+ "in either binary format or json format";
+ const char *nvmset_id = "NVM Set Identify value";
+ int err, fmt, fd;
+ struct nvme_id_nvmset nvmset;
+
+ struct config {
+ __u16 nvmset_id;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .nvmset_id = 0,
+ .output_format = "normal",
+ };
+
+ const struct argconfig_commandline_options command_line_options[] = {
+ {"nvmset_id", 'i', "NUM", CFG_POSITIVE, &cfg.nvmset_id, required_argument, nvmset_id},
+ {"output-format", 'o', "FMT", CFG_STRING, &cfg.output_format, required_argument, output_format },
+ {NULL}
+ };
+
+ fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+ if (fd < 0)
+ return fd;
+
+ fmt = validate_output_format(cfg.output_format);
+ if (fmt < 0) {
+ err = fmt;
+ goto close_fd;
+ }
+
+ err = nvme_identify_nvmset(fd, cfg.nvmset_id, &nvmset);
+ if (!err) {
+ if (fmt == BINARY)
+ d_raw((unsigned char *)&nvmset, sizeof(nvmset));
+ else if (fmt == JSON)
+ json_nvme_id_nvmset(&nvmset, devicename);
+ else {
+ printf("NVME Identify NVM Set List %d:\n", cfg.nvmset_id);
+ show_nvme_id_nvmset(&nvmset);
+ }
+ }
+ else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x) NVMSETID:%d\n",
+ nvme_status_to_string(err), err, cfg.nvmset_id);
+ else
+ perror("identify nvm set list");
+
+ close_fd:
+ close(fd);
+
+ return err;
+}
+
static int get_ns_id(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
int nsid, fd;