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