]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - sbin/nvmecontrol/nvmecontrol.c
MFC r252264:
[FreeBSD/stable/9.git] / sbin / nvmecontrol / nvmecontrol.c
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$");
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 static void
214 read_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
237 static void
238 read_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
261 static int
262 open_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
291 static void
292 devlist_usage(void)
293 {
294         fprintf(stderr, "usage:\n");
295         fprintf(stderr, DEVLIST_USAGE);
296         exit(EX_USAGE);
297 }
298
299 static void
300 devlist(int argc, char *argv[])
301 {
302         struct nvme_controller_data     cdata;
303         struct nvme_namespace_data      nsdata;
304         char                            name[64];
305         uint32_t                        i;
306         int                             ch, ctrlr, exit_code, fd, found;
307
308         exit_code = EX_OK;
309
310         while ((ch = getopt(argc, argv, "")) != -1) {
311                 switch ((char)ch) {
312                 default:
313                         devlist_usage();
314                 }
315         }
316
317         ctrlr = -1;
318         found = 0;
319
320         while (1) {
321                 ctrlr++;
322                 sprintf(name, "nvme%d", ctrlr);
323
324                 exit_code = open_dev(name, &fd, 0, 0);
325
326                 if (exit_code == EX_NOINPUT)
327                         break;
328                 else if (exit_code == EX_NOPERM) {
329                         printf("Could not open /dev/%s, errno = %d (%s)\n",
330                             name, errno, strerror(errno));
331                         continue;
332                 }
333
334                 found++;
335                 read_controller_data(fd, &cdata);
336                 printf("%6s: %s\n", name, cdata.mn);
337
338                 for (i = 0; i < cdata.nn; i++) {
339                         sprintf(name, "nvme%dns%d", ctrlr, i+1);
340                         read_namespace_data(fd, i+1, &nsdata);
341                         printf("  %10s (%lldGB)\n",
342                                 name,
343                                 nsdata.nsze *
344                                 (long long)ns_get_sector_size(&nsdata) /
345                                 1024 / 1024 / 1024);
346                 }
347
348                 close(fd);
349         }
350
351         if (found == 0)
352                 printf("No NVMe controllers found.\n");
353
354         exit(EX_OK);
355 }
356
357 static void
358 identify_usage(void)
359 {
360         fprintf(stderr, "usage:\n");
361         fprintf(stderr, IDENTIFY_USAGE);
362         exit(EX_USAGE);
363 }
364
365 static void
366 identify_ctrlr(int argc, char *argv[])
367 {
368         struct nvme_controller_data     cdata;
369         int                             ch, fd, hexflag = 0, hexlength;
370         int                             verboseflag = 0;
371
372         while ((ch = getopt(argc, argv, "vx")) != -1) {
373                 switch ((char)ch) {
374                 case 'v':
375                         verboseflag = 1;
376                         break;
377                 case 'x':
378                         hexflag = 1;
379                         break;
380                 default:
381                         identify_usage();
382                 }
383         }
384
385         open_dev(argv[optind], &fd, 1, 1);
386         read_controller_data(fd, &cdata);
387         close(fd);
388
389         if (hexflag == 1) {
390                 if (verboseflag == 1)
391                         hexlength = sizeof(struct nvme_controller_data);
392                 else
393                         hexlength = offsetof(struct nvme_controller_data,
394                             reserved5);
395                 print_controller_hex(&cdata, hexlength);
396                 exit(EX_OK);
397         }
398
399         if (verboseflag == 1) {
400                 printf("-v not currently supported without -x.\n");
401                 identify_usage();
402         }
403
404         print_controller(&cdata);
405         exit(EX_OK);
406 }
407
408 static void
409 identify_ns(int argc, char *argv[])
410 {
411         struct nvme_namespace_data      nsdata;
412         char                            path[64];
413         char                            *nsloc;
414         int                             ch, fd, hexflag = 0, hexlength, nsid;
415         int                             verboseflag = 0;
416
417         while ((ch = getopt(argc, argv, "vx")) != -1) {
418                 switch ((char)ch) {
419                 case 'v':
420                         verboseflag = 1;
421                         break;
422                 case 'x':
423                         hexflag = 1;
424                         break;
425                 default:
426                         identify_usage();
427                 }
428         }
429
430         /*
431          * Check if the specified device node exists before continuing.
432          *  This is a cleaner check for cases where the correct controller
433          *  is specified, but an invalid namespace on that controller.
434          */
435         open_dev(argv[optind], &fd, 1, 1);
436         close(fd);
437
438         /*
439          * Pull the namespace id from the string. +2 skips past the "ns" part
440          *  of the string.  Don't search past 10 characters into the string,
441          *  otherwise we know it is malformed.
442          */
443         nsloc = strnstr(argv[optind], "ns", 10);
444         if (nsloc != NULL)
445                 nsid = strtol(nsloc + 2, NULL, 10);
446         if (nsloc == NULL || (nsid == 0 && errno != 0)) {
447                 printf("Invalid namespace ID %s.\n", argv[optind]);
448                 exit(EX_IOERR);
449         }
450
451         /*
452          * We send IDENTIFY commands to the controller, not the namespace,
453          *  since it is an admin cmd.  So the path should only include the
454          *  nvmeX part of the nvmeXnsY string.
455          */
456         snprintf(path, nsloc - argv[optind] + 1, "%s", argv[optind]);
457         open_dev(path, &fd, 1, 1);
458         read_namespace_data(fd, nsid, &nsdata);
459         close(fd);
460
461         if (hexflag == 1) {
462                 if (verboseflag == 1)
463                         hexlength = sizeof(struct nvme_namespace_data);
464                 else
465                         hexlength = offsetof(struct nvme_namespace_data,
466                             reserved6);
467                 print_namespace_hex(&nsdata, hexlength);
468                 exit(EX_OK);
469         }
470
471         if (verboseflag == 1) {
472                 printf("-v not currently supported without -x.\n");
473                 identify_usage();
474         }
475
476         print_namespace(&nsdata);
477         exit(EX_OK);
478 }
479
480 static void
481 identify(int argc, char *argv[])
482 {
483         char    *target;
484
485         if (argc < 2)
486                 identify_usage();
487
488         while (getopt(argc, argv, "vx") != -1) ;
489
490         target = argv[optind];
491
492         optreset = 1;
493         optind = 1;
494
495         /*
496          * If device node contains "ns", we consider it a namespace,
497          *  otherwise, consider it a controller.
498          */
499         if (strstr(target, "ns") == NULL)
500                 identify_ctrlr(argc, argv);
501         else
502                 identify_ns(argc, argv);
503 }
504
505 static void
506 print_perftest(struct nvme_io_test *io_test, bool perthread)
507 {
508         uint32_t i, io_completed = 0, iops, mbps;
509
510         for (i = 0; i < io_test->num_threads; i++)
511                 io_completed += io_test->io_completed[i];
512
513         iops = io_completed/io_test->time;
514         mbps = iops * io_test->size / (1024*1024);
515
516         printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n",
517             io_test->num_threads, io_test->size,
518             io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
519             io_test->time, iops, mbps);
520
521         if (perthread)
522                 for (i = 0; i < io_test->num_threads; i++)
523                         printf("\t%3d: %8d IO/s\n", i,
524                             io_test->io_completed[i]/io_test->time);
525
526         exit(1);
527 }
528
529 static void
530 perftest_usage(void)
531 {
532         fprintf(stderr, "usage:\n");
533         fprintf(stderr, PERFTEST_USAGE);
534         exit(EX_USAGE);
535 }
536
537 static void
538 perftest(int argc, char *argv[])
539 {
540         struct nvme_io_test             io_test;
541         int                             fd;
542         char                            ch;
543         char                            *p;
544         u_long                          ioctl_cmd = NVME_IO_TEST;
545         bool                            nflag, oflag, sflag, tflag;
546         int                             perthread = 0;
547
548         nflag = oflag = sflag = tflag = false;
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         if (!nflag || !oflag || !sflag || !tflag || optind >= argc)
627                 perftest_usage();
628
629         open_dev(argv[optind], &fd, 1, 1);
630         if (ioctl(fd, ioctl_cmd, &io_test) < 0) {
631                 fprintf(stderr, "NVME_IO_TEST failed. errno=%d (%s)\n", errno,
632                     strerror(errno));
633                 close(fd);
634                 exit(EX_IOERR);
635         }
636
637         close(fd);
638         print_perftest(&io_test, perthread);
639         exit(EX_OK);
640 }
641
642 static void
643 reset_usage(void)
644 {
645         fprintf(stderr, "usage:\n");
646         fprintf(stderr, RESET_USAGE);
647         exit(EX_USAGE);
648 }
649
650 static void
651 reset_ctrlr(int argc, char *argv[])
652 {
653         int     ch, fd;
654
655         while ((ch = getopt(argc, argv, "")) != -1) {
656                 switch ((char)ch) {
657                 default:
658                         reset_usage();
659                 }
660         }
661
662         open_dev(argv[optind], &fd, 1, 1);
663         if (ioctl(fd, NVME_RESET_CONTROLLER) < 0) {
664                 printf("Reset request to %s failed. errno=%d (%s)\n",
665                     argv[optind], errno, strerror(errno));
666                 exit(EX_IOERR);
667         }
668
669         exit(EX_OK);
670 }
671
672 int
673 main(int argc, char *argv[])
674 {
675
676         if (argc < 2)
677                 usage();
678
679         if (strcmp(argv[1], "devlist") == 0)
680                 devlist(argc-1, &argv[1]);
681         else if (strcmp(argv[1], "identify") == 0)
682                 identify(argc-1, &argv[1]);
683         else if (strcmp(argv[1], "perftest") == 0)
684                 perftest(argc-1, &argv[1]);
685         else if (strcmp(argv[1], "reset") == 0)
686                 reset_ctrlr(argc-1, &argv[1]);
687
688         usage();
689
690         return (0);
691 }
692