Skip to content

Commit b6864e7

Browse files
authored
Merge pull request #392 from CodeConstruct/mi+admin
MI: add further admin commands
2 parents 1689b69 + 08a7352 commit b6864e7

4 files changed

Lines changed: 574 additions & 1 deletion

File tree

examples/mi-mctp.c

Lines changed: 291 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212

1313
#include <assert.h>
14+
#include <ctype.h>
1415
#include <err.h>
1516
#include <stdio.h>
1617
#include <stdlib.h>
@@ -240,10 +241,280 @@ int do_identify(nvme_mi_ep_t ep, int argc, char **argv)
240241
return 0;
241242
}
242243

244+
void fhexdump(FILE *fp, const unsigned char *buf, int len)
245+
{
246+
const int row_len = 16;
247+
int i, j;
248+
249+
for (i = 0; i < len; i += row_len) {
250+
char hbuf[row_len * strlen("00 ") + 1];
251+
char cbuf[row_len + strlen("|") + 1];
252+
253+
for (j = 0; (j < row_len) && ((i+j) < len); j++) {
254+
unsigned char c = buf[i + j];
255+
256+
sprintf(hbuf + j * 3, "%02x ", c);
257+
258+
if (!isprint(c))
259+
c = '.';
260+
261+
sprintf(cbuf + j, "%c", c);
262+
}
263+
264+
strcat(cbuf, "|");
265+
266+
fprintf(fp, "%08x %*s |%s\n", i,
267+
0 - (int)sizeof(hbuf) + 1, hbuf, cbuf);
268+
}
269+
}
270+
271+
void hexdump(const unsigned char *buf, int len)
272+
{
273+
fhexdump(stdout, buf, len);
274+
}
275+
276+
int do_get_log_page(nvme_mi_ep_t ep, int argc, char **argv)
277+
{
278+
struct nvme_get_log_args args = { 0 };
279+
struct nvme_mi_ctrl *ctrl;
280+
uint8_t buf[512];
281+
uint16_t ctrl_id;
282+
int rc, tmp;
283+
284+
if (argc < 2) {
285+
fprintf(stderr, "no controller ID specified\n");
286+
return -1;
287+
}
288+
289+
tmp = atoi(argv[1]);
290+
if (tmp < 0 || tmp > 0xffff) {
291+
fprintf(stderr, "invalid controller ID\n");
292+
return -1;
293+
}
294+
295+
ctrl_id = tmp & 0xffff;
296+
297+
args.args_size = sizeof(args);
298+
args.log = buf;
299+
args.len = sizeof(buf);
300+
301+
if (argc > 2) {
302+
tmp = atoi(argv[2]);
303+
args.lid = tmp & 0xff;
304+
} else {
305+
args.lid = 0x1;
306+
}
307+
308+
ctrl = nvme_mi_init_ctrl(ep, ctrl_id);
309+
if (!ctrl) {
310+
warn("can't create controller");
311+
return -1;
312+
}
313+
314+
rc = nvme_mi_admin_get_log_page(ctrl, &args);
315+
if (rc) {
316+
warn("can't perform Get Log page command");
317+
return -1;
318+
}
319+
320+
printf("Get log page (log id = 0x%02x) data:\n", args.lid);
321+
hexdump(buf, args.len);
322+
323+
return 0;
324+
}
325+
326+
int do_admin_raw(nvme_mi_ep_t ep, int argc, char **argv)
327+
{
328+
struct nvme_mi_admin_req_hdr req;
329+
struct nvme_mi_admin_resp_hdr *resp;
330+
struct nvme_mi_ctrl *ctrl;
331+
size_t resp_data_len;
332+
unsigned long tmp;
333+
uint8_t buf[512];
334+
uint16_t ctrl_id;
335+
uint8_t opcode;
336+
__le32 *cdw;
337+
int i, rc;
338+
339+
if (argc < 2) {
340+
fprintf(stderr, "no controller ID specified\n");
341+
return -1;
342+
}
343+
344+
if (argc < 3) {
345+
fprintf(stderr, "no opcode specified\n");
346+
return -1;
347+
}
348+
349+
tmp = atoi(argv[1]);
350+
if (tmp < 0 || tmp > 0xffff) {
351+
fprintf(stderr, "invalid controller ID\n");
352+
return -1;
353+
}
354+
ctrl_id = tmp & 0xffff;
355+
356+
tmp = atoi(argv[2]);
357+
if (tmp < 0 || tmp > 0xff) {
358+
fprintf(stderr, "invalid opcode\n");
359+
return -1;
360+
}
361+
opcode = tmp & 0xff;
362+
363+
memset(&req, 0, sizeof(req));
364+
req.opcode = opcode;
365+
req.ctrl_id = cpu_to_le16(ctrl_id);
366+
367+
/* The cdw10 - cdw16 fields are contiguous in req; set from argv. */
368+
cdw = (void *)&req + offsetof(typeof(req), cdw10);
369+
for (i = 0; i < 6; i++) {
370+
if (argc >= 4 + i)
371+
tmp = strtoul(argv[3 + i], NULL, 0);
372+
else
373+
tmp = 0;
374+
*cdw = cpu_to_le32(tmp & 0xffffffff);
375+
cdw++;
376+
}
377+
378+
printf("Admin request:\n");
379+
printf(" opcode: 0x%02x\n", req.opcode);
380+
printf(" ctrl: 0x%04x\n", le16_to_cpu(req.ctrl_id));
381+
printf(" cdw10: 0x%08x\n", le32_to_cpu(req.cdw10));
382+
printf(" cdw11: 0x%08x\n", le32_to_cpu(req.cdw11));
383+
printf(" cdw12: 0x%08x\n", le32_to_cpu(req.cdw12));
384+
printf(" cdw13: 0x%08x\n", le32_to_cpu(req.cdw13));
385+
printf(" cdw14: 0x%08x\n", le32_to_cpu(req.cdw14));
386+
printf(" cdw15: 0x%08x\n", le32_to_cpu(req.cdw15));
387+
printf(" raw:\n");
388+
hexdump((void *)&req, sizeof(req));
389+
390+
memset(buf, 0, sizeof(buf));
391+
resp = (void *)buf;
392+
393+
ctrl = nvme_mi_init_ctrl(ep, ctrl_id);
394+
if (!ctrl) {
395+
warn("can't create controller");
396+
return -1;
397+
}
398+
399+
resp_data_len = sizeof(buf) - sizeof(*resp);
400+
401+
rc = nvme_mi_admin_xfer(ctrl, &req, 0, resp, 0, &resp_data_len);
402+
if (rc) {
403+
warn("nvme_admin_xfer failed: %d", rc);
404+
return -1;
405+
}
406+
407+
printf("Admin response:\n");
408+
printf(" Status: 0x%02x\n", resp->status);
409+
printf(" cdw0: 0x%08x\n", le32_to_cpu(resp->cdw0));
410+
printf(" cdw1: 0x%08x\n", le32_to_cpu(resp->cdw1));
411+
printf(" cdw3: 0x%08x\n", le32_to_cpu(resp->cdw3));
412+
printf(" data [%zd bytes]\n", resp_data_len);
413+
414+
hexdump(buf + sizeof(*resp), resp_data_len);
415+
return 0;
416+
}
417+
418+
static struct {
419+
uint8_t id;
420+
const char *name;
421+
} sec_protos[] = {
422+
{ 0x00, "Security protocol information" },
423+
{ 0xea, "NVMe" },
424+
{ 0xec, "JEDEC Universal Flash Storage" },
425+
{ 0xed, "SDCard TrustedFlash Security" },
426+
{ 0xee, "IEEE 1667" },
427+
{ 0xef, "ATA Device Server Password Security" },
428+
};
429+
430+
static const char *sec_proto_description(uint8_t id)
431+
{
432+
unsigned int i;
433+
434+
for (i = 0; i < ARRAY_SIZE(sec_protos); i++) {
435+
if (sec_protos[i].id == id)
436+
return sec_protos[i].name;
437+
}
438+
439+
if (id >= 0xf0)
440+
return "Vendor specific";
441+
442+
return "unknown";
443+
}
444+
445+
int do_security_info(nvme_mi_ep_t ep, int argc, char **argv)
446+
{
447+
struct nvme_security_receive_args args = { 0 };
448+
nvme_mi_ctrl_t ctrl;
449+
int i, rc, n_proto;
450+
unsigned long tmp;
451+
uint16_t ctrl_id;
452+
struct {
453+
uint8_t rsvd[6];
454+
uint16_t len;
455+
uint8_t protocols[256];
456+
} proto_info;
457+
458+
if (argc != 2) {
459+
fprintf(stderr, "no controller ID specified\n");
460+
return -1;
461+
}
462+
463+
tmp = atoi(argv[1]);
464+
if (tmp < 0 || tmp > 0xffff) {
465+
fprintf(stderr, "invalid controller ID\n");
466+
return -1;
467+
}
468+
469+
ctrl_id = tmp & 0xffff;
470+
471+
ctrl = nvme_mi_init_ctrl(ep, ctrl_id);
472+
if (!ctrl) {
473+
warn("can't create controller");
474+
return -1;
475+
}
476+
477+
/* protocol 0x00, spsp 0x0000: retrieve supported protocols */
478+
args.args_size = sizeof(args);
479+
args.data = &proto_info;
480+
args.data_len = sizeof(proto_info);
481+
482+
rc = nvme_mi_admin_security_recv(ctrl, &args);
483+
if (rc) {
484+
warnx("can't perform Security Receive command: rc %d", rc);
485+
return -1;
486+
}
487+
488+
if (args.data_len < 6) {
489+
warnx("Short response in security receive command (%d bytes)",
490+
args.data_len);
491+
return -1;
492+
}
493+
494+
n_proto = be16_to_cpu(proto_info.len);
495+
if (args.data_len < 6 + n_proto) {
496+
warnx("Short response in security receive command (%d bytes), "
497+
"for %d protocols", args.data_len, n_proto);
498+
return -1;
499+
}
500+
501+
printf("Supported protocols:\n");
502+
for (i = 0; i < n_proto; i++) {
503+
uint8_t id = proto_info.protocols[i];
504+
printf(" 0x%02x: %s\n", id, sec_proto_description(id));
505+
}
506+
507+
return 0;
508+
}
509+
510+
243511
enum action {
244512
ACTION_INFO,
245513
ACTION_CONTROLLERS,
246514
ACTION_IDENTIFY,
515+
ACTION_GET_LOG_PAGE,
516+
ACTION_ADMIN_RAW,
517+
ACTION_SECURITY_INFO,
247518
};
248519

