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