nvmecontrol.c revision 252654
1/*-
2 * Copyright (C) 2012-2013 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: stable/9/sbin/nvmecontrol/nvmecontrol.c 252654 2013-07-03 23:40:43Z jimharris $");
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
62static void perftest_usage(void);
63
64static void
65usage(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
75static void
76print_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
94static void
95print_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
161static void
162print_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
180static void
181print_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
206static uint32_t
207ns_get_sector_size(struct nvme_namespace_data *nsdata)
208{
209
210	return (1 << nsdata->lbaf[0].lbads);
211}
212
213static void
214read_controller_data(int fd, struct nvme_controller_data *cdata)
215{
216	struct nvme_pt_command	pt;
217
218	memset(&pt, 0, sizeof(pt));
219	pt.cmd.opc = NVME_OPC_IDENTIFY;
220	pt.cmd.cdw10 = 1;
221	pt.buf = cdata;
222	pt.len = sizeof(*cdata);
223	pt.is_read = 1;
224
225	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) {
226		printf("Identify request failed. errno=%d (%s)\n",
227		    errno, strerror(errno));
228		exit(EX_IOERR);
229	}
230
231	if (nvme_completion_is_error(&pt.cpl)) {
232		printf("Passthrough command returned error.\n");
233		exit(EX_IOERR);
234	}
235}
236
237static void
238read_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata)
239{
240	struct nvme_pt_command	pt;
241
242	memset(&pt, 0, sizeof(pt));
243	pt.cmd.opc = NVME_OPC_IDENTIFY;
244	pt.cmd.nsid = nsid;
245	pt.buf = nsdata;
246	pt.len = sizeof(*nsdata);
247	pt.is_read = 1;
248
249	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) {
250		printf("Identify request failed. errno=%d (%s)\n",
251		    errno, strerror(errno));
252		exit(EX_IOERR);
253	}
254
255	if (nvme_completion_is_error(&pt.cpl)) {
256		printf("Passthrough command returned error.\n");
257		exit(EX_IOERR);
258	}
259}
260
261static int
262open_dev(const char *str, int *fd, int show_error, int exit_on_error)
263{
264	struct stat	devstat;
265	char		full_path[64];
266
267	snprintf(full_path, sizeof(full_path), "/dev/%s", str);
268	if (stat(full_path, &devstat) != 0) {
269		if (show_error)
270			fprintf(stderr, "error\n");
271		if (exit_on_error)
272			exit(EX_NOINPUT);
273		else
274			return (EX_NOINPUT);
275	}
276
277	*fd = open(full_path, O_RDWR);
278	if (*fd < 0) {
279		if (show_error)
280			printf("Could not open %s. errno=%d (%s)\n", full_path,
281			    errno, strerror(errno));
282		if (exit_on_error)
283			exit(EX_NOPERM);
284		else
285			return (EX_NOPERM);
286	}
287
288	return (EX_OK);
289}
290
291static void
292devlist(int argc, char *argv[])
293{
294	struct nvme_controller_data	cdata;
295	struct nvme_namespace_data	nsdata;
296	char				name[64];
297	uint32_t			i;
298	int				ch, ctrlr, exit_code, fd, found;
299
300	exit_code = EX_OK;
301
302	while ((ch = getopt(argc, argv, "")) != -1) {
303		switch ((char)ch) {
304		default:
305			usage();
306		}
307	}
308
309	ctrlr = -1;
310	found = 0;
311
312	while (1) {
313		ctrlr++;
314		sprintf(name, "nvme%d", ctrlr);
315
316		exit_code = open_dev(name, &fd, 0, 0);
317
318		if (exit_code == EX_NOINPUT)
319			break;
320		else if (exit_code == EX_NOPERM) {
321			printf("Could not open /dev/%s, errno = %d (%s)\n",
322			    name, errno, strerror(errno));
323			continue;
324		}
325
326		found++;
327		read_controller_data(fd, &cdata);
328		printf("%6s: %s\n", name, cdata.mn);
329
330		for (i = 0; i < cdata.nn; i++) {
331			sprintf(name, "nvme%dns%d", ctrlr, i+1);
332			read_namespace_data(fd, i+1, &nsdata);
333			printf("  %10s (%lldGB)\n",
334				name,
335				nsdata.nsze *
336				(long long)ns_get_sector_size(&nsdata) /
337				1024 / 1024 / 1024);
338		}
339
340		close(fd);
341	}
342
343	if (found == 0)
344		printf("No NVMe controllers found.\n");
345
346	exit(EX_OK);
347}
348
349static void
350identify_ctrlr(int argc, char *argv[])
351{
352	struct nvme_controller_data	cdata;
353	int				ch, fd, hexflag = 0, hexlength;
354	int				verboseflag = 0;
355
356	while ((ch = getopt(argc, argv, "vx")) != -1) {
357		switch ((char)ch) {
358		case 'v':
359			verboseflag = 1;
360			break;
361		case 'x':
362			hexflag = 1;
363			break;
364		default:
365			usage();
366		}
367	}
368
369	open_dev(argv[optind], &fd, 1, 1);
370	read_controller_data(fd, &cdata);
371	close(fd);
372
373	if (hexflag == 1) {
374		if (verboseflag == 1)
375			hexlength = sizeof(struct nvme_controller_data);
376		else
377			hexlength = offsetof(struct nvme_controller_data,
378			    reserved5);
379		print_controller_hex(&cdata, hexlength);
380		exit(EX_OK);
381	}
382
383	if (verboseflag == 1) {
384		printf("-v not currently supported without -x.\n");
385		usage();
386	}
387
388	print_controller(&cdata);
389	exit(EX_OK);
390}
391
392static void
393identify_ns(int argc, char *argv[])
394{
395	struct nvme_namespace_data	nsdata;
396	char				path[64];
397	char				*nsloc;
398	int				ch, fd, hexflag = 0, hexlength, nsid;
399	int				verboseflag = 0;
400
401	while ((ch = getopt(argc, argv, "vx")) != -1) {
402		switch ((char)ch) {
403		case 'v':
404			verboseflag = 1;
405			break;
406		case 'x':
407			hexflag = 1;
408			break;
409		default:
410			usage();
411		}
412	}
413
414	/*
415	 * Check if the specified device node exists before continuing.
416	 *  This is a cleaner check for cases where the correct controller
417	 *  is specified, but an invalid namespace on that controller.
418	 */
419	open_dev(argv[optind], &fd, 1, 1);
420	close(fd);
421
422	/*
423	 * Pull the namespace id from the string. +2 skips past the "ns" part
424	 *  of the string.  Don't search past 10 characters into the string,
425	 *  otherwise we know it is malformed.
426	 */
427	nsloc = strnstr(argv[optind], "ns", 10);
428	if (nsloc != NULL)
429		nsid = strtol(nsloc + 2, NULL, 10);
430	if (nsloc == NULL || (nsid == 0 && errno != 0)) {
431		printf("Invalid namespace ID %s.\n", argv[optind]);
432		exit(EX_IOERR);
433	}
434
435	/*
436	 * We send IDENTIFY commands to the controller, not the namespace,
437	 *  since it is an admin cmd.  So the path should only include the
438	 *  nvmeX part of the nvmeXnsY string.
439	 */
440	snprintf(path, nsloc - argv[optind] + 1, "%s", argv[optind]);
441	open_dev(path, &fd, 1, 1);
442	read_namespace_data(fd, nsid, &nsdata);
443	close(fd);
444
445	if (hexflag == 1) {
446		if (verboseflag == 1)
447			hexlength = sizeof(struct nvme_namespace_data);
448		else
449			hexlength = offsetof(struct nvme_namespace_data,
450			    reserved6);
451		print_namespace_hex(&nsdata, hexlength);
452		exit(EX_OK);
453	}
454
455	if (verboseflag == 1) {
456		printf("-v not currently supported without -x.\n");
457		usage();
458	}
459
460	print_namespace(&nsdata);
461	exit(EX_OK);
462}
463
464static void
465identify(int argc, char *argv[])
466{
467	char	*target;
468
469	if (argc < 2)
470		usage();
471
472	while (getopt(argc, argv, "vx") != -1) ;
473
474	target = argv[optind];
475
476	optreset = 1;
477	optind = 1;
478
479	/*
480	 * If device node contains "ns", we consider it a namespace,
481	 *  otherwise, consider it a controller.
482	 */
483	if (strstr(target, "ns") == NULL)
484		identify_ctrlr(argc, argv);
485	else
486		identify_ns(argc, argv);
487}
488
489static void
490print_perftest(struct nvme_io_test *io_test, bool perthread)
491{
492	uint32_t i, io_completed = 0, iops, mbps;
493
494	for (i = 0; i < io_test->num_threads; i++)
495		io_completed += io_test->io_completed[i];
496
497	iops = io_completed/io_test->time;
498	mbps = iops * io_test->size / (1024*1024);
499
500	printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n",
501	    io_test->num_threads, io_test->size,
502	    io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
503	    io_test->time, iops, mbps);
504
505	if (perthread)
506		for (i = 0; i < io_test->num_threads; i++)
507			printf("\t%3d: %8d IO/s\n", i,
508			    io_test->io_completed[i]/io_test->time);
509
510	exit(1);
511}
512
513static void
514perftest_usage(void)
515{
516	fprintf(stderr, "usage:\n");
517	fprintf(stderr, PERFTEST_USAGE);
518	exit(EX_USAGE);
519}
520
521static void
522perftest(int argc, char *argv[])
523{
524	struct nvme_io_test		io_test;
525	int				fd;
526	char				ch;
527	char				*p;
528	u_long				ioctl_cmd = NVME_IO_TEST;
529	bool				nflag, oflag, sflag, tflag;
530	int				perthread = 0;
531
532	nflag = oflag = sflag = tflag = false;
533
534	memset(&io_test, 0, sizeof(io_test));
535
536	while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) {
537		switch (ch) {
538		case 'f':
539			if (!strcmp(optarg, "refthread"))
540				io_test.flags |= NVME_TEST_FLAG_REFTHREAD;
541			break;
542		case 'i':
543			if (!strcmp(optarg, "bio") ||
544			    !strcmp(optarg, "wait"))
545				ioctl_cmd = NVME_BIO_TEST;
546			else if (!strcmp(optarg, "io") ||
547				 !strcmp(optarg, "intr"))
548				ioctl_cmd = NVME_IO_TEST;
549			break;
550		case 'n':
551			nflag = true;
552			io_test.num_threads = strtoul(optarg, &p, 0);
553			if (p != NULL && *p != '\0') {
554				fprintf(stderr,
555				    "\"%s\" not valid number of threads.\n",
556				    optarg);
557				perftest_usage();
558			} else if (io_test.num_threads == 0 ||
559				   io_test.num_threads > 128) {
560				fprintf(stderr,
561				    "\"%s\" not valid number of threads.\n",
562				    optarg);
563				perftest_usage();
564			}
565			break;
566		case 'o':
567			oflag = true;
568			if (!strcmp(optarg, "read") || !strcmp(optarg, "READ"))
569				io_test.opc = NVME_OPC_READ;
570			else if (!strcmp(optarg, "write") ||
571				 !strcmp(optarg, "WRITE"))
572				io_test.opc = NVME_OPC_WRITE;
573			else {
574				fprintf(stderr, "\"%s\" not valid opcode.\n",
575				    optarg);
576				perftest_usage();
577			}
578			break;
579		case 'p':
580			perthread = 1;
581			break;
582		case 's':
583			sflag = true;
584			io_test.size = strtoul(optarg, &p, 0);
585			if (p == NULL || *p == '\0' || toupper(*p) == 'B') {
586				// do nothing
587			} else if (toupper(*p) == 'K') {
588				io_test.size *= 1024;
589			} else if (toupper(*p) == 'M') {
590				io_test.size *= 1024 * 1024;
591			} else {
592				fprintf(stderr, "\"%s\" not valid size.\n",
593				    optarg);
594				perftest_usage();
595			}
596			break;
597		case 't':
598			tflag = true;
599			io_test.time = strtoul(optarg, &p, 0);
600			if (p != NULL && *p != '\0') {
601				fprintf(stderr,
602				    "\"%s\" not valid time duration.\n",
603				    optarg);
604				perftest_usage();
605			}
606			break;
607		}
608	}
609
610	if (!nflag || !oflag || !sflag || !tflag || optind >= argc)
611		perftest_usage();
612
613	open_dev(argv[optind], &fd, 1, 1);
614	if (ioctl(fd, ioctl_cmd, &io_test) < 0) {
615		fprintf(stderr, "NVME_IO_TEST failed. errno=%d (%s)\n", errno,
616		    strerror(errno));
617		close(fd);
618		exit(EX_IOERR);
619	}
620
621	close(fd);
622	print_perftest(&io_test, perthread);
623	exit(EX_OK);
624}
625
626static void
627reset_ctrlr(int argc, char *argv[])
628{
629	int	ch, fd;
630
631	while ((ch = getopt(argc, argv, "")) != -1) {
632		switch ((char)ch) {
633		default:
634			usage();
635		}
636	}
637
638	open_dev(argv[optind], &fd, 1, 1);
639	if (ioctl(fd, NVME_RESET_CONTROLLER) < 0) {
640		printf("Reset request to %s failed. errno=%d (%s)\n",
641		    argv[optind], errno, strerror(errno));
642		exit(EX_IOERR);
643	}
644
645	exit(EX_OK);
646}
647
648int
649main(int argc, char *argv[])
650{
651
652	if (argc < 2)
653		usage();
654
655	if (strcmp(argv[1], "devlist") == 0)
656		devlist(argc-1, &argv[1]);
657	else if (strcmp(argv[1], "identify") == 0)
658		identify(argc-1, &argv[1]);
659	else if (strcmp(argv[1], "perftest") == 0)
660		perftest(argc-1, &argv[1]);
661	else if (strcmp(argv[1], "reset") == 0)
662		reset_ctrlr(argc-1, &argv[1]);
663
664	usage();
665
666	return (0);
667}
668
669