Skip to content

Commit f4d06f0

Browse files
author
Keith Busch
authored
Merge pull request #550 from RevanthRajashekar/uuid
nvme: UUIDs for Vendor-Specific Information
2 parents c126e37 + 4ef5a03 commit f4d06f0

7 files changed

Lines changed: 206 additions & 11 deletions

File tree

linux/nvme.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ enum {
310310
NVME_CTRL_CTRATT_ENDURANCE_GROUPS = 1 << 4,
311311
NVME_CTRL_CTRATT_PREDICTABLE_LAT = 1 << 5,
312312
NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY = 1 << 7,
313+
NVME_CTRL_CTRATT_UUID_LIST = 1 << 9,
313314
};
314315

315316
struct nvme_lbaf {
@@ -370,6 +371,7 @@ enum {
370371
NVME_ID_CNS_CTRL_LIST = 0x13,
371372
NVME_ID_CNS_SCNDRY_CTRL_LIST = 0x15,
372373
NVME_ID_CNS_NS_GRANULARITY = 0x16,
374+
NVME_ID_CNS_UUID_LIST = 0x17,
373375
};
374376

375377
enum {
@@ -452,6 +454,17 @@ struct nvme_id_ns_granularity_list {
452454
struct nvme_id_ns_granularity_list_entry entry[16];
453455
};
454456

457+
#define NVME_MAX_UUID_ENTRIES 128
458+
struct nvme_id_uuid_list_entry {
459+
__u8 header;
460+
__u8 rsvd1[15];
461+
__u8 uuid[16];
462+
};
463+
464+
struct nvme_id_uuid_list {
465+
struct nvme_id_uuid_list_entry entry[NVME_MAX_UUID_ENTRIES];
466+
};
467+
455468
/**
456469
* struct nvme_telemetry_log_page_hdr - structure for telemetry log page
457470
* @lpi: Log page identifier
@@ -583,6 +596,7 @@ enum {
583596
NVME_CMD_EFFECTS_NIC = 1 << 3,
584597
NVME_CMD_EFFECTS_CCC = 1 << 4,
585598
NVME_CMD_EFFECTS_CSE_MASK = 3 << 16,
599+
NVME_CMD_EFFECTS_UUID_SEL = 1 << 19,
586600
};
587601

588602
struct nvme_effects_log {

nvme-builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ COMMAND_LIST(
1717
ENTRY("list-secondary", "List Secondary Controllers associated with a Primary Controller", list_secondary_ctrl)
1818
ENTRY("ns-descs", "Send NVMe Namespace Descriptor List, display structure", ns_descs)
1919
ENTRY("id-nvmset", "Send NVMe Identify NVM Set List, display structure", id_nvmset)
20+
ENTRY("id-uuid", "Send NVMe Identify UUID List, display structure", id_uuid)
2021
ENTRY("create-ns", "Creates a namespace with the provided parameters", create_ns)
2122
ENTRY("delete-ns", "Deletes a namespace from the controller", delete_ns)
2223
ENTRY("attach-ns", "Attaches a namespace to requested controller(s)", attach_ns)

nvme-ioctl.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,13 @@ int nvme_identify_ns_granularity(int fd, void *data)
408408
return nvme_identify13(fd, 0, NVME_ID_CNS_NS_GRANULARITY, 0, data);
409409
}
410410

411-
int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
412-
__u16 lsi, bool rae, __u32 data_len, void *data)
411+
int nvme_identify_uuid(int fd, void *data)
412+
{
413+
return nvme_identify(fd, 0, NVME_ID_CNS_UUID_LIST, data);
414+
}
415+
416+
int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
417+
__u16 lsi, bool rae, __u8 uuid_ix, __u32 data_len, void *data)
413418
{
414419
struct nvme_admin_cmd cmd = {
415420
.opcode = nvme_admin_get_log_page,
@@ -427,6 +432,7 @@ int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
427432
cmd.cdw11 = numdu | (lsi << 16);
428433
cmd.cdw12 = lpo;
429434
cmd.cdw13 = (lpo >> 32);
435+
cmd.cdw14 = uuid_ix;
430436

431437
return nvme_submit_admin_passthru(fd, &cmd);
432438

nvme-ioctl.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,22 @@ int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data);
7878
int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
7979
int nvme_identify_ns_descs(int fd, __u32 nsid, void *data);
8080
int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data);
81+
int nvme_identify_uuid(int fd, void *data);
8182
int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
8283
int nvme_identify_ns_granularity(int fd, void *data);
83-
int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
84-
__u16 group_id, bool rae, __u32 data_len, void *data);
8584
int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
8685
__u32 data_len, void *data);
86+
int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
87+
__u16 group_id, bool rae, __u8 uuid_ix,
88+
__u32 data_len, void *data);
89+
90+
static inline int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp,
91+
__u64 lpo, __u16 lsi, bool rae, __u32 data_len,
92+
void *data)
93+
{
94+
return nvme_get_log14(fd, nsid, log_id, lsp, lpo, lsi, rae, 0,
95+
data_len, data);
96+
}
8797

8898
int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
8999
int ctrl_gen, size_t log_page_size, __u64 offset);

nvme-print.c

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@
1010
#include "suffix.h"
1111
#include "common.h"
1212

13+
static const uint8_t zero_uuid[16] = {
14+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
15+
};
16+
17+
static const uint8_t invalid_uuid[16] = {
18+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
19+
};
20+
1321
static const char *nvme_ana_state_to_string(enum nvme_ana_state state)
1422
{
1523
switch (state) {
@@ -102,6 +110,27 @@ static void format(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz)
102110
}
103111
}
104112

113+
static const char *nvme_uuid_to_string(uuid_t uuid)
114+
{
115+
/* large enough to hold uuid str (37) + null-termination byte */
116+
static char uuid_str[40];
117+
#ifdef LIBUUID
118+
uuid_unparse_lower(uuid, uuid_str);
119+
#else
120+
static const char *hex_digits = "0123456789abcdef";
121+
char *p = &uuid_str[0];
122+
int i;
123+
for (i = 0; i < 16; i++) {
124+
*p++ = hex_digits[(uuid.b[i] & 0xf0) >> 4];
125+
*p++ = hex_digits[uuid.b[i] & 0x0f];
126+
if (i == 3 || i == 5 || i == 7 || i == 9)
127+
*p++ = '-';
128+
}
129+
*p = '\0';
130+
#endif
131+
return uuid_str;
132+
}
133+
105134
static void show_nvme_id_ctrl_cmic(__u8 cmic)
106135
{
107136
__u8 rsvd = (cmic & 0xF0) >> 4;
@@ -155,19 +184,29 @@ static void show_nvme_id_ctrl_oaes(__le32 ctrl_oaes)
155184
static void show_nvme_id_ctrl_ctratt(__le32 ctrl_ctratt)
156185
{
157186
__u32 ctratt = le32_to_cpu(ctrl_ctratt);
158-
__u32 rsvd0 = ctratt >> 8;
187+
__u32 rsvd = ctratt >> 10;
159188
__u32 hostid128 = (ctratt & NVME_CTRL_CTRATT_128_ID) >> 0;
160189
__u32 psp = (ctratt & NVME_CTRL_CTRATT_NON_OP_PSP) >> 1;
161190
__u32 sets = (ctratt & NVME_CTRL_CTRATT_NVM_SETS) >> 2;
162191
__u32 rrl = (ctratt & NVME_CTRL_CTRATT_READ_RECV_LVLS) >> 3;
163192
__u32 eg = (ctratt & NVME_CTRL_CTRATT_ENDURANCE_GROUPS) >> 4;
164193
__u32 iod = (ctratt & NVME_CTRL_CTRATT_PREDICTABLE_LAT) >> 5;
165194
__u32 ng = (ctratt & NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY) >> 7;
195+
__u32 uuidlist = (ctratt & NVME_CTRL_CTRATT_UUID_LIST) >> 9;
196+
__u32 rsvd6 = (ctratt & 0x00000040) >> 6;
197+
__u32 rsvd8 = (ctratt & 0x00000100) >> 8;
166198

167-
if (rsvd0)
168-
printf(" [31:8] : %#x\tReserved\n", rsvd0);
199+
if (rsvd)
200+
printf(" [31:10] : %#x\tReserved\n", rsvd);
201+
202+
printf(" [9:9] : %#x\tUUID List %sSupported\n",
203+
uuidlist, uuidlist ? "" : "Not ");
204+
if (rsvd8)
205+
printf(" [8:8] : %#x\tReserved\n", rsvd8);
169206
printf(" [7:7] : %#x\tNamespace Granularity %sSupported\n",
170207
ng, ng ? "" : "Not ");
208+
if (rsvd6)
209+
printf(" [6:6] : %#x\tReserved\n", rsvd6);
171210
printf(" [5:5] : %#x\tPredictable Latency Mode %sSupported\n",
172211
iod, iod ? "" : "Not ");
173212
printf(" [4:4] : %#x\tEndurance Groups %sSupported\n",
@@ -1316,6 +1355,69 @@ void json_nvme_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *
13161355
json_free_object(root);
13171356
}
13181357

1358+
void show_nvme_id_uuid_list(const struct nvme_id_uuid_list *uuid_list, unsigned int flags)
1359+
{
1360+
int i, human = flags & HUMAN;
1361+
/* The 0th entry is reserved */
1362+
for (i = 1; i < NVME_MAX_UUID_ENTRIES; i++) {
1363+
uuid_t uuid;
1364+
char *association = "";
1365+
uint8_t identifier_association = uuid_list->entry[i].header & 0x3;
1366+
/* The list is terminated by a zero UUID value */
1367+
if (memcmp(uuid_list->entry[i].uuid, zero_uuid, sizeof(zero_uuid)) == 0)
1368+
break;
1369+
memcpy(&uuid, uuid_list->entry[i].uuid, sizeof(uuid));
1370+
if (human) {
1371+
switch (identifier_association) {
1372+
case 0x0:
1373+
association = "No association reported";
1374+
break;
1375+
case 0x1:
1376+
association = "associated with PCI Vendor ID";
1377+
break;
1378+
case 0x2:
1379+
association = "associated with PCI Subsystem Vendor ID";
1380+
break;
1381+
default:
1382+
association = "Reserved";
1383+
break;
1384+
}
1385+
}
1386+
printf(" Entry[%3d]\n", i);
1387+
printf(".................\n");
1388+
printf("association : 0x%x %s\n", identifier_association, association);
1389+
printf("UUID : %s", nvme_uuid_to_string(uuid));
1390+
if (memcmp(uuid_list->entry[i].uuid, invalid_uuid, sizeof(zero_uuid)) == 0)
1391+
printf(" (Invalid UUID)");
1392+
printf("\n.................\n");
1393+
}
1394+
}
1395+
1396+
void json_nvme_id_uuid_list(struct nvme_id_uuid_list *uuid_list)
1397+
{
1398+
struct json_object *root;
1399+
struct json_array *entries;
1400+
int i;
1401+
root = json_create_object();
1402+
entries = json_create_array();
1403+
/* The 0th entry is reserved */
1404+
for (i = 1; i < NVME_MAX_UUID_ENTRIES; i++) {
1405+
uuid_t uuid;
1406+
struct json_object *entry = json_create_object();
1407+
/* The list is terminated by a zero UUID value */
1408+
if (memcmp(uuid_list->entry[i].uuid, zero_uuid, sizeof(zero_uuid)) == 0)
1409+
break;
1410+
memcpy(&uuid, uuid_list->entry[i].uuid, sizeof(uuid));
1411+
json_object_add_value_int(entry, "association", uuid_list->entry[i].header & 0x3);
1412+
json_object_add_value_string(entry, "uuid", nvme_uuid_to_string(uuid));
1413+
json_array_add_value_object(entries, entry);
1414+
}
1415+
json_object_add_value_array(root, "UUID-list", entries);
1416+
json_print_object(root, NULL);
1417+
printf("\n");
1418+
json_free_object(root);
1419+
}
1420+
13191421
void show_error_log(struct nvme_error_log_page *err_log, int entries, const char *devname)
13201422
{
13211423
int i;
@@ -1439,6 +1541,7 @@ static void show_effects_log_human(__u32 effect)
14391541
printf(" NCC%s", (effect & NVME_CMD_EFFECTS_NCC) ? set : clr);
14401542
printf(" NIC%s", (effect & NVME_CMD_EFFECTS_NIC) ? set : clr);
14411543
printf(" CCC%s", (effect & NVME_CMD_EFFECTS_CCC) ? set : clr);
1544+
printf(" USS%s", (effect & NVME_CMD_EFFECTS_UUID_SEL) ? set : clr);
14421545

14431546
if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 0)
14441547
printf(" No command restriction\n");

nvme-print.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ void show_nvme_subsystem_list(struct subsys_list_item *slist, int n);
4242
void show_nvme_id_nvmset(struct nvme_id_nvmset *nvmset);
4343
void show_nvme_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list, __u32 count);
4444
void show_nvme_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *granularity, unsigned int flags);
45+
void show_nvme_id_uuid_list(const struct nvme_id_uuid_list *uuid_list, unsigned int flags);
4546

4647
void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf);
4748
void nvme_directive_show_fields(__u8 dtype, __u8 doper, unsigned int result, unsigned char *buf);
@@ -71,4 +72,6 @@ void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset, const char *devname);
7172
void json_ctrl_registers(void *bar);
7273
void json_nvme_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list, __u32 count);
7374
void json_nvme_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *granularity, unsigned int flags);
75+
void json_nvme_id_uuid_list(struct nvme_id_uuid_list *uuid_list);
76+
7477
#endif

