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