nvmecontrol.c revision 252656
1210006Srdivacky/*-
2210006Srdivacky * Copyright (C) 2012-2013 Intel Corporation
3210006Srdivacky * All rights reserved.
4210006Srdivacky *
5210006Srdivacky * Redistribution and use in source and binary forms, with or without
6210006Srdivacky * modification, are permitted provided that the following conditions
7210006Srdivacky * are met:
8210006Srdivacky * 1. Redistributions of source code must retain the above copyright
9210006Srdivacky *    notice, this list of conditions and the following disclaimer.
10210006Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
11210006Srdivacky *    notice, this list of conditions and the following disclaimer in the
12249423Sdim *    documentation and/or other materials provided with the distribution.
13210006Srdivacky *
14210006Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15210006Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16210006Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17210006Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18210006Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19210006Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20210006Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21210006Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22210006Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23210006Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24210006Srdivacky * SUCH DAMAGE.
25210006Srdivacky */
26210006Srdivacky
27210006Srdivacky#include <sys/cdefs.h>
28210006Srdivacky__FBSDID("$FreeBSD: stable/9/sbin/nvmecontrol/nvmecontrol.c 252656 2013-07-03 23:45:58Z jimharris $");
29210006Srdivacky
30210006Srdivacky#include <sys/param.h>
31210006Srdivacky#include <sys/ioccom.h>
32210006Srdivacky#include <sys/stat.h>
33210006Srdivacky
34210006Srdivacky#include <ctype.h>
35210006Srdivacky#include <errno.h>
36210006Srdivacky#include <fcntl.h>
37210006Srdivacky#include <stdbool.h>
38210006Srdivacky#include <stddef.h>
39234353Sdim#include <stdio.h>
40210006Srdivacky#include <stdlib.h>
41210006Srdivacky#include <string.h>
42210006Srdivacky#include <sysexits.h>
43210006Srdivacky#include <unistd.h>
44210006Srdivacky
45210006Srdivacky#include "nvmecontrol.h"
46210006Srdivacky
47210006Srdivackystatic void perftest_usage(void);
48210006Srdivacky
49210006Srdivackystatic void
50210006Srdivackyusage(void)
51243830Sdim{
52243830Sdim	fprintf(stderr, "usage:\n");
53210006Srdivacky	fprintf(stderr, DEVLIST_USAGE);
54243830Sdim	fprintf(stderr, IDENTIFY_USAGE);
55210006Srdivacky	fprintf(stderr, RESET_USAGE);
56210006Srdivacky	fprintf(stderr, PERFTEST_USAGE);
57210006Srdivacky	exit(EX_USAGE);
58210006Srdivacky}
59243830Sdim
60243830Sdimstatic void
61243830Sdimprint_controller_hex(struct nvme_controller_data *cdata, uint32_t length)
62243830Sdim{
63210006Srdivacky	uint32_t	*p;
64210006Srdivacky	uint32_t	i, j;
65210006Srdivacky
66210006Srdivacky	p = (uint32_t *)cdata;
67210006Srdivacky	length /= sizeof(uint32_t);
68210006Srdivacky
69210006Srdivacky	for (i = 0; i < length; i+=8) {
70210006Srdivacky		printf("%03x: ", i*4);
71243830Sdim		for (j = 0; j < 8; j++)
72210006Srdivacky			printf("%08x ", p[i+j]);
73210006Srdivacky		printf("\n");
74210006Srdivacky	}
75210006Srdivacky
76210006Srdivacky	printf("\n");
77210006Srdivacky}
78
79static void
80print_controller(struct nvme_controller_data *cdata)
81{
82	printf("Controller Capabilities/Features\n");
83	printf("================================\n");
84	printf("Vendor ID:                  %04x\n", cdata->vid);
85	printf("Subsystem Vendor ID:        %04x\n", cdata->ssvid);
86	printf("Serial Number:              %s\n", cdata->sn);
87	printf("Model Number:               %s\n", cdata->mn);
88	printf("Firmware Version:           %s\n", cdata->fr);
89	printf("Recommended Arb Burst:      %d\n", cdata->rab);
90	printf("IEEE OUI Identifier:        %02x %02x %02x\n",
91		cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
92	printf("Multi-Interface Cap:        %02x\n", cdata->mic);
93	/* TODO: Use CAP.MPSMIN to determine true memory page size. */
94	printf("Max Data Transfer Size:     ");
95	if (cdata->mdts == 0)
96		printf("Unlimited\n");
97	else
98		printf("%d\n", PAGE_SIZE * (1 << cdata->mdts));
99	printf("\n");
100
101	printf("Admin Command Set Attributes\n");
102	printf("============================\n");
103	printf("Security Send/Receive:       %s\n",
104		cdata->oacs.security ? "Supported" : "Not Supported");
105	printf("Format NVM:                  %s\n",
106		cdata->oacs.format ? "Supported" : "Not Supported");
107	printf("Firmware Activate/Download:  %s\n",
108		cdata->oacs.firmware ? "Supported" : "Not Supported");
109	printf("Abort Command Limit:         %d\n", cdata->acl+1);
110	printf("Async Event Request Limit:   %d\n", cdata->aerl+1);
111	printf("Number of Firmware Slots:    ");
112	if (cdata->oacs.firmware != 0)
113		printf("%d\n", cdata->frmw.num_slots);
114	else
115		printf("N/A\n");
116	printf("Firmware Slot 1 Read-Only:   ");
117	if (cdata->oacs.firmware != 0)
118		printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No");
119	else
120		printf("N/A\n");
121	printf("Per-Namespace SMART Log:     %s\n",
122		cdata->lpa.ns_smart ? "Yes" : "No");
123	printf("Error Log Page Entries:      %d\n", cdata->elpe+1);
124	printf("Number of Power States:      %d\n", cdata->npss+1);
125	printf("\n");
126
127	printf("NVM Command Set Attributes\n");
128	printf("==========================\n");
129	printf("Submission Queue Entry Size\n");
130	printf("  Max:                       %d\n", 1 << cdata->sqes.max);
131	printf("  Min:                       %d\n", 1 << cdata->sqes.min);
132	printf("Completion Queue Entry Size\n");
133	printf("  Max:                       %d\n", 1 << cdata->cqes.max);
134	printf("  Min:                       %d\n", 1 << cdata->cqes.min);
135	printf("Number of Namespaces:        %d\n", cdata->nn);
136	printf("Compare Command:             %s\n",
137		cdata->oncs.compare ? "Supported" : "Not Supported");
138	printf("Write Uncorrectable Command: %s\n",
139		cdata->oncs.write_unc ? "Supported" : "Not Supported");
140	printf("Dataset Management Command:  %s\n",
141		cdata->oncs.dsm ? "Supported" : "Not Supported");
142	printf("Volatile Write Cache:        %s\n",
143		cdata->vwc.present ? "Present" : "Not Present");
144}
145
146static void
147print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length)
148{
149	uint32_t	*p;
150	uint32_t	i, j;
151
152	p = (uint32_t *)nsdata;
153	length /= sizeof(uint32_t);
154
155	for (i = 0; i < length; i+=8) {
156		printf("%03x: ", i*4);
157		for (j = 0; j < 8; j++)
158			printf("%08x ", p[i+j]);
159		printf("\n");
160	}
161
162	printf("\n");
163}
164
165static void
166print_namespace(struct nvme_namespace_data *nsdata)
167{
168	uint32_t	i;
169
170	printf("Size (in LBAs):              %lld (%lldM)\n",
171		(long long)nsdata->nsze,
172		(long long)nsdata->nsze / 1024 / 1024);
173	printf("Capacity (in LBAs):          %lld (%lldM)\n",
174		(long long)nsdata->ncap,
175		(long long)nsdata->ncap / 1024 / 1024);
176	printf("Utilization (in LBAs):       %lld (%lldM)\n",
177		(long long)nsdata->nuse,
178		(long long)nsdata->nuse / 1024 / 1024);
179	printf("Thin Provisioning:           %s\n",
180		nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported");
181	printf("Number of LBA Formats:       %d\n", nsdata->nlbaf+1);
182	printf("Current LBA Format:          LBA Format #%d\n",
183		nsdata->flbas.format);
184	for (i = 0; i <= nsdata->nlbaf; i++) {
185		printf("LBA Format #%d:\n", i);
186		printf("  LBA Data Size:             %d\n",
187			1 << nsdata->lbaf[i].lbads);
188	}
189}
190
191void
192read_controller_data(int fd, struct nvme_controller_data *cdata)
193{
194	struct nvme_pt_command	pt;
195
196	memset(&pt, 0, sizeof(pt));
197	pt.cmd.opc = NVME_OPC_IDENTIFY;
198	pt.cmd.cdw10 = 1;
199	pt.buf = cdata;
200	pt.len = sizeof(*cdata);
201	pt.is_read = 1;
202
203	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) {
204		printf("Identify request failed. errno=%d (%s)\n",
205		    errno, strerror(errno));
206		exit(EX_IOERR);
207	}
208
209	if (nvme_completion_is_error(&pt.cpl)) {
210		printf("Passthrough command returned error.\n");
211		exit(EX_IOERR);
212	}
213}
214
215void
216read_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata)
217{
218	struct nvme_pt_command	pt;
219
220	memset(&pt, 0, sizeof(pt));
221	pt.cmd.opc = NVME_OPC_IDENTIFY;
222	pt.cmd.nsid = nsid;
223	pt.buf = nsdata;
224	pt.len = sizeof(*nsdata);
225	pt.is_read = 1;
226
227	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) {
228		printf("Identify request failed. errno=%d (%s)\n",
229		    errno, strerror(errno));
230		exit(EX_IOERR);
231	}
232
233	if (nvme_completion_is_error(&pt.cpl)) {
234		printf("Passthrough command returned error.\n");
235		exit(EX_IOERR);
236	}
237}
238
239int
240open_dev(const char *str, int *fd, int show_error, int exit_on_error)
241{
242	struct stat	devstat;
243	char		full_path[64];
244
245	snprintf(full_path, sizeof(full_path), "/dev/%s", str);
246	if (stat(full_path, &devstat) != 0) {
247		if (show_error)
248			fprintf(stderr, "error\n");
249		if (exit_on_error)
250			exit(EX_NOINPUT);
251		else
252			return (EX_NOINPUT);
253	}
254
255	*fd = open(full_path, O_RDWR);
256	if (*fd < 0) {
257		if (show_error)
258			printf("Could not open %s. errno=%d (%s)\n", full_path,
259			    errno, strerror(errno));
260		if (exit_on_error)
261			exit(EX_NOPERM);
262		else
263			return (EX_NOPERM);
264	}
265
266	return (EX_OK);
267}
268
269static void
270identify_usage(void)
271{
272	fprintf(stderr, "usage:\n");
273	fprintf(stderr, IDENTIFY_USAGE);
274	exit(EX_USAGE);
275}
276
277static void
278identify_ctrlr(int argc, char *argv[])
279{
280	struct nvme_controller_data	cdata;
281	int				ch, fd, hexflag = 0, hexlength;
282	int				verboseflag = 0;
283
284	while ((ch = getopt(argc, argv, "vx")) != -1) {
285		switch ((char)ch) {
286		case 'v':
287			verboseflag = 1;
288			break;
289		case 'x':
290			hexflag = 1;
291			break;
292		default:
293			identify_usage();
294		}
295	}
296
297	open_dev(argv[optind], &fd, 1, 1);
298	read_controller_data(fd, &cdata);
299	close(fd);
300
301	if (hexflag == 1) {
302		if (verboseflag == 1)
303			hexlength = sizeof(struct nvme_controller_data);
304		else
305			hexlength = offsetof(struct nvme_controller_data,
306			    reserved5);
307		print_controller_hex(&cdata, hexlength);
308		exit(EX_OK);
309	}
310
311	if (verboseflag == 1) {
312		printf("-v not currently supported without -x.\n");
313		identify_usage();
314	}
315
316	print_controller(&cdata);
317	exit(EX_OK);
318}
319
320static void
321identify_ns(int argc, char *argv[])
322{
323	struct nvme_namespace_data	nsdata;
324	char				path[64];
325	char				*nsloc;
326	int				ch, fd, hexflag = 0, hexlength, nsid;
327	int				verboseflag = 0;
328
329	while ((ch = getopt(argc, argv, "vx")) != -1) {
330		switch ((char)ch) {
331		case 'v':
332			verboseflag = 1;
333			break;
334		case 'x':
335			hexflag = 1;
336			break;
337		default:
338			identify_usage();
339		}
340	}
341
342	/*
343	 * Check if the specified device node exists before continuing.
344	 *  This is a cleaner check for cases where the correct controller
345	 *  is specified, but an invalid namespace on that controller.
346	 */
347	open_dev(argv[optind], &fd, 1, 1);
348	close(fd);
349
350	/*
351	 * Pull the namespace id from the string. +2 skips past the "ns" part
352	 *  of the string.  Don't search past 10 characters into the string,
353	 *  otherwise we know it is malformed.
354	 */
355	nsloc = strnstr(argv[optind], "ns", 10);
356	if (nsloc != NULL)
357		nsid = strtol(nsloc + 2, NULL, 10);
358	if (nsloc == NULL || (nsid == 0 && errno != 0)) {
359		printf("Invalid namespace ID %s.\n", argv[optind]);
360		exit(EX_IOERR);
361	}
362
363	/*
364	 * We send IDENTIFY commands to the controller, not the namespace,
365	 *  since it is an admin cmd.  So the path should only include the
366	 *  nvmeX part of the nvmeXnsY string.
367	 */
368	snprintf(path, nsloc - argv[optind] + 1, "%s", argv[optind]);
369	open_dev(path, &fd, 1, 1);
370	read_namespace_data(fd, nsid, &nsdata);
371	close(fd);
372
373	if (hexflag == 1) {
374		if (verboseflag == 1)
375			hexlength = sizeof(struct nvme_namespace_data);
376		else
377			hexlength = offsetof(struct nvme_namespace_data,
378			    reserved6);
379		print_namespace_hex(&nsdata, hexlength);
380		exit(EX_OK);
381	}
382
383	if (verboseflag == 1) {
384		printf("-v not currently supported without -x.\n");
385		identify_usage();
386	}
387
388	print_namespace(&nsdata);
389	exit(EX_OK);
390}
391
392static void
393identify(int argc, char *argv[])
394{
395	char	*target;
396
397	if (argc < 2)
398		identify_usage();
399
400	while (getopt(argc, argv, "vx") != -1) ;
401
402	target = argv[optind];
403
404	optreset = 1;
405	optind = 1;
406
407	/*
408	 * If device node contains "ns", we consider it a namespace,
409	 *  otherwise, consider it a controller.
410	 */
411	if (strstr(target, "ns") == NULL)
412		identify_ctrlr(argc, argv);
413	else
414		identify_ns(argc, argv);
415}
416
417static void
418print_perftest(struct nvme_io_test *io_test, bool perthread)
419{
420	uint32_t i, io_completed = 0, iops, mbps;
421
422	for (i = 0; i < io_test->num_threads; i++)
423		io_completed += io_test->io_completed[i];
424
425	iops = io_completed/io_test->time;
426	mbps = iops * io_test->size / (1024*1024);
427
428	printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n",
429	    io_test->num_threads, io_test->size,
430	    io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
431	    io_test->time, iops, mbps);
432
433	if (perthread)
434		for (i = 0; i < io_test->num_threads; i++)
435			printf("\t%3d: %8d IO/s\n", i,
436			    io_test->io_completed[i]/io_test->time);
437
438	exit(1);
439}
440
441static void
442perftest_usage(void)
443{
444	fprintf(stderr, "usage:\n");
445	fprintf(stderr, PERFTEST_USAGE);
446	exit(EX_USAGE);
447}
448
449static void
450perftest(int argc, char *argv[])
451{
452	struct nvme_io_test		io_test;
453	int				fd;
454	char				ch;
455	char				*p;
456	u_long				ioctl_cmd = NVME_IO_TEST;
457	bool				nflag, oflag, sflag, tflag;
458	int				perthread = 0;
459
460	nflag = oflag = sflag = tflag = false;
461
462	memset(&io_test, 0, sizeof(io_test));
463
464	while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) {
465		switch (ch) {
466		case 'f':
467			if (!strcmp(optarg, "refthread"))
468				io_test.flags |= NVME_TEST_FLAG_REFTHREAD;
469			break;
470		case 'i':
471			if (!strcmp(optarg, "bio") ||
472			    !strcmp(optarg, "wait"))
473				ioctl_cmd = NVME_BIO_TEST;
474			else if (!strcmp(optarg, "io") ||
475				 !strcmp(optarg, "intr"))
476				ioctl_cmd = NVME_IO_TEST;
477			break;
478		case 'n':
479			nflag = true;
480			io_test.num_threads = strtoul(optarg, &p, 0);
481			if (p != NULL && *p != '\0') {
482				fprintf(stderr,
483				    "\"%s\" not valid number of threads.\n",
484				    optarg);
485				perftest_usage();
486			} else if (io_test.num_threads == 0 ||
487				   io_test.num_threads > 128) {
488				fprintf(stderr,
489				    "\"%s\" not valid number of threads.\n",
490				    optarg);
491				perftest_usage();
492			}
493			break;
494		case 'o':
495			oflag = true;
496			if (!strcmp(optarg, "read") || !strcmp(optarg, "READ"))
497				io_test.opc = NVME_OPC_READ;
498			else if (!strcmp(optarg, "write") ||
499				 !strcmp(optarg, "WRITE"))
500				io_test.opc = NVME_OPC_WRITE;
501			else {
502				fprintf(stderr, "\"%s\" not valid opcode.\n",
503				    optarg);
504				perftest_usage();
505			}
506			break;
507		case 'p':
508			perthread = 1;
509			break;
510		case 's':
511			sflag = true;
512			io_test.size = strtoul(optarg, &p, 0);
513			if (p == NULL || *p == '\0' || toupper(*p) == 'B') {
514				// do nothing
515			} else if (toupper(*p) == 'K') {
516				io_test.size *= 1024;
517			} else if (toupper(*p) == 'M') {
518				io_test.size *= 1024 * 1024;
519			} else {
520				fprintf(stderr, "\"%s\" not valid size.\n",
521				    optarg);
522				perftest_usage();
523			}
524			break;
525		case 't':
526			tflag = true;
527			io_test.time = strtoul(optarg, &p, 0);
528			if (p != NULL && *p != '\0') {
529				fprintf(stderr,
530				    "\"%s\" not valid time duration.\n",
531				    optarg);
532				perftest_usage();
533			}
534			break;
535		}
536	}
537
538	if (!nflag || !oflag || !sflag || !tflag || optind >= argc)
539		perftest_usage();
540
541	open_dev(argv[optind], &fd, 1, 1);
542	if (ioctl(fd, ioctl_cmd, &io_test) < 0) {
543		fprintf(stderr, "NVME_IO_TEST failed. errno=%d (%s)\n", errno,
544		    strerror(errno));
545		close(fd);
546		exit(EX_IOERR);
547	}
548
549	close(fd);
550	print_perftest(&io_test, perthread);
551	exit(EX_OK);
552}
553
554static void
555reset_usage(void)
556{
557	fprintf(stderr, "usage:\n");
558	fprintf(stderr, RESET_USAGE);
559	exit(EX_USAGE);
560}
561
562static void
563reset_ctrlr(int argc, char *argv[])
564{
565	int	ch, fd;
566
567	while ((ch = getopt(argc, argv, "")) != -1) {
568		switch ((char)ch) {
569		default:
570			reset_usage();
571		}
572	}
573
574	open_dev(argv[optind], &fd, 1, 1);
575	if (ioctl(fd, NVME_RESET_CONTROLLER) < 0) {
576		printf("Reset request to %s failed. errno=%d (%s)\n",
577		    argv[optind], errno, strerror(errno));
578		exit(EX_IOERR);
579	}
580
581	exit(EX_OK);
582}
583
584int
585main(int argc, char *argv[])
586{
587
588	if (argc < 2)
589		usage();
590
591	if (strcmp(argv[1], "devlist") == 0)
592		devlist(argc-1, &argv[1]);
593	else if (strcmp(argv[1], "identify") == 0)
594		identify(argc-1, &argv[1]);
595	else if (strcmp(argv[1], "perftest") == 0)
596		perftest(argc-1, &argv[1]);
597	else if (strcmp(argv[1], "reset") == 0)
598		reset_ctrlr(argc-1, &argv[1]);
599
600	usage();
601
602	return (0);
603}
604
605