nvme.c

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
769769
const char *lpo = "log page offset specifies the location within a log page from where to start returning data";
770770
const char *rae = "retain an asynchronous event";
771771
const char *raw_binary = "output in raw format";
772+
const char *uuid_index = "UUID index";
772773
int err, fd;
773774

774775
struct config {
@@ -778,6 +779,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
778779
__u32 aen;
779780
__u64 lpo;
780781
__u8 lsp;
782+
__u8 uuid_index;
781783
int rae;
782784
int raw_binary;
783785
};
@@ -789,6 +791,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
789791
.lpo = NVME_NO_LOG_LPO,
790792
.lsp = NVME_NO_LOG_LSP,
791793
.rae = 0,
794+
.uuid_index = 0,
792795
};
793796

794797
const struct argconfig_commandline_options command_line_options[] = {
@@ -800,6 +803,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
800803
{"lpo", 'o', "NUM", CFG_LONG, &cfg.lpo, required_argument, lpo},
801804
{"lsp", 's', "NUM", CFG_BYTE, &cfg.lsp, required_argument, lsp},
802805
{"rae", 'r', "", CFG_NONE, &cfg.rae, no_argument, rae},
806+
{"uuid-index", 'U', "NUM", CFG_BYTE, &cfg.uuid_index, required_argument, uuid_index},
803807
{NULL}
804808
};
805809

