xref: /freebsd/sbin/nvmecontrol/nvmecontrol.c (revision c6ec7d31830ab1c80edae95ad5e4b9dba10c47ac)
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 static void perftest_usage(void);
60 
61 static void
62 usage(void)
63 {
64 	fprintf(stderr, "usage:\n");
65 	fprintf(stderr, DEVLIST_USAGE);
66 	fprintf(stderr, IDENTIFY_USAGE);
67 	fprintf(stderr, PERFTEST_USAGE);
68 	exit(EX_USAGE);
69 }
70 
71 static void
72 print_controller_hex(struct nvme_controller_data *cdata, uint32_t length)
73 {
74 	uint32_t	*p;
75 	uint32_t	i, j;
76 
77 	p = (uint32_t *)cdata;
78 	length /= sizeof(uint32_t);
79 
80 	for (i = 0; i < length; i+=8) {
81 		printf("%03x: ", i*4);
82 		for (j = 0; j < 8; j++)
83 			printf("%08x ", p[i+j]);
84 		printf("\n");
85 	}
86 
87 	printf("\n");
88 }
89 
90 static void
91 print_controller(struct nvme_controller_data *cdata)
92 {
93 	printf("Controller Capabilities/Features\n");
94 	printf("================================\n");
95 	printf("Vendor ID:                  %04x\n", cdata->vid);
96 	printf("Subsystem Vendor ID:        %04x\n", cdata->ssvid);
97 	printf("Serial Number:              %s\n", cdata->sn);
98 	printf("Model Number:               %s\n", cdata->mn);
99 	printf("Firmware Version:           %s\n", cdata->fr);
100 	printf("Recommended Arb Burst:      %d\n", cdata->rab);
101 	printf("IEEE OUI Identifier:        %02x %02x %02x\n",
102 		cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
103 	printf("Multi-Interface Cap:        %02x\n", cdata->mic);
104 	/* TODO: Use CAP.MPSMIN to determine true memory page size. */
105 	printf("Max Data Transfer Size:     ");
106 	if (cdata->mdts == 0)
107 		printf("Unlimited\n");
108 	else
109 		printf("%d\n", PAGE_SIZE * (1 << cdata->mdts));
110 	printf("\n");
111 
112 	printf("Admin Command Set Attributes\n");
113 	printf("============================\n");
114 	printf("Security Send/Receive:       %s\n",
115 		cdata->oacs.security ? "Supported" : "Not Supported");
116 	printf("Format NVM:                  %s\n",
117 		cdata->oacs.format ? "Supported" : "Not Supported");
118 	printf("Firmware Activate/Download:  %s\n",
119 		cdata->oacs.firmware ? "Supported" : "Not Supported");
120 	printf("Abort Command Limit:         %d\n", cdata->acl+1);
121 	printf("Async Event Request Limit:   %d\n", cdata->aerl+1);
122 	printf("Number of Firmware Slots:    ");
123 	if (cdata->oacs.firmware != 0)
124 		printf("%d\n", cdata->frmw.num_slots);
125 	else
126 		printf("N/A\n");
127 	printf("Firmware Slot 1 Read-Only:   ");
128 	if (cdata->oacs.firmware != 0)
129 		printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No");
130 	else
131 		printf("N/A\n");
132 	printf("Per-Namespace SMART Log:     %s\n",
133 		cdata->lpa.ns_smart ? "Yes" : "No");
134 	printf("Error Log Page Entries:      %d\n", cdata->elpe+1);
135 	printf("Number of Power States:      %d\n", cdata->npss+1);
136 	printf("\n");
137 
138 	printf("NVM Command Set Attributes\n");
139 	printf("==========================\n");
140 	printf("Submission Queue Entry Size\n");
141 	printf("  Max:                       %d\n", 1 << cdata->sqes.max);
142 	printf("  Min:                       %d\n", 1 << cdata->sqes.min);
143 	printf("Completion Queue Entry Size\n");
144 	printf("  Max:                       %d\n", 1 << cdata->cqes.max);
145 	printf("  Min:                       %d\n", 1 << cdata->cqes.min);
146 	printf("Number of Namespaces:        %d\n", cdata->nn);
147 	printf("Compare Command:             %s\n",
148 		cdata->oncs.compare ? "Supported" : "Not Supported");
149 	printf("Write Uncorrectable Command: %s\n",
150 		cdata->oncs.write_unc ? "Supported" : "Not Supported");
151 	printf("Dataset Management Command:  %s\n",
152 		cdata->oncs.dsm ? "Supported" : "Not Supported");
153 	printf("Volatile Write Cache:        %s\n",
154 		cdata->vwc.present ? "Present" : "Not Present");
155 }
156 
157 static void
158 print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length)
159 {
160 	uint32_t	*p;
161 	uint32_t	i, j;
162 
163 	p = (uint32_t *)nsdata;
164 	length /= sizeof(uint32_t);
165 
166 	for (i = 0; i < length; i+=8) {
167 		printf("%03x: ", i*4);
168 		for (j = 0; j < 8; j++)
169 			printf("%08x ", p[i+j]);
170 		printf("\n");
171 	}
172 
173 	printf("\n");
174 }
175 
176 static void
177 print_namespace(struct nvme_namespace_data *nsdata)
178 {
179 	uint32_t	i;
180 
181 	printf("Size (in LBAs):              %lld (%lldM)\n",
182 		(long long)nsdata->nsze,
183 		(long long)nsdata->nsze / 1024 / 1024);
184 	printf("Capacity (in LBAs):          %lld (%lldM)\n",
185 		(long long)nsdata->ncap,
186 		(long long)nsdata->ncap / 1024 / 1024);
187 	printf("Utilization (in LBAs):       %lld (%lldM)\n",
188 		(long long)nsdata->nuse,
189 		(long long)nsdata->nuse / 1024 / 1024);
190 	printf("Thin Provisioning:           %s\n",
191 		nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported");
192 	printf("Number of LBA Formats:       %d\n", nsdata->nlbaf+1);
193 	printf("Current LBA Format:          LBA Format #%d\n",
194 		nsdata->flbas.format);
195 	for (i = 0; i <= nsdata->nlbaf; i++) {
196 		printf("LBA Format #%d:\n", i);
197 		printf("  LBA Data Size:             %d\n",
198 			1 << nsdata->lbaf[i].lbads);
199 	}
200 }
201 
202 static uint32_t
203 ns_get_sector_size(struct nvme_namespace_data *nsdata)
204 {
205 
206 	return (1 << nsdata->lbaf[0].lbads);
207 }
208 
209 
210 static void
211 devlist(int argc, char *argv[])
212 {
213 	struct nvme_controller_data	cdata;
214 	struct nvme_namespace_data	nsdata;
215 	struct stat			devstat;
216 	char				name[64], path[64];
217 	uint32_t			i;
218 	int				ch, ctrlr, exit_code, fd, found;
219 
220 	exit_code = EX_OK;
221 
222 	while ((ch = getopt(argc, argv, "")) != -1) {
223 		switch ((char)ch) {
224 		default:
225 			usage();
226 		}
227 	}
228 
229 	ctrlr = -1;
230 	found = 0;
231 
232 	while (1) {
233 		ctrlr++;
234 		sprintf(name, "nvme%d", ctrlr);
235 		sprintf(path, "/dev/%s", name);
236 
237 		if (stat(path, &devstat) != 0)
238 			break;
239 
240 		found++;
241 
242 		fd = open(path, O_RDWR);
243 		if (fd < 0) {
244 			printf("Could not open %s.\n", path);
245 			exit_code = EX_NOPERM;
246 			continue;
247 		}
248 
249 		if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) {
250 			printf("ioctl to %s failed.\n", path);
251 			exit_code = EX_IOERR;
252 			continue;
253 		}
254 
255 		printf("%6s: %s\n", name, cdata.mn);
256 
257 		for (i = 0; i < cdata.nn; i++) {
258 			sprintf(name, "nvme%dns%d", ctrlr, i+1);
259 			sprintf(path, "/dev/%s", name);
260 
261 			fd = open(path, O_RDWR);
262 			if (fd < 0) {
263 				printf("Could not open %s.\n", path);
264 				exit_code = EX_NOPERM;
265 				continue;
266 			}
267 			if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) {
268 				printf("ioctl to %s failed.\n", path);
269 				exit_code = EX_IOERR;
270 				continue;
271 			}
272 			printf("  %10s (%lldGB)\n",
273 				name,
274 				nsdata.nsze *
275 				(long long)ns_get_sector_size(&nsdata) /
276 				1024 / 1024 / 1024);
277 		}
278 	}
279 
280 	if (found == 0)
281 		printf("No NVMe controllers found.\n");
282 
283 	exit(exit_code);
284 }
285 
286 static void
287 identify_ctrlr(int argc, char *argv[])
288 {
289 	struct nvme_controller_data	cdata;
290 	struct stat			devstat;
291 	char				path[64];
292 	int				ch, fd, hexflag = 0, hexlength;
293 	int				verboseflag = 0;
294 
295 	while ((ch = getopt(argc, argv, "vx")) != -1) {
296 		switch ((char)ch) {
297 		case 'v':
298 			verboseflag = 1;
299 			break;
300 		case 'x':
301 			hexflag = 1;
302 			break;
303 		default:
304 			usage();
305 		}
306 	}
307 
308 	sprintf(path, "/dev/%s", argv[optind]);
309 
310 	if (stat(path, &devstat) != 0) {
311 		printf("Invalid device node '%s'.\n", path);
312 		exit(EX_IOERR);
313 	}
314 
315 	fd = open(path, O_RDWR);
316 	if (fd < 0) {
317 		printf("Could not open %s.\n", path);
318 		exit(EX_NOPERM);
319 	}
320 
321 	if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) {
322 		printf("ioctl to %s failed.\n", path);
323 		exit(EX_IOERR);
324 	}
325 
326 	if (hexflag == 1) {
327 		if (verboseflag == 1)
328 			hexlength = sizeof(struct nvme_controller_data);
329 		else
330 			hexlength = offsetof(struct nvme_controller_data,
331 			    reserved5);
332 		print_controller_hex(&cdata, hexlength);
333 		exit(EX_OK);
334 	}
335 
336 	if (verboseflag == 1) {
337 		printf("-v not currently supported without -x.\n");
338 		usage();
339 	}
340 
341 	print_controller(&cdata);
342 	exit(EX_OK);
343 }
344 
345 static void
346 identify_ns(int argc, char *argv[])
347 {
348 	struct nvme_namespace_data	nsdata;
349 	struct stat			devstat;
350 	char				path[64];
351 	int				ch, fd, hexflag = 0, hexlength;
352 	int				verboseflag = 0;
353 
354 	while ((ch = getopt(argc, argv, "vx")) != -1) {
355 		switch ((char)ch) {
356 		case 'v':
357 			verboseflag = 1;
358 			break;
359 		case 'x':
360 			hexflag = 1;
361 			break;
362 		default:
363 			usage();
364 		}
365 	}
366 
367 	sprintf(path, "/dev/%s", argv[optind]);
368 
369 	if (stat(path, &devstat) != 0) {
370 		printf("Invalid device node '%s'.\n", path);
371 		exit(EX_IOERR);
372 	}
373 
374 	fd = open(path, O_RDWR);
375 	if (fd < 0) {
376 		printf("Could not open %s.\n", path);
377 		exit(EX_NOPERM);
378 	}
379 
380 	if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) {
381 		printf("ioctl to %s failed.\n", path);
382 		exit(EX_IOERR);
383 	}
384 
385 	if (hexflag == 1) {
386 		if (verboseflag == 1)
387 			hexlength = sizeof(struct nvme_namespace_data);
388 		else
389 			hexlength = offsetof(struct nvme_namespace_data,
390 			    reserved6);
391 		print_namespace_hex(&nsdata, hexlength);
392 		exit(EX_OK);
393 	}
394 
395 	if (verboseflag == 1) {
396 		printf("-v not currently supported without -x.\n");
397 		usage();
398 	}
399 
400 	print_namespace(&nsdata);
401 	exit(EX_OK);
402 }
403 
404 static void
405 identify(int argc, char *argv[])
406 {
407 	char	*target;
408 
409 	if (argc < 2)
410 		usage();
411 
412 	while (getopt(argc, argv, "vx") != -1) ;
413 
414 	target = argv[optind];
415 
416 	/* Specified device node must have "nvme" in it. */
417 	if (strstr(argv[optind], "nvme") == NULL) {
418 		printf("Invalid device node '%s'.\n", argv[optind]);
419 		exit(EX_IOERR);
420 	}
421 
422 	optreset = 1;
423 	optind = 1;
424 
425 	/*
426 	 * If devicde node contains "ns", we consider it a namespace,
427 	 *  otherwise, consider it a controller.
428 	 */
429 	if (strstr(target, "ns") == NULL)
430 		identify_ctrlr(argc, argv);
431 	else
432 		identify_ns(argc, argv);
433 }
434 
435 static void
436 print_perftest(struct nvme_io_test *io_test, bool perthread)
437 {
438 	uint32_t i, io_completed = 0, iops, mbps;
439 
440 	for (i = 0; i < io_test->num_threads; i++)
441 		io_completed += io_test->io_completed[i];
442 
443 	iops = io_completed/io_test->time;
444 	mbps = iops * io_test->size / (1024*1024);
445 
446 	printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n",
447 	    io_test->num_threads, io_test->size,
448 	    io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
449 	    io_test->time, iops, mbps);
450 
451 	if (perthread)
452 		for (i = 0; i < io_test->num_threads; i++)
453 			printf("\t%3d: %8d IO/s\n", i,
454 			    io_test->io_completed[i]/io_test->time);
455 
456 	exit(1);
457 }
458 
459 static void
460 perftest_usage(void)
461 {
462 	fprintf(stderr, "usage:\n");
463 	fprintf(stderr, PERFTEST_USAGE);
464 	exit(EX_USAGE);
465 }
466 
467 static void
468 perftest(int argc, char *argv[])
469 {
470 	struct nvme_io_test		io_test;
471 	int				fd;
472 	char				ch;
473 	char				*p;
474 	const char			*name;
475 	char				path[64];
476 	u_long				ioctl_cmd = NVME_IO_TEST;
477 	bool				nflag, oflag, sflag, tflag;
478 	int				err, perthread = 0;
479 
480 	nflag = oflag = sflag = tflag = false;
481 	name = NULL;
482 
483 	memset(&io_test, 0, sizeof(io_test));
484 
485 	while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) {
486 		switch (ch) {
487 		case 'f':
488 			if (!strcmp(optarg, "refthread"))
489 				io_test.flags |= NVME_TEST_FLAG_REFTHREAD;
490 			break;
491 		case 'i':
492 			if (!strcmp(optarg, "bio") ||
493 			    !strcmp(optarg, "wait"))
494 				ioctl_cmd = NVME_BIO_TEST;
495 			else if (!strcmp(optarg, "io") ||
496 				 !strcmp(optarg, "intr"))
497 				ioctl_cmd = NVME_IO_TEST;
498 			break;
499 		case 'n':
500 			nflag = true;
501 			io_test.num_threads = strtoul(optarg, &p, 0);
502 			if (p != NULL && *p != '\0') {
503 				fprintf(stderr,
504 				    "\"%s\" not valid number of threads.\n",
505 				    optarg);
506 				perftest_usage();
507 			} else if (io_test.num_threads == 0 ||
508 				   io_test.num_threads > 128) {
509 				fprintf(stderr,
510 				    "\"%s\" not valid number of threads.\n",
511 				    optarg);
512 				perftest_usage();
513 			}
514 			break;
515 		case 'o':
516 			oflag = true;
517 			if (!strcmp(optarg, "read") || !strcmp(optarg, "READ"))
518 				io_test.opc = NVME_OPC_READ;
519 			else if (!strcmp(optarg, "write") ||
520 				 !strcmp(optarg, "WRITE"))
521 				io_test.opc = NVME_OPC_WRITE;
522 			else {
523 				fprintf(stderr, "\"%s\" not valid opcode.\n",
524 				    optarg);
525 				perftest_usage();
526 			}
527 			break;
528 		case 'p':
529 			perthread = 1;
530 			break;
531 		case 's':
532 			sflag = true;
533 			io_test.size = strtoul(optarg, &p, 0);
534 			if (p == NULL || *p == '\0' || toupper(*p) == 'B') {
535 				// do nothing
536 			} else if (toupper(*p) == 'K') {
537 				io_test.size *= 1024;
538 			} else if (toupper(*p) == 'M') {
539 				io_test.size *= 1024 * 1024;
540 			} else {
541 				fprintf(stderr, "\"%s\" not valid size.\n",
542 				    optarg);
543 				perftest_usage();
544 			}
545 			break;
546 		case 't':
547 			tflag = true;
548 			io_test.time = strtoul(optarg, &p, 0);
549 			if (p != NULL && *p != '\0') {
550 				fprintf(stderr,
551 				    "\"%s\" not valid time duration.\n",
552 				    optarg);
553 				perftest_usage();
554 			}
555 			break;
556 		}
557 	}
558 
559 	name = argv[optind];
560 
561 	if (!nflag || !oflag || !sflag || !tflag || name == NULL)
562 		perftest_usage();
563 
564 	sprintf(path, "/dev/%s", name);
565 
566 	fd = open(path, O_RDWR);
567 	if (fd < 0) {
568 		fprintf(stderr, "%s not valid device.\n", path);
569 		perftest_usage();
570 	}
571 
572 	err = ioctl(fd, ioctl_cmd, &io_test);
573 
574 	if (err) {
575 		fprintf(stderr, "NVME_IO_TEST returned %d\n", errno);
576 		exit(EX_IOERR);
577 	}
578 
579 	print_perftest(&io_test, perthread);
580 	exit(EX_OK);
581 }
582 
583 int
584 main(int argc, char *argv[])
585 {
586 
587 	if (argc < 2)
588 		usage();
589 
590 	if (strcmp(argv[1], "devlist") == 0)
591 		devlist(argc-1, &argv[1]);
592 	else if (strcmp(argv[1], "identify") == 0)
593 		identify(argc-1, &argv[1]);
594 	else if (strcmp(argv[1], "perftest") == 0)
595 		perftest(argc-1, &argv[1]);
596 
597 	usage();
598 
599 	return (0);
600 }
601