xref: /freebsd/sbin/nvmecontrol/nvmecontrol.c (revision d2ce15bd43b3a1dcce08eecbff8d5d359946d972)
1 /*-
2  * Copyright (C) 2012 Intel Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/ioccom.h>
32 #include <sys/stat.h>
33 
34 #include <dev/nvme/nvme.h>
35 
36 #include <ctype.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdbool.h>
40 #include <stddef.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sysexits.h>
45 #include <unistd.h>
46 
47 #define DEVLIST_USAGE							       \
48 "       nvmecontrol devlist\n"
49 
50 #define IDENTIFY_USAGE							       \
51 "       nvmecontrol identify <controller id|namespace id>\n"
52 
53 #define PERFTEST_USAGE							       \
54 "       nvmecontrol perftest <-n num_threads> <-o read|write>\n"	       \
55 "                            <-s size_in_bytes> <-t time_in_seconds>\n"	       \
56 "                            <-i intr|wait> [-f refthread] [-p]\n"	       \
57 "                            <namespace id>\n"
58 
59 #define RESET_USAGE							       \
60 "       nvmecontrol reset <controller id>\n"
61 
62 static void perftest_usage(void);
63 
64 static void
65 usage(void)
66 {
67 	fprintf(stderr, "usage:\n");
68 	fprintf(stderr, DEVLIST_USAGE);
69 	fprintf(stderr, IDENTIFY_USAGE);
70 	fprintf(stderr, RESET_USAGE);
71 	fprintf(stderr, PERFTEST_USAGE);
72 	exit(EX_USAGE);
73 }
74 
75 static void
76 print_controller_hex(struct nvme_controller_data *cdata, uint32_t length)
77 {
78 	uint32_t	*p;
79 	uint32_t	i, j;
80 
81 	p = (uint32_t *)cdata;
82 	length /= sizeof(uint32_t);
83 
84 	for (i = 0; i < length; i+=8) {
85 		printf("%03x: ", i*4);
86 		for (j = 0; j < 8; j++)
87 			printf("%08x ", p[i+j]);
88 		printf("\n");
89 	}
90 
91 	printf("\n");
92 }
93 
94 static void
95 print_controller(struct nvme_controller_data *cdata)
96 {
97 	printf("Controller Capabilities/Features\n");
98 	printf("================================\n");
99 	printf("Vendor ID:                  %04x\n", cdata->vid);
100 	printf("Subsystem Vendor ID:        %04x\n", cdata->ssvid);
101 	printf("Serial Number:              %s\n", cdata->sn);
102 	printf("Model Number:               %s\n", cdata->mn);
103 	printf("Firmware Version:           %s\n", cdata->fr);
104 	printf("Recommended Arb Burst:      %d\n", cdata->rab);
105 	printf("IEEE OUI Identifier:        %02x %02x %02x\n",
106 		cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
107 	printf("Multi-Interface Cap:        %02x\n", cdata->mic);
108 	/* TODO: Use CAP.MPSMIN to determine true memory page size. */
109 	printf("Max Data Transfer Size:     ");
110 	if (cdata->mdts == 0)
111 		printf("Unlimited\n");
112 	else
113 		printf("%d\n", PAGE_SIZE * (1 << cdata->mdts));
114 	printf("\n");
115 
116 	printf("Admin Command Set Attributes\n");
117 	printf("============================\n");
118 	printf("Security Send/Receive:       %s\n",
119 		cdata->oacs.security ? "Supported" : "Not Supported");
120 	printf("Format NVM:                  %s\n",
121 		cdata->oacs.format ? "Supported" : "Not Supported");
122 	printf("Firmware Activate/Download:  %s\n",
123 		cdata->oacs.firmware ? "Supported" : "Not Supported");
124 	printf("Abort Command Limit:         %d\n", cdata->acl+1);
125 	printf("Async Event Request Limit:   %d\n", cdata->aerl+1);
126 	printf("Number of Firmware Slots:    ");
127 	if (cdata->oacs.firmware != 0)
128 		printf("%d\n", cdata->frmw.num_slots);
129 	else
130 		printf("N/A\n");
131 	printf("Firmware Slot 1 Read-Only:   ");
132 	if (cdata->oacs.firmware != 0)
133 		printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No");
134 	else
135 		printf("N/A\n");
136 	printf("Per-Namespace SMART Log:     %s\n",
137 		cdata->lpa.ns_smart ? "Yes" : "No");
138 	printf("Error Log Page Entries:      %d\n", cdata->elpe+1);
139 	printf("Number of Power States:      %d\n", cdata->npss+1);
140 	printf("\n");
141 
142 	printf("NVM Command Set Attributes\n");
143 	printf("==========================\n");
144 	printf("Submission Queue Entry Size\n");
145 	printf("  Max:                       %d\n", 1 << cdata->sqes.max);
146 	printf("  Min:                       %d\n", 1 << cdata->sqes.min);
147 	printf("Completion Queue Entry Size\n");
148 	printf("  Max:                       %d\n", 1 << cdata->cqes.max);
149 	printf("  Min:                       %d\n", 1 << cdata->cqes.min);
150 	printf("Number of Namespaces:        %d\n", cdata->nn);
151 	printf("Compare Command:             %s\n",
152 		cdata->oncs.compare ? "Supported" : "Not Supported");
153 	printf("Write Uncorrectable Command: %s\n",
154 		cdata->oncs.write_unc ? "Supported" : "Not Supported");
155 	printf("Dataset Management Command:  %s\n",
156 		cdata->oncs.dsm ? "Supported" : "Not Supported");
157 	printf("Volatile Write Cache:        %s\n",
158 		cdata->vwc.present ? "Present" : "Not Present");
159 }
160 
161 static void
162 print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length)
163 {
164 	uint32_t	*p;
165 	uint32_t	i, j;
166 
167 	p = (uint32_t *)nsdata;
168 	length /= sizeof(uint32_t);
169 
170 	for (i = 0; i < length; i+=8) {
171 		printf("%03x: ", i*4);
172 		for (j = 0; j < 8; j++)
173 			printf("%08x ", p[i+j]);
174 		printf("\n");
175 	}
176 
177 	printf("\n");
178 }
179 
180 static void
181 print_namespace(struct nvme_namespace_data *nsdata)
182 {
183 	uint32_t	i;
184 
185 	printf("Size (in LBAs):              %lld (%lldM)\n",
186 		(long long)nsdata->nsze,
187 		(long long)nsdata->nsze / 1024 / 1024);
188 	printf("Capacity (in LBAs):          %lld (%lldM)\n",
189 		(long long)nsdata->ncap,
190 		(long long)nsdata->ncap / 1024 / 1024);
191 	printf("Utilization (in LBAs):       %lld (%lldM)\n",
192 		(long long)nsdata->nuse,
193 		(long long)nsdata->nuse / 1024 / 1024);
194 	printf("Thin Provisioning:           %s\n",
195 		nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported");
196 	printf("Number of LBA Formats:       %d\n", nsdata->nlbaf+1);
197 	printf("Current LBA Format:          LBA Format #%d\n",
198 		nsdata->flbas.format);
199 	for (i = 0; i <= nsdata->nlbaf; i++) {
200 		printf("LBA Format #%d:\n", i);
201 		printf("  LBA Data Size:             %d\n",
202 			1 << nsdata->lbaf[i].lbads);
203 	}
204 }
205 
206 static uint32_t
207 ns_get_sector_size(struct nvme_namespace_data *nsdata)
208 {
209 
210 	return (1 << nsdata->lbaf[0].lbads);
211 }
212 
213 
214 static void
215 devlist(int argc, char *argv[])
216 {
217 	struct nvme_controller_data	cdata;
218 	struct nvme_namespace_data	nsdata;
219 	struct stat			devstat;
220 	char				name[64], path[64];
221 	uint32_t			i;
222 	int				ch, ctrlr, exit_code, fd, found;
223 
224 	exit_code = EX_OK;
225 
226 	while ((ch = getopt(argc, argv, "")) != -1) {
227 		switch ((char)ch) {
228 		default:
229 			usage();
230 		}
231 	}
232 
233 	ctrlr = -1;
234 	found = 0;
235 
236 	while (1) {
237 		ctrlr++;
238 		sprintf(name, "nvme%d", ctrlr);
239 		sprintf(path, "/dev/%s", name);
240 
241 		if (stat(path, &devstat) != 0)
242 			break;
243 
244 		found++;
245 
246 		fd = open(path, O_RDWR);
247 		if (fd < 0) {
248 			printf("Could not open %s. errno=%d (%s)\n", path,
249 			    errno, strerror(errno));
250 			exit_code = EX_NOPERM;
251 			continue;
252 		}
253 
254 		if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) < 0) {
255 			printf("Identify request to %s failed. errno=%d (%s)\n",
256 			    path, errno, strerror(errno));
257 			exit_code = EX_IOERR;
258 			continue;
259 		}
260 
261 		printf("%6s: %s\n", name, cdata.mn);
262 
263 		for (i = 0; i < cdata.nn; i++) {
264 			sprintf(name, "nvme%dns%d", ctrlr, i+1);
265 			sprintf(path, "/dev/%s", name);
266 
267 			fd = open(path, O_RDWR);
268 			if (fd < 0) {
269 				printf("Could not open %s. errno=%d (%s)\n",
270 				    path, errno, strerror(errno));
271 				exit_code = EX_NOPERM;
272 				continue;
273 			}
274 			if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) < 0) {
275 				printf("Identify request to %s failed. "
276 				    "errno=%d (%s)\n", path, errno,
277 				    strerror(errno));
278 				exit_code = EX_IOERR;
279 				continue;
280 			}
281 			printf("  %10s (%lldGB)\n",
282 				name,
283 				nsdata.nsze *
284 				(long long)ns_get_sector_size(&nsdata) /
285 				1024 / 1024 / 1024);
286 		}
287 	}
288 
289 	if (found == 0)
290 		printf("No NVMe controllers found.\n");
291 
292 	exit(exit_code);
293 }
294 
295 static void
296 identify_ctrlr(int argc, char *argv[])
297 {
298 	struct nvme_controller_data	cdata;
299 	struct stat			devstat;
300 	char				path[64];
301 	int				ch, fd, hexflag = 0, hexlength;
302 	int				verboseflag = 0;
303 
304 	while ((ch = getopt(argc, argv, "vx")) != -1) {
305 		switch ((char)ch) {
306 		case 'v':
307 			verboseflag = 1;
308 			break;
309 		case 'x':
310 			hexflag = 1;
311 			break;
312 		default:
313 			usage();
314 		}
315 	}
316 
317 	sprintf(path, "/dev/%s", argv[optind]);
318 
319 	if (stat(path, &devstat) < 0) {
320 		printf("Invalid device node %s. errno=%d (%s)\n", path, errno,
321 		    strerror(errno));
322 		exit(EX_IOERR);
323 	}
324 
325 	fd = open(path, O_RDWR);
326 	if (fd < 0) {
327 		printf("Could not open %s. errno=%d (%s)\n", path, errno,
328 		    strerror(errno));
329 		exit(EX_NOPERM);
330 	}
331 
332 	if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) < 0) {
333 		printf("Identify request to %s failed. errno=%d (%s)\n", path,
334 		    errno, strerror(errno));
335 		exit(EX_IOERR);
336 	}
337 
338 	if (hexflag == 1) {
339 		if (verboseflag == 1)
340 			hexlength = sizeof(struct nvme_controller_data);
341 		else
342 			hexlength = offsetof(struct nvme_controller_data,
343 			    reserved5);
344 		print_controller_hex(&cdata, hexlength);
345 		exit(EX_OK);
346 	}
347 
348 	if (verboseflag == 1) {
349 		printf("-v not currently supported without -x.\n");
350 		usage();
351 	}
352 
353 	print_controller(&cdata);
354 	exit(EX_OK);
355 }
356 
357 static void
358 identify_ns(int argc, char *argv[])
359 {
360 	struct nvme_namespace_data	nsdata;
361 	struct stat			devstat;
362 	char				path[64];
363 	int				ch, fd, hexflag = 0, hexlength;
364 	int				verboseflag = 0;
365 
366 	while ((ch = getopt(argc, argv, "vx")) != -1) {
367 		switch ((char)ch) {
368 		case 'v':
369 			verboseflag = 1;
370 			break;
371 		case 'x':
372 			hexflag = 1;
373 			break;
374 		default:
375 			usage();
376 		}
377 	}
378 
379 	sprintf(path, "/dev/%s", argv[optind]);
380 
381 	if (stat(path, &devstat) < 0) {
382 		printf("Invalid device node %s. errno=%d (%s)\n", path, errno,
383 		    strerror(errno));
384 		exit(EX_IOERR);
385 	}
386 
387 	fd = open(path, O_RDWR);
388 	if (fd < 0) {
389 		printf("Could not open %s. errno=%d (%s)\n", path, errno,
390 		    strerror(errno));
391 		exit(EX_NOPERM);
392 	}
393 
394 	if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) < 0) {
395 		printf("Identify request to %s failed. errno=%d (%s)\n", path,
396 		    errno, strerror(errno));
397 		exit(EX_IOERR);
398 	}
399 
400 	if (hexflag == 1) {
401 		if (verboseflag == 1)
402 			hexlength = sizeof(struct nvme_namespace_data);
403 		else
404 			hexlength = offsetof(struct nvme_namespace_data,
405 			    reserved6);
406 		print_namespace_hex(&nsdata, hexlength);
407 		exit(EX_OK);
408 	}
409 
410 	if (verboseflag == 1) {
411 		printf("-v not currently supported without -x.\n");
412 		usage();
413 	}
414 
415 	print_namespace(&nsdata);
416 	exit(EX_OK);
417 }
418 
419 static void
420 identify(int argc, char *argv[])
421 {
422 	char	*target;
423 
424 	if (argc < 2)
425 		usage();
426 
427 	while (getopt(argc, argv, "vx") != -1) ;
428 
429 	target = argv[optind];
430 
431 	/* Specified device node must have "nvme" in it. */
432 	if (strstr(argv[optind], "nvme") == NULL) {
433 		printf("Invalid device node '%s'.\n", argv[optind]);
434 		exit(EX_IOERR);
435 	}
436 
437 	optreset = 1;
438 	optind = 1;
439 
440 	/*
441 	 * If device node contains "ns", we consider it a namespace,
442 	 *  otherwise, consider it a controller.
443 	 */
444 	if (strstr(target, "ns") == NULL)
445 		identify_ctrlr(argc, argv);
446 	else
447 		identify_ns(argc, argv);
448 }
449 
450 static void
451 print_perftest(struct nvme_io_test *io_test, bool perthread)
452 {
453 	uint32_t i, io_completed = 0, iops, mbps;
454 
455 	for (i = 0; i < io_test->num_threads; i++)
456 		io_completed += io_test->io_completed[i];
457 
458 	iops = io_completed/io_test->time;
459 	mbps = iops * io_test->size / (1024*1024);
460 
461 	printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n",
462 	    io_test->num_threads, io_test->size,
463 	    io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
464 	    io_test->time, iops, mbps);
465 
466 	if (perthread)
467 		for (i = 0; i < io_test->num_threads; i++)
468 			printf("\t%3d: %8d IO/s\n", i,
469 			    io_test->io_completed[i]/io_test->time);
470 
471 	exit(1);
472 }
473 
474 static void
475 perftest_usage(void)
476 {
477 	fprintf(stderr, "usage:\n");
478 	fprintf(stderr, PERFTEST_USAGE);
479 	exit(EX_USAGE);
480 }
481 
482 static void
483 perftest(int argc, char *argv[])
484 {
485 	struct nvme_io_test		io_test;
486 	int				fd;
487 	char				ch;
488 	char				*p;
489 	const char			*name;
490 	char				path[64];
491 	u_long				ioctl_cmd = NVME_IO_TEST;
492 	bool				nflag, oflag, sflag, tflag;
493 	int				perthread = 0;
494 
495 	nflag = oflag = sflag = tflag = false;
496 	name = NULL;
497 
498 	memset(&io_test, 0, sizeof(io_test));
499 
500 	while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) {
501 		switch (ch) {
502 		case 'f':
503 			if (!strcmp(optarg, "refthread"))
504 				io_test.flags |= NVME_TEST_FLAG_REFTHREAD;
505 			break;
506 		case 'i':
507 			if (!strcmp(optarg, "bio") ||
508 			    !strcmp(optarg, "wait"))
509 				ioctl_cmd = NVME_BIO_TEST;
510 			else if (!strcmp(optarg, "io") ||
511 				 !strcmp(optarg, "intr"))
512 				ioctl_cmd = NVME_IO_TEST;
513 			break;
514 		case 'n':
515 			nflag = true;
516 			io_test.num_threads = strtoul(optarg, &p, 0);
517 			if (p != NULL && *p != '\0') {
518 				fprintf(stderr,
519 				    "\"%s\" not valid number of threads.\n",
520 				    optarg);
521 				perftest_usage();
522 			} else if (io_test.num_threads == 0 ||
523 				   io_test.num_threads > 128) {
524 				fprintf(stderr,
525 				    "\"%s\" not valid number of threads.\n",
526 				    optarg);
527 				perftest_usage();
528 			}
529 			break;
530 		case 'o':
531 			oflag = true;
532 			if (!strcmp(optarg, "read") || !strcmp(optarg, "READ"))
533 				io_test.opc = NVME_OPC_READ;
534 			else if (!strcmp(optarg, "write") ||
535 				 !strcmp(optarg, "WRITE"))
536 				io_test.opc = NVME_OPC_WRITE;
537 			else {
538 				fprintf(stderr, "\"%s\" not valid opcode.\n",
539 				    optarg);
540 				perftest_usage();
541 			}
542 			break;
543 		case 'p':
544 			perthread = 1;
545 			break;
546 		case 's':
547 			sflag = true;
548 			io_test.size = strtoul(optarg, &p, 0);
549 			if (p == NULL || *p == '\0' || toupper(*p) == 'B') {
550 				// do nothing
551 			} else if (toupper(*p) == 'K') {
552 				io_test.size *= 1024;
553 			} else if (toupper(*p) == 'M') {
554 				io_test.size *= 1024 * 1024;
555 			} else {
556 				fprintf(stderr, "\"%s\" not valid size.\n",
557 				    optarg);
558 				perftest_usage();
559 			}
560 			break;
561 		case 't':
562 			tflag = true;
563 			io_test.time = strtoul(optarg, &p, 0);
564 			if (p != NULL && *p != '\0') {
565 				fprintf(stderr,
566 				    "\"%s\" not valid time duration.\n",
567 				    optarg);
568 				perftest_usage();
569 			}
570 			break;
571 		}
572 	}
573 
574 	name = argv[optind];
575 
576 	if (!nflag || !oflag || !sflag || !tflag || name == NULL)
577 		perftest_usage();
578 
579 	sprintf(path, "/dev/%s", name);
580 
581 	fd = open(path, O_RDWR);
582 	if (fd < 0) {
583 		fprintf(stderr, "%s not valid device. errno=%d (%s)\n", path,
584 		    errno, strerror(errno));
585 		perftest_usage();
586 	}
587 
588 	if (ioctl(fd, ioctl_cmd, &io_test) < 0) {
589 		fprintf(stderr, "NVME_IO_TEST failed. errno=%d (%s)\n", errno,
590 		    strerror(errno));
591 		exit(EX_IOERR);
592 	}
593 
594 	print_perftest(&io_test, perthread);
595 	exit(EX_OK);
596 }
597 
598 static void
599 reset_ctrlr(int argc, char *argv[])
600 {
601 	struct stat			devstat;
602 	char				path[64];
603 	int				ch, fd;
604 
605 	while ((ch = getopt(argc, argv, "")) != -1) {
606 		switch ((char)ch) {
607 		default:
608 			usage();
609 		}
610 	}
611 
612 	sprintf(path, "/dev/%s", argv[optind]);
613 
614 	if (stat(path, &devstat) < 0) {
615 		printf("Invalid device node %s. errno=%d (%s)\n", path, errno,
616 		    strerror(errno));
617 		exit(EX_IOERR);
618 	}
619 
620 	fd = open(path, O_RDWR);
621 	if (fd < 0) {
622 		printf("Could not open %s. errno=%d (%s)\n", path, errno,
623 		    strerror(errno));
624 		exit(EX_NOPERM);
625 	}
626 
627 	if (ioctl(fd, NVME_RESET_CONTROLLER) < 0) {
628 		printf("Reset request to %s failed. errno=%d (%s)\n", path,
629 		    errno, strerror(errno));
630 		exit(EX_IOERR);
631 	}
632 
633 	exit(EX_OK);
634 }
635 
636 int
637 main(int argc, char *argv[])
638 {
639 
640 	if (argc < 2)
641 		usage();
642 
643 	if (strcmp(argv[1], "devlist") == 0)
644 		devlist(argc-1, &argv[1]);
645 	else if (strcmp(argv[1], "identify") == 0)
646 		identify(argc-1, &argv[1]);
647 	else if (strcmp(argv[1], "perftest") == 0)
648 		perftest(argc-1, &argv[1]);
649 	else if (strcmp(argv[1], "reset") == 0)
650 		reset_ctrlr(argc-1, &argv[1]);
651 
652 	usage();
653 
654 	return (0);
655 }
656