@@ -834,9 +838,9 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
834838
goto close_fd;
835839
}
836840

837-
err = nvme_get_log13(fd, cfg.namespace_id, cfg.log_id,
841+
err = nvme_get_log14(fd, cfg.namespace_id, cfg.log_id,
838842
cfg.lsp, cfg.lpo, 0, cfg.rae,
839-
cfg.log_len, log);
843+
cfg.uuid_index, cfg.log_len, log);
840844
if (!err) {
841845
if (!cfg.raw_binary) {
842846
printf("Device:%s log-id:%d namespace-id:%#x\n",
@@ -2455,6 +2459,61 @@ static int id_nvmset(int argc, char **argv, struct command *cmd, struct plugin *
24552459
return nvme_status_to_errno(err, false);
24562460
}
24572461

2462+
static int id_uuid(int argc, char **argv, struct command *cmd, struct plugin *plugin)
2463+
{
2464+
const char *desc = "Send an Identify UUID List command to the "\
2465+
"given device, returns list of supported Vendor Specific UUIDs "\
2466+
"in either human-readable or binary format.";
2467+
const char *raw_binary = "show infos in binary format";
2468+
const char *human_readable = "show infos in readable format";
2469+
struct nvme_id_uuid_list uuid_list;
2470+
int err, fmt, fd;
2471+
unsigned int flags = 0;
2472+
struct config {
2473+
int raw_binary;
2474+
int human_readable;
2475+
char *output_format;
2476+
};
2477+
struct config cfg = {
2478+
.output_format = "normal",
2479+
};
2480+
const struct argconfig_commandline_options command_line_options[] = {
2481+
{"raw-binary", 'b', "", CFG_NONE, &cfg.raw_binary, no_argument, raw_binary},
2482+
{"human-readable", 'H', "", CFG_NONE, &cfg.human_readable, no_argument, human_readable},
2483+
{"output-format", 'o', "FMT", CFG_STRING, &cfg.output_format, required_argument, output_format },
2484+
{NULL}
2485+
};
2486+
fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
2487+
if (fd < 0)
2488+
return fd;
2489+
fmt = validate_output_format(cfg.output_format);
2490+
if (fmt < 0) {
2491+
err = fmt;
2492+
goto close_fd;
2493+
}
2494+
if (cfg.raw_binary)
2495+
fmt = BINARY;
2496+
if (cfg.human_readable)
2497+
flags |= HUMAN;
2498+
err = nvme_identify_uuid(fd, &uuid_list);
2499+
if (!err) {
2500+
if (fmt == BINARY)
2501+
d_raw((unsigned char *)&uuid_list, sizeof(uuid_list));
2502+
else if (fmt == JSON)
2503+
json_nvme_id_uuid_list(&uuid_list);
2504+
else {
2505+
printf("NVME Identify UUID:\n");
2506+
show_nvme_id_uuid_list(&uuid_list, flags);
2507+
}
2508+
} else if (err > 0)
2509+
show_nvme_status(err);
2510+
else
2511+
perror("identify UUID list");
2512+
close_fd:
2513+
close(fd);
2514+
return err;
2515+
}
2516+
24582517
static int get_ns_id(int argc, char **argv, struct command *cmd, struct plugin *plugin)
24592518
{
24602519
int err = 0, nsid, fd;
@@ -2616,8 +2675,7 @@ static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struc
26162675
else
26172676
show_nvme_list_secondary_ctrl(sc_list, cfg.num_entries);
26182677
} else if (err > 0)
2619-
fprintf(stderr, "NVMe Status:%s(%x) cntid:%d\n",
2620-
nvme_status_to_string(err), err, cfg.cntid);
2678+
show_nvme_status(err);
26212679
else
26222680
perror("id secondary controller list");
26232681

0 commit comments

Comments
 (0)