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$"); 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 static void perftest_usage(void); 60 61 static void 62 usage(void) 63 { 64 fprintf(stderr, "usage:\n"); 65 fprintf(stderr, DEVLIST_USAGE); 66 fprintf(stderr, IDENTIFY_USAGE); 67 fprintf(stderr, PERFTEST_USAGE); 68 exit(EX_USAGE); 69 } 70 71 static void 72 print_controller_hex(struct nvme_controller_data *cdata, uint32_t length) 73 { 74 uint32_t *p; 75 uint32_t i, j; 76 77 p = (uint32_t *)cdata; 78 length /= sizeof(uint32_t); 79 80 for (i = 0; i < length; i+=8) { 81 printf("%03x: ", i*4); 82 for (j = 0; j < 8; j++) 83 printf("%08x ", p[i+j]); 84 printf("\n"); 85 } 86 87 printf("\n"); 88 } 89 90 static void 91 print_controller(struct nvme_controller_data *cdata) 92 { 93 printf("Controller Capabilities/Features\n"); 94 printf("================================\n"); 95 printf("Vendor ID: %04x\n", cdata->vid); 96 printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 97 printf("Serial Number: %s\n", cdata->sn); 98 printf("Model Number: %s\n", cdata->mn); 99 printf("Firmware Version: %s\n", cdata->fr); 100 printf("Recommended Arb Burst: %d\n", cdata->rab); 101 printf("IEEE OUI Identifier: %02x %02x %02x\n", 102 cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 103 printf("Multi-Interface Cap: %02x\n", cdata->mic); 104 /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 105 printf("Max Data Transfer Size: "); 106 if (cdata->mdts == 0) 107 printf("Unlimited\n"); 108 else 109 printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); 110 printf("\n"); 111 112 printf("Admin Command Set Attributes\n"); 113 printf("============================\n"); 114 printf("Security Send/Receive: %s\n", 115 cdata->oacs.security ? "Supported" : "Not Supported"); 116 printf("Format NVM: %s\n", 117 cdata->oacs.format ? "Supported" : "Not Supported"); 118 printf("Firmware Activate/Download: %s\n", 119 cdata->oacs.firmware ? "Supported" : "Not Supported"); 120 printf("Abort Command Limit: %d\n", cdata->acl+1); 121 printf("Async Event Request Limit: %d\n", cdata->aerl+1); 122 printf("Number of Firmware Slots: "); 123 if (cdata->oacs.firmware != 0) 124 printf("%d\n", cdata->frmw.num_slots); 125 else 126 printf("N/A\n"); 127 printf("Firmware Slot 1 Read-Only: "); 128 if (cdata->oacs.firmware != 0) 129 printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); 130 else 131 printf("N/A\n"); 132 printf("Per-Namespace SMART Log: %s\n", 133 cdata->lpa.ns_smart ? "Yes" : "No"); 134 printf("Error Log Page Entries: %d\n", cdata->elpe+1); 135 printf("Number of Power States: %d\n", cdata->npss+1); 136 printf("\n"); 137 138 printf("NVM Command Set Attributes\n"); 139 printf("==========================\n"); 140 printf("Submission Queue Entry Size\n"); 141 printf(" Max: %d\n", 1 << cdata->sqes.max); 142 printf(" Min: %d\n", 1 << cdata->sqes.min); 143 printf("Completion Queue Entry Size\n"); 144 printf(" Max: %d\n", 1 << cdata->cqes.max); 145 printf(" Min: %d\n", 1 << cdata->cqes.min); 146 printf("Number of Namespaces: %d\n", cdata->nn); 147 printf("Compare Command: %s\n", 148 cdata->oncs.compare ? "Supported" : "Not Supported"); 149 printf("Write Uncorrectable Command: %s\n", 150 cdata->oncs.write_unc ? "Supported" : "Not Supported"); 151 printf("Dataset Management Command: %s\n", 152 cdata->oncs.dsm ? "Supported" : "Not Supported"); 153 printf("Volatile Write Cache: %s\n", 154 cdata->vwc.present ? "Present" : "Not Present"); 155 } 156 157 static void 158 print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length) 159 { 160 uint32_t *p; 161 uint32_t i, j; 162 163 p = (uint32_t *)nsdata; 164 length /= sizeof(uint32_t); 165 166 for (i = 0; i < length; i+=8) { 167 printf("%03x: ", i*4); 168 for (j = 0; j < 8; j++) 169 printf("%08x ", p[i+j]); 170 printf("\n"); 171 } 172 173 printf("\n"); 174 } 175 176 static void 177 print_namespace(struct nvme_namespace_data *nsdata) 178 { 179 uint32_t i; 180 181 printf("Size (in LBAs): %lld (%lldM)\n", 182 (long long)nsdata->nsze, 183 (long long)nsdata->nsze / 1024 / 1024); 184 printf("Capacity (in LBAs): %lld (%lldM)\n", 185 (long long)nsdata->ncap, 186 (long long)nsdata->ncap / 1024 / 1024); 187 printf("Utilization (in LBAs): %lld (%lldM)\n", 188 (long long)nsdata->nuse, 189 (long long)nsdata->nuse / 1024 / 1024); 190 printf("Thin Provisioning: %s\n", 191 nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); 192 printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 193 printf("Current LBA Format: LBA Format #%d\n", 194 nsdata->flbas.format); 195 for (i = 0; i <= nsdata->nlbaf; i++) { 196 printf("LBA Format #%d:\n", i); 197 printf(" LBA Data Size: %d\n", 198 1 << nsdata->lbaf[i].lbads); 199 } 200 } 201 202 static uint32_t 203 ns_get_sector_size(struct nvme_namespace_data *nsdata) 204 { 205 206 return (1 << nsdata->lbaf[0].lbads); 207 } 208 209 210 static void 211 devlist(int argc, char *argv[]) 212 { 213 struct nvme_controller_data cdata; 214 struct nvme_namespace_data nsdata; 215 struct stat devstat; 216 char name[64], path[64]; 217 uint32_t i; 218 int ch, ctrlr, exit_code, fd, found; 219 220 exit_code = EX_OK; 221 222 while ((ch = getopt(argc, argv, "")) != -1) { 223 switch ((char)ch) { 224 default: 225 usage(); 226 } 227 } 228 229 ctrlr = -1; 230 found = 0; 231 232 while (1) { 233 ctrlr++; 234 sprintf(name, "nvme%d", ctrlr); 235 sprintf(path, "/dev/%s", name); 236 237 if (stat(path, &devstat) != 0) 238 break; 239 240 found++; 241 242 fd = open(path, O_RDWR); 243 if (fd < 0) { 244 printf("Could not open %s.\n", path); 245 exit_code = EX_NOPERM; 246 continue; 247 } 248 249 if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) { 250 printf("ioctl to %s failed.\n", path); 251 exit_code = EX_IOERR; 252 continue; 253 } 254 255 printf("%6s: %s\n", name, cdata.mn); 256 257 for (i = 0; i < cdata.nn; i++) { 258 sprintf(name, "nvme%dns%d", ctrlr, i+1); 259 sprintf(path, "/dev/%s", name); 260 261 fd = open(path, O_RDWR); 262 if (fd < 0) { 263 printf("Could not open %s.\n", path); 264 exit_code = EX_NOPERM; 265 continue; 266 } 267 if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) { 268 printf("ioctl to %s failed.\n", path); 269 exit_code = EX_IOERR; 270 continue; 271 } 272 printf(" %10s (%lldGB)\n", 273 name, 274 nsdata.nsze * 275 (long long)ns_get_sector_size(&nsdata) / 276 1024 / 1024 / 1024); 277 } 278 } 279 280 if (found == 0) 281 printf("No NVMe controllers found.\n"); 282 283 exit(exit_code); 284 } 285 286 static void 287 identify_ctrlr(int argc, char *argv[]) 288 { 289 struct nvme_controller_data cdata; 290 struct stat devstat; 291 char path[64]; 292 int ch, fd, hexflag = 0, hexlength; 293 int verboseflag = 0; 294 295 while ((ch = getopt(argc, argv, "vx")) != -1) { 296 switch ((char)ch) { 297 case 'v': 298 verboseflag = 1; 299 break; 300 case 'x': 301 hexflag = 1; 302 break; 303 default: 304 usage(); 305 } 306 } 307 308 sprintf(path, "/dev/%s", argv[optind]); 309 310 if (stat(path, &devstat) != 0) { 311 printf("Invalid device node '%s'.\n", path); 312 exit(EX_IOERR); 313 } 314 315 fd = open(path, O_RDWR); 316 if (fd < 0) { 317 printf("Could not open %s.\n", path); 318 exit(EX_NOPERM); 319 } 320 321 if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) { 322 printf("ioctl to %s failed.\n", path); 323 exit(EX_IOERR); 324 } 325 326 if (hexflag == 1) { 327 if (verboseflag == 1) 328 hexlength = sizeof(struct nvme_controller_data); 329 else 330 hexlength = offsetof(struct nvme_controller_data, 331 reserved5); 332 print_controller_hex(&cdata, hexlength); 333 exit(EX_OK); 334 } 335 336 if (verboseflag == 1) { 337 printf("-v not currently supported without -x.\n"); 338 usage(); 339 } 340 341 print_controller(&cdata); 342 exit(EX_OK); 343 } 344 345 static void 346 identify_ns(int argc, char *argv[]) 347 { 348 struct nvme_namespace_data nsdata; 349 struct stat devstat; 350 char path[64]; 351 int ch, fd, hexflag = 0, hexlength; 352 int verboseflag = 0; 353 354 while ((ch = getopt(argc, argv, "vx")) != -1) { 355 switch ((char)ch) { 356 case 'v': 357 verboseflag = 1; 358 break; 359 case 'x': 360 hexflag = 1; 361 break; 362 default: 363 usage(); 364 } 365 } 366 367 sprintf(path, "/dev/%s", argv[optind]); 368 369 if (stat(path, &devstat) != 0) { 370 printf("Invalid device node '%s'.\n", path); 371 exit(EX_IOERR); 372 } 373 374 fd = open(path, O_RDWR); 375 if (fd < 0) { 376 printf("Could not open %s.\n", path); 377 exit(EX_NOPERM); 378 } 379 380 if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) { 381 printf("ioctl to %s failed.\n", path); 382 exit(EX_IOERR); 383 } 384 385 if (hexflag == 1) { 386 if (verboseflag == 1) 387 hexlength = sizeof(struct nvme_namespace_data); 388 else 389 hexlength = offsetof(struct nvme_namespace_data, 390 reserved6); 391 print_namespace_hex(&nsdata, hexlength); 392 exit(EX_OK); 393 } 394 395 if (verboseflag == 1) { 396 printf("-v not currently supported without -x.\n"); 397 usage(); 398 } 399 400 print_namespace(&nsdata); 401 exit(EX_OK); 402 } 403 404 static void 405 identify(int argc, char *argv[]) 406 { 407 char *target; 408 409 if (argc < 2) 410 usage(); 411 412 while (getopt(argc, argv, "vx") != -1) ; 413 414 target = argv[optind]; 415 416 /* Specified device node must have "nvme" in it. */ 417 if (strstr(argv[optind], "nvme") == NULL) { 418 printf("Invalid device node '%s'.\n", argv[optind]); 419 exit(EX_IOERR); 420 } 421 422 optreset = 1; 423 optind = 1; 424 425 /* 426 * If devicde node contains "ns", we consider it a namespace, 427 * otherwise, consider it a controller. 428 */ 429 if (strstr(target, "ns") == NULL) 430 identify_ctrlr(argc, argv); 431 else 432 identify_ns(argc, argv); 433 } 434 435 static void 436 print_perftest(struct nvme_io_test *io_test, bool perthread) 437 { 438 uint32_t i, io_completed = 0, iops, mbps; 439 440 for (i = 0; i < io_test->num_threads; i++) 441 io_completed += io_test->io_completed[i]; 442 443 iops = io_completed/io_test->time; 444 mbps = iops * io_test->size / (1024*1024); 445 446 printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n", 447 io_test->num_threads, io_test->size, 448 io_test->opc == NVME_OPC_READ ? "READ" : "WRITE", 449 io_test->time, iops, mbps); 450 451 if (perthread) 452 for (i = 0; i < io_test->num_threads; i++) 453 printf("\t%3d: %8d IO/s\n", i, 454 io_test->io_completed[i]/io_test->time); 455 456 exit(1); 457 } 458 459 static void 460 perftest_usage(void) 461 { 462 fprintf(stderr, "usage:\n"); 463 fprintf(stderr, PERFTEST_USAGE); 464 exit(EX_USAGE); 465 } 466 467 static void 468 perftest(int argc, char *argv[]) 469 { 470 struct nvme_io_test io_test; 471 int fd; 472 char ch; 473 char *p; 474 const char *name; 475 char path[64]; 476 u_long ioctl_cmd = NVME_IO_TEST; 477 bool nflag, oflag, sflag, tflag; 478 int err, perthread = 0; 479 480 nflag = oflag = sflag = tflag = false; 481 name = NULL; 482 483 memset(&io_test, 0, sizeof(io_test)); 484 485 while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) { 486 switch (ch) { 487 case 'f': 488 if (!strcmp(optarg, "refthread")) 489 io_test.flags |= NVME_TEST_FLAG_REFTHREAD; 490 break; 491 case 'i': 492 if (!strcmp(optarg, "bio") || 493 !strcmp(optarg, "wait")) 494 ioctl_cmd = NVME_BIO_TEST; 495 else if (!strcmp(optarg, "io") || 496 !strcmp(optarg, "intr")) 497 ioctl_cmd = NVME_IO_TEST; 498 break; 499 case 'n': 500 nflag = true; 501 io_test.num_threads = strtoul(optarg, &p, 0); 502 if (p != NULL && *p != '\0') { 503 fprintf(stderr, 504 "\"%s\" not valid number of threads.\n", 505 optarg); 506 perftest_usage(); 507 } else if (io_test.num_threads == 0 || 508 io_test.num_threads > 128) { 509 fprintf(stderr, 510 "\"%s\" not valid number of threads.\n", 511 optarg); 512 perftest_usage(); 513 } 514 break; 515 case 'o': 516 oflag = true; 517 if (!strcmp(optarg, "read") || !strcmp(optarg, "READ")) 518 io_test.opc = NVME_OPC_READ; 519 else if (!strcmp(optarg, "write") || 520 !strcmp(optarg, "WRITE")) 521 io_test.opc = NVME_OPC_WRITE; 522 else { 523 fprintf(stderr, "\"%s\" not valid opcode.\n", 524 optarg); 525 perftest_usage(); 526 } 527 break; 528 case 'p': 529 perthread = 1; 530 break; 531 case 's': 532 sflag = true; 533 io_test.size = strtoul(optarg, &p, 0); 534 if (p == NULL || *p == '\0' || toupper(*p) == 'B') { 535 // do nothing 536 } else if (toupper(*p) == 'K') { 537 io_test.size *= 1024; 538 } else if (toupper(*p) == 'M') { 539 io_test.size *= 1024 * 1024; 540 } else { 541 fprintf(stderr, "\"%s\" not valid size.\n", 542 optarg); 543 perftest_usage(); 544 } 545 break; 546 case 't': 547 tflag = true; 548 io_test.time = strtoul(optarg, &p, 0); 549 if (p != NULL && *p != '\0') { 550 fprintf(stderr, 551 "\"%s\" not valid time duration.\n", 552 optarg); 553 perftest_usage(); 554 } 555 break; 556 } 557 } 558 559 name = argv[optind]; 560 561 if (!nflag || !oflag || !sflag || !tflag || name == NULL) 562 perftest_usage(); 563 564 sprintf(path, "/dev/%s", name); 565 566 fd = open(path, O_RDWR); 567 if (fd < 0) { 568 fprintf(stderr, "%s not valid device.\n", path); 569 perftest_usage(); 570 } 571 572 err = ioctl(fd, ioctl_cmd, &io_test); 573 574 if (err) { 575 fprintf(stderr, "NVME_IO_TEST returned %d\n", errno); 576 exit(EX_IOERR); 577 } 578 579 print_perftest(&io_test, perthread); 580 exit(EX_OK); 581 } 582 583 int 584 main(int argc, char *argv[]) 585 { 586 587 if (argc < 2) 588 usage(); 589 590 if (strcmp(argv[1], "devlist") == 0) 591 devlist(argc-1, &argv[1]); 592 else if (strcmp(argv[1], "identify") == 0) 593 identify(argc-1, &argv[1]); 594 else if (strcmp(argv[1], "perftest") == 0) 595 perftest(argc-1, &argv[1]); 596 597 usage(); 598 599 return (0); 600 } 601