249520
int main(int argc, char **argv)
@@ -261,7 +532,11 @@ int main(int argc, char **argv)
261532
fprintf(stderr, "where action is:\n"
262533
" info\n"
263534
" controllers\n"
264-
" identify <controller-id> [--partial]\n");
535+
" identify <controller-id> [--partial]\n"
536+
" get-log-page <controller-id> [<log-id>]\n"
537+
" admin <controller-id> <opcode> [<cdw10>, <cdw11>, ...]\n"
538+
" security-info <controller-id>\n"
539+
);
265540
return EXIT_FAILURE;
266541
}
267542

@@ -283,6 +558,12 @@ int main(int argc, char **argv)
283558
action = ACTION_CONTROLLERS;
284559
} else if (!strcmp(action_str, "identify")) {
285560
action = ACTION_IDENTIFY;
561+
} else if (!strcmp(action_str, "get-log-page")) {
562+
action = ACTION_GET_LOG_PAGE;
563+
} else if (!strcmp(action_str, "admin")) {
564+
action = ACTION_ADMIN_RAW;
565+
} else if (!strcmp(action_str, "security-info")) {
566+
action = ACTION_SECURITY_INFO;
286567
} else {
287568
fprintf(stderr, "invalid action '%s'\n", action_str);
288569
return EXIT_FAILURE;
@@ -307,6 +588,15 @@ int main(int argc, char **argv)
307588
case ACTION_IDENTIFY:
308589
rc = do_identify(ep, argc, argv);
309590
break;
591+
case ACTION_GET_LOG_PAGE:
592+
rc = do_get_log_page(ep, argc, argv);
593+
break;
594+
case ACTION_ADMIN_RAW:
595+
rc = do_admin_raw(ep, argc, argv);
596+
break;
597+
case ACTION_SECURITY_INFO:
598+
rc = do_security_info(ep, argc, argv);
599+
break;
310600
}
311601

312602
nvme_mi_close(ep);

src/libnvme-mi.map

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ LIBNVME_MI_1_1 {
1111
nvme_mi_mi_read_mi_data_ctrl;
1212
nvme_mi_mi_subsystem_health_status_poll;
1313
nvme_mi_admin_identify_partial;
14+
nvme_mi_admin_get_log_page;
15+
nvme_mi_admin_xfer;
16+
nvme_mi_admin_security_send;
17+
nvme_mi_admin_security_recv;
1418
nvme_mi_open_mctp;
1519
local:
1620
*;

0 commit comments

Comments
 (0)