nvmecontrol.c revision 240620
1240620Sjimharris/*- 2240620Sjimharris * Copyright (C) 2012 Intel Corporation 3240620Sjimharris * All rights reserved. 4240620Sjimharris * 5240620Sjimharris * Redistribution and use in source and binary forms, with or without 6240620Sjimharris * modification, are permitted provided that the following conditions 7240620Sjimharris * are met: 8240620Sjimharris * 1. Redistributions of source code must retain the above copyright 9240620Sjimharris * notice, this list of conditions and the following disclaimer. 10240620Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 11240620Sjimharris * notice, this list of conditions and the following disclaimer in the 12240620Sjimharris * documentation and/or other materials provided with the distribution. 13240620Sjimharris * 14240620Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15240620Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16240620Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17240620Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18240620Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19240620Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20240620Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21240620Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22240620Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23240620Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24240620Sjimharris * SUCH DAMAGE. 25240620Sjimharris */ 26240620Sjimharris 27240620Sjimharris#include <sys/cdefs.h> 28240620Sjimharris__FBSDID("$FreeBSD: head/sbin/nvmecontrol/nvmecontrol.c 240620 2012-09-17 21:26:55Z jimharris $"); 29240620Sjimharris 30240620Sjimharris#include <sys/param.h> 31240620Sjimharris#include <sys/ioccom.h> 32240620Sjimharris#include <sys/stat.h> 33240620Sjimharris 34240620Sjimharris#include <dev/nvme/nvme.h> 35240620Sjimharris 36240620Sjimharris#include <ctype.h> 37240620Sjimharris#include <errno.h> 38240620Sjimharris#include <fcntl.h> 39240620Sjimharris#include <stdbool.h> 40240620Sjimharris#include <stddef.h> 41240620Sjimharris#include <stdio.h> 42240620Sjimharris#include <stdlib.h> 43240620Sjimharris#include <string.h> 44240620Sjimharris#include <sysexits.h> 45240620Sjimharris#include <unistd.h> 46240620Sjimharris 47240620Sjimharris#define DEVLIST_USAGE \ 48240620Sjimharris" nvmecontrol devlist\n" 49240620Sjimharris 50240620Sjimharris#define IDENTIFY_USAGE \ 51240620Sjimharris" nvmecontrol identify <controller id|namespace id>\n" 52240620Sjimharris 53240620Sjimharris#define PERFTEST_USAGE \ 54240620Sjimharris" nvmecontrol perftest <-n num_threads> <-o read|write>\n" \ 55240620Sjimharris" <-s size_in_bytes> <-t time_in_seconds>\n" \ 56240620Sjimharris" <-i intr|wait> [-f refthread] [-p]\n" \ 57240620Sjimharris" <namespace id>\n" 58240620Sjimharris 59240620Sjimharrisstatic void perftest_usage(void); 60240620Sjimharris 61240620Sjimharrisstatic void 62240620Sjimharrisusage(void) 63240620Sjimharris{ 64240620Sjimharris fprintf(stderr, "usage:\n"); 65240620Sjimharris fprintf(stderr, DEVLIST_USAGE); 66240620Sjimharris fprintf(stderr, IDENTIFY_USAGE); 67240620Sjimharris fprintf(stderr, PERFTEST_USAGE); 68240620Sjimharris exit(EX_USAGE); 69240620Sjimharris} 70240620Sjimharris 71240620Sjimharrisstatic void 72240620Sjimharrisprint_controller_hex(struct nvme_controller_data *cdata, uint32_t length) 73240620Sjimharris{ 74240620Sjimharris uint32_t *p; 75240620Sjimharris uint32_t i, j; 76240620Sjimharris 77240620Sjimharris p = (uint32_t *)cdata; 78240620Sjimharris length /= sizeof(uint32_t); 79240620Sjimharris 80240620Sjimharris for (i = 0; i < length; i+=8) { 81240620Sjimharris printf("%03x: ", i*4); 82240620Sjimharris for (j = 0; j < 8; j++) 83240620Sjimharris printf("%08x ", p[i+j]); 84240620Sjimharris printf("\n"); 85240620Sjimharris } 86240620Sjimharris 87240620Sjimharris printf("\n"); 88240620Sjimharris} 89240620Sjimharris 90240620Sjimharrisstatic void 91240620Sjimharrisprint_controller(struct nvme_controller_data *cdata) 92240620Sjimharris{ 93240620Sjimharris printf("Controller Capabilities/Features\n"); 94240620Sjimharris printf("================================\n"); 95240620Sjimharris printf("Vendor ID: %04x\n", cdata->vid); 96240620Sjimharris printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 97240620Sjimharris printf("Serial Number: %s\n", cdata->sn); 98240620Sjimharris printf("Model Number: %s\n", cdata->mn); 99240620Sjimharris printf("Firmware Version: %s\n", cdata->fr); 100240620Sjimharris printf("Recommended Arb Burst: %d\n", cdata->rab); 101240620Sjimharris printf("IEEE OUI Identifier: %02x %02x %02x\n", 102240620Sjimharris cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 103240620Sjimharris printf("Multi-Interface Cap: %02x\n", cdata->mic); 104240620Sjimharris /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 105240620Sjimharris printf("Max Data Transfer Size: "); 106240620Sjimharris if (cdata->mdts == 0) 107240620Sjimharris printf("Unlimited\n"); 108240620Sjimharris else 109240620Sjimharris printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); 110240620Sjimharris printf("\n"); 111240620Sjimharris 112240620Sjimharris printf("Admin Command Set Attributes\n"); 113240620Sjimharris printf("============================\n"); 114240620Sjimharris printf("Security Send/Receive: %s\n", 115240620Sjimharris cdata->oacs.security ? "Supported" : "Not Supported"); 116240620Sjimharris printf("Format NVM: %s\n", 117240620Sjimharris cdata->oacs.format ? "Supported" : "Not Supported"); 118240620Sjimharris printf("Firmware Activate/Download: %s\n", 119240620Sjimharris cdata->oacs.firmware ? "Supported" : "Not Supported"); 120240620Sjimharris printf("Abort Command Limit: %d\n", cdata->acl+1); 121240620Sjimharris printf("Async Event Request Limit: %d\n", cdata->aerl+1); 122240620Sjimharris printf("Number of Firmware Slots: "); 123240620Sjimharris if (cdata->oacs.firmware != 0) 124240620Sjimharris printf("%d\n", cdata->frmw.num_slots); 125240620Sjimharris else 126240620Sjimharris printf("N/A\n"); 127240620Sjimharris printf("Firmware Slot 1 Read-Only: "); 128240620Sjimharris if (cdata->oacs.firmware != 0) 129240620Sjimharris printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); 130240620Sjimharris else 131240620Sjimharris printf("N/A\n"); 132240620Sjimharris printf("Per-Namespace SMART Log: %s\n", 133240620Sjimharris cdata->lpa.ns_smart ? "Yes" : "No"); 134240620Sjimharris printf("Error Log Page Entries: %d\n", cdata->elpe+1); 135240620Sjimharris printf("Number of Power States: %d\n", cdata->npss+1); 136240620Sjimharris printf("\n"); 137240620Sjimharris 138240620Sjimharris printf("NVM Command Set Attributes\n"); 139240620Sjimharris printf("==========================\n"); 140240620Sjimharris printf("Submission Queue Entry Size\n"); 141240620Sjimharris printf(" Max: %d\n", 1 << cdata->sqes.max); 142240620Sjimharris printf(" Min: %d\n", 1 << cdata->sqes.min); 143240620Sjimharris printf("Completion Queue Entry Size\n"); 144240620Sjimharris printf(" Max: %d\n", 1 << cdata->cqes.max); 145240620Sjimharris printf(" Min: %d\n", 1 << cdata->cqes.min); 146240620Sjimharris printf("Number of Namespaces: %d\n", cdata->nn); 147240620Sjimharris printf("Compare Command: %s\n", 148240620Sjimharris cdata->oncs.compare ? "Supported" : "Not Supported"); 149240620Sjimharris printf("Write Uncorrectable Command: %s\n", 150240620Sjimharris cdata->oncs.write_unc ? "Supported" : "Not Supported"); 151240620Sjimharris printf("Dataset Management Command: %s\n", 152240620Sjimharris cdata->oncs.dsm ? "Supported" : "Not Supported"); 153240620Sjimharris printf("Volatile Write Cache: %s\n", 154240620Sjimharris cdata->vwc.present ? "Present" : "Not Present"); 155240620Sjimharris} 156240620Sjimharris 157240620Sjimharrisstatic void 158240620Sjimharrisprint_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length) 159240620Sjimharris{ 160240620Sjimharris uint32_t *p; 161240620Sjimharris uint32_t i, j; 162240620Sjimharris 163240620Sjimharris p = (uint32_t *)nsdata; 164240620Sjimharris length /= sizeof(uint32_t); 165240620Sjimharris 166240620Sjimharris for (i = 0; i < length; i+=8) { 167240620Sjimharris printf("%03x: ", i*4); 168240620Sjimharris for (j = 0; j < 8; j++) 169240620Sjimharris printf("%08x ", p[i+j]); 170240620Sjimharris printf("\n"); 171240620Sjimharris } 172240620Sjimharris 173240620Sjimharris printf("\n"); 174240620Sjimharris} 175240620Sjimharris 176240620Sjimharrisstatic void 177240620Sjimharrisprint_namespace(struct nvme_namespace_data *nsdata) 178240620Sjimharris{ 179240620Sjimharris uint32_t i; 180240620Sjimharris 181240620Sjimharris printf("Size (in LBAs): %lld (%lldM)\n", 182240620Sjimharris (long long)nsdata->nsze, 183240620Sjimharris (long long)nsdata->nsze / 1024 / 1024); 184240620Sjimharris printf("Capacity (in LBAs): %lld (%lldM)\n", 185240620Sjimharris (long long)nsdata->ncap, 186240620Sjimharris (long long)nsdata->ncap / 1024 / 1024); 187240620Sjimharris printf("Utilization (in LBAs): %lld (%lldM)\n", 188240620Sjimharris (long long)nsdata->nuse, 189240620Sjimharris (long long)nsdata->nuse / 1024 / 1024); 190240620Sjimharris printf("Thin Provisioning: %s\n", 191240620Sjimharris nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); 192240620Sjimharris printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 193240620Sjimharris printf("Current LBA Format: LBA Format #%d\n", 194240620Sjimharris nsdata->flbas.format); 195240620Sjimharris for (i = 0; i <= nsdata->nlbaf; i++) { 196240620Sjimharris printf("LBA Format #%d:\n", i); 197240620Sjimharris printf(" LBA Data Size: %d\n", 198240620Sjimharris 1 << nsdata->lbaf[i].lbads); 199240620Sjimharris } 200240620Sjimharris} 201240620Sjimharris 202240620Sjimharrisstatic uint32_t 203240620Sjimharrisns_get_sector_size(struct nvme_namespace_data *nsdata) 204240620Sjimharris{ 205240620Sjimharris 206240620Sjimharris return (1 << nsdata->lbaf[0].lbads); 207240620Sjimharris} 208240620Sjimharris 209240620Sjimharris 210240620Sjimharrisstatic void 211240620Sjimharrisdevlist(int argc, char *argv[]) 212240620Sjimharris{ 213240620Sjimharris struct nvme_controller_data cdata; 214240620Sjimharris struct nvme_namespace_data nsdata; 215240620Sjimharris struct stat devstat; 216240620Sjimharris char name[64], path[64]; 217240620Sjimharris uint32_t i; 218240620Sjimharris int ch, ctrlr, exit_code, fd, found; 219240620Sjimharris 220240620Sjimharris exit_code = EX_OK; 221240620Sjimharris 222240620Sjimharris while ((ch = getopt(argc, argv, "")) != -1) { 223240620Sjimharris switch ((char)ch) { 224240620Sjimharris default: 225240620Sjimharris usage(); 226240620Sjimharris } 227240620Sjimharris } 228240620Sjimharris 229240620Sjimharris ctrlr = -1; 230240620Sjimharris found = 0; 231240620Sjimharris 232240620Sjimharris while (1) { 233240620Sjimharris ctrlr++; 234240620Sjimharris sprintf(name, "nvme%d", ctrlr); 235240620Sjimharris sprintf(path, "/dev/%s", name); 236240620Sjimharris 237240620Sjimharris if (stat(path, &devstat) != 0) 238240620Sjimharris break; 239240620Sjimharris 240240620Sjimharris found++; 241240620Sjimharris 242240620Sjimharris fd = open(path, O_RDWR); 243240620Sjimharris if (fd < 0) { 244240620Sjimharris printf("Could not open %s.\n", path); 245240620Sjimharris exit_code = EX_NOPERM; 246240620Sjimharris continue; 247240620Sjimharris } 248240620Sjimharris 249240620Sjimharris if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) { 250240620Sjimharris printf("ioctl to %s failed.\n", path); 251240620Sjimharris exit_code = EX_IOERR; 252240620Sjimharris continue; 253240620Sjimharris } 254240620Sjimharris 255240620Sjimharris printf("%6s: %s\n", name, cdata.mn); 256240620Sjimharris 257240620Sjimharris for (i = 0; i < cdata.nn; i++) { 258240620Sjimharris sprintf(name, "nvme%dns%d", ctrlr, i+1); 259240620Sjimharris sprintf(path, "/dev/%s", name); 260240620Sjimharris 261240620Sjimharris fd = open(path, O_RDWR); 262240620Sjimharris if (fd < 0) { 263240620Sjimharris printf("Could not open %s.\n", path); 264240620Sjimharris exit_code = EX_NOPERM; 265240620Sjimharris continue; 266240620Sjimharris } 267240620Sjimharris if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) { 268240620Sjimharris printf("ioctl to %s failed.\n", path); 269240620Sjimharris exit_code = EX_IOERR; 270240620Sjimharris continue; 271240620Sjimharris } 272240620Sjimharris printf(" %10s (%lldGB)\n", 273240620Sjimharris name, 274240620Sjimharris nsdata.nsze * 275240620Sjimharris (long long)ns_get_sector_size(&nsdata) / 276240620Sjimharris 1024 / 1024 / 1024); 277240620Sjimharris } 278240620Sjimharris } 279240620Sjimharris 280240620Sjimharris if (found == 0) 281240620Sjimharris printf("No NVMe controllers found.\n"); 282240620Sjimharris 283240620Sjimharris exit(exit_code); 284240620Sjimharris} 285240620Sjimharris 286240620Sjimharrisstatic void 287240620Sjimharrisidentify_ctrlr(int argc, char *argv[]) 288240620Sjimharris{ 289240620Sjimharris struct nvme_controller_data cdata; 290240620Sjimharris struct stat devstat; 291240620Sjimharris char path[64]; 292240620Sjimharris int ch, fd, hexflag = 0, hexlength; 293240620Sjimharris int verboseflag = 0; 294240620Sjimharris 295240620Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 296240620Sjimharris switch ((char)ch) { 297240620Sjimharris case 'v': 298240620Sjimharris verboseflag = 1; 299240620Sjimharris break; 300240620Sjimharris case 'x': 301240620Sjimharris hexflag = 1; 302240620Sjimharris break; 303240620Sjimharris default: 304240620Sjimharris usage(); 305240620Sjimharris } 306240620Sjimharris } 307240620Sjimharris 308240620Sjimharris sprintf(path, "/dev/%s", argv[optind]); 309240620Sjimharris 310240620Sjimharris if (stat(path, &devstat) != 0) { 311240620Sjimharris printf("Invalid device node '%s'.\n", path); 312240620Sjimharris exit(EX_IOERR); 313240620Sjimharris } 314240620Sjimharris 315240620Sjimharris fd = open(path, O_RDWR); 316240620Sjimharris if (fd < 0) { 317240620Sjimharris printf("Could not open %s.\n", path); 318240620Sjimharris exit(EX_NOPERM); 319240620Sjimharris } 320240620Sjimharris 321240620Sjimharris if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) { 322240620Sjimharris printf("ioctl to %s failed.\n", path); 323240620Sjimharris exit(EX_IOERR); 324240620Sjimharris } 325240620Sjimharris 326240620Sjimharris if (hexflag == 1) { 327240620Sjimharris if (verboseflag == 1) 328240620Sjimharris hexlength = sizeof(struct nvme_controller_data); 329240620Sjimharris else 330240620Sjimharris hexlength = offsetof(struct nvme_controller_data, 331240620Sjimharris reserved5); 332240620Sjimharris print_controller_hex(&cdata, hexlength); 333240620Sjimharris exit(EX_OK); 334240620Sjimharris } 335240620Sjimharris 336240620Sjimharris if (verboseflag == 1) { 337240620Sjimharris printf("-v not currently supported without -x.\n"); 338240620Sjimharris usage(); 339240620Sjimharris } 340240620Sjimharris 341240620Sjimharris print_controller(&cdata); 342240620Sjimharris exit(EX_OK); 343240620Sjimharris} 344240620Sjimharris 345240620Sjimharrisstatic void 346240620Sjimharrisidentify_ns(int argc, char *argv[]) 347240620Sjimharris{ 348240620Sjimharris struct nvme_namespace_data nsdata; 349240620Sjimharris struct stat devstat; 350240620Sjimharris char path[64]; 351240620Sjimharris int ch, fd, hexflag = 0, hexlength; 352240620Sjimharris int verboseflag = 0; 353240620Sjimharris 354240620Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 355240620Sjimharris switch ((char)ch) { 356240620Sjimharris case 'v': 357240620Sjimharris verboseflag = 1; 358240620Sjimharris break; 359240620Sjimharris case 'x': 360240620Sjimharris hexflag = 1; 361240620Sjimharris break; 362240620Sjimharris default: 363240620Sjimharris usage(); 364240620Sjimharris } 365240620Sjimharris } 366240620Sjimharris 367240620Sjimharris sprintf(path, "/dev/%s", argv[optind]); 368240620Sjimharris 369240620Sjimharris if (stat(path, &devstat) != 0) { 370240620Sjimharris printf("Invalid device node '%s'.\n", path); 371240620Sjimharris exit(EX_IOERR); 372240620Sjimharris } 373240620Sjimharris 374240620Sjimharris fd = open(path, O_RDWR); 375240620Sjimharris if (fd < 0) { 376240620Sjimharris printf("Could not open %s.\n", path); 377240620Sjimharris exit(EX_NOPERM); 378240620Sjimharris } 379240620Sjimharris 380240620Sjimharris if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) { 381240620Sjimharris printf("ioctl to %s failed.\n", path); 382240620Sjimharris exit(EX_IOERR); 383240620Sjimharris } 384240620Sjimharris 385240620Sjimharris if (hexflag == 1) { 386240620Sjimharris if (verboseflag == 1) 387240620Sjimharris hexlength = sizeof(struct nvme_namespace_data); 388240620Sjimharris else 389240620Sjimharris hexlength = offsetof(struct nvme_namespace_data, 390240620Sjimharris reserved6); 391240620Sjimharris print_namespace_hex(&nsdata, hexlength); 392240620Sjimharris exit(EX_OK); 393240620Sjimharris } 394240620Sjimharris 395240620Sjimharris if (verboseflag == 1) { 396240620Sjimharris printf("-v not currently supported without -x.\n"); 397240620Sjimharris usage(); 398240620Sjimharris } 399240620Sjimharris 400240620Sjimharris print_namespace(&nsdata); 401240620Sjimharris exit(EX_OK); 402240620Sjimharris} 403240620Sjimharris 404240620Sjimharrisstatic void 405240620Sjimharrisidentify(int argc, char *argv[]) 406240620Sjimharris{ 407240620Sjimharris char *target; 408240620Sjimharris 409240620Sjimharris if (argc < 2) 410240620Sjimharris usage(); 411240620Sjimharris 412240620Sjimharris while (getopt(argc, argv, "vx") != -1) ; 413240620Sjimharris 414240620Sjimharris target = argv[optind]; 415240620Sjimharris 416240620Sjimharris /* Specified device node must have "nvme" in it. */ 417240620Sjimharris if (strstr(argv[optind], "nvme") == NULL) { 418240620Sjimharris printf("Invalid device node '%s'.\n", argv[optind]); 419240620Sjimharris exit(EX_IOERR); 420240620Sjimharris } 421240620Sjimharris 422240620Sjimharris optreset = 1; 423240620Sjimharris optind = 1; 424240620Sjimharris 425240620Sjimharris /* 426240620Sjimharris * If devicde node contains "ns", we consider it a namespace, 427240620Sjimharris * otherwise, consider it a controller. 428240620Sjimharris */ 429240620Sjimharris if (strstr(target, "ns") == NULL) 430240620Sjimharris identify_ctrlr(argc, argv); 431240620Sjimharris else 432240620Sjimharris identify_ns(argc, argv); 433240620Sjimharris} 434240620Sjimharris 435240620Sjimharrisstatic void 436240620Sjimharrisprint_perftest(struct nvme_io_test *io_test, bool perthread) 437240620Sjimharris{ 438240620Sjimharris uint32_t i, io_completed = 0, iops, mbps; 439240620Sjimharris 440240620Sjimharris for (i = 0; i < io_test->num_threads; i++) 441240620Sjimharris io_completed += io_test->io_completed[i]; 442240620Sjimharris 443240620Sjimharris iops = io_completed/io_test->time; 444240620Sjimharris mbps = iops * io_test->size / (1024*1024); 445240620Sjimharris 446240620Sjimharris printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n", 447240620Sjimharris io_test->num_threads, io_test->size, 448240620Sjimharris io_test->opc == NVME_OPC_READ ? "READ" : "WRITE", 449240620Sjimharris io_test->time, iops, mbps); 450240620Sjimharris 451240620Sjimharris if (perthread) 452240620Sjimharris for (i = 0; i < io_test->num_threads; i++) 453240620Sjimharris printf("\t%3d: %8d IO/s\n", i, 454240620Sjimharris io_test->io_completed[i]/io_test->time); 455240620Sjimharris 456240620Sjimharris exit(1); 457240620Sjimharris} 458240620Sjimharris 459240620Sjimharrisstatic void 460240620Sjimharrisperftest_usage(void) 461240620Sjimharris{ 462240620Sjimharris fprintf(stderr, "usage:\n"); 463240620Sjimharris fprintf(stderr, PERFTEST_USAGE); 464240620Sjimharris exit(EX_USAGE); 465240620Sjimharris} 466240620Sjimharris 467240620Sjimharrisstatic void 468240620Sjimharrisperftest(int argc, char *argv[]) 469240620Sjimharris{ 470240620Sjimharris struct nvme_io_test io_test; 471240620Sjimharris int fd; 472240620Sjimharris char ch; 473240620Sjimharris char *p; 474240620Sjimharris const char *name; 475240620Sjimharris char path[64]; 476240620Sjimharris u_long ioctl_cmd = NVME_IO_TEST; 477240620Sjimharris bool nflag, oflag, sflag, tflag; 478240620Sjimharris int err, perthread = 0; 479240620Sjimharris 480240620Sjimharris nflag = oflag = sflag = tflag = false; 481240620Sjimharris name = NULL; 482240620Sjimharris 483240620Sjimharris memset(&io_test, 0, sizeof(io_test)); 484240620Sjimharris 485240620Sjimharris while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) { 486240620Sjimharris switch (ch) { 487240620Sjimharris case 'f': 488240620Sjimharris if (!strcmp(optarg, "refthread")) 489240620Sjimharris io_test.flags |= NVME_TEST_FLAG_REFTHREAD; 490240620Sjimharris break; 491240620Sjimharris case 'i': 492240620Sjimharris if (!strcmp(optarg, "bio") || 493240620Sjimharris !strcmp(optarg, "wait")) 494240620Sjimharris ioctl_cmd = NVME_BIO_TEST; 495240620Sjimharris else if (!strcmp(optarg, "io") || 496240620Sjimharris !strcmp(optarg, "intr")) 497240620Sjimharris ioctl_cmd = NVME_IO_TEST; 498240620Sjimharris break; 499240620Sjimharris case 'n': 500240620Sjimharris nflag = true; 501240620Sjimharris io_test.num_threads = strtoul(optarg, &p, 0); 502240620Sjimharris if (p != NULL && *p != '\0') { 503240620Sjimharris fprintf(stderr, 504240620Sjimharris "\"%s\" not valid number of threads.\n", 505240620Sjimharris optarg); 506240620Sjimharris perftest_usage(); 507240620Sjimharris } else if (io_test.num_threads == 0 || 508240620Sjimharris io_test.num_threads > 128) { 509240620Sjimharris fprintf(stderr, 510240620Sjimharris "\"%s\" not valid number of threads.\n", 511240620Sjimharris optarg); 512240620Sjimharris perftest_usage(); 513240620Sjimharris } 514240620Sjimharris break; 515240620Sjimharris case 'o': 516240620Sjimharris oflag = true; 517240620Sjimharris if (!strcmp(optarg, "read") || !strcmp(optarg, "READ")) 518240620Sjimharris io_test.opc = NVME_OPC_READ; 519240620Sjimharris else if (!strcmp(optarg, "write") || 520240620Sjimharris !strcmp(optarg, "WRITE")) 521240620Sjimharris io_test.opc = NVME_OPC_WRITE; 522240620Sjimharris else { 523240620Sjimharris fprintf(stderr, "\"%s\" not valid opcode.\n", 524240620Sjimharris optarg); 525240620Sjimharris perftest_usage(); 526240620Sjimharris } 527240620Sjimharris break; 528240620Sjimharris case 'p': 529240620Sjimharris perthread = 1; 530240620Sjimharris break; 531240620Sjimharris case 's': 532240620Sjimharris sflag = true; 533240620Sjimharris io_test.size = strtoul(optarg, &p, 0); 534240620Sjimharris if (p == NULL || *p == '\0' || toupper(*p) == 'B') { 535240620Sjimharris // do nothing 536240620Sjimharris } else if (toupper(*p) == 'K') { 537240620Sjimharris io_test.size *= 1024; 538240620Sjimharris } else if (toupper(*p) == 'M') { 539240620Sjimharris io_test.size *= 1024 * 1024; 540240620Sjimharris } else { 541240620Sjimharris fprintf(stderr, "\"%s\" not valid size.\n", 542240620Sjimharris optarg); 543240620Sjimharris perftest_usage(); 544240620Sjimharris } 545240620Sjimharris break; 546240620Sjimharris case 't': 547240620Sjimharris tflag = true; 548240620Sjimharris io_test.time = strtoul(optarg, &p, 0); 549240620Sjimharris if (p != NULL && *p != '\0') { 550240620Sjimharris fprintf(stderr, 551240620Sjimharris "\"%s\" not valid time duration.\n", 552240620Sjimharris optarg); 553240620Sjimharris perftest_usage(); 554240620Sjimharris } 555240620Sjimharris break; 556240620Sjimharris } 557240620Sjimharris } 558240620Sjimharris 559240620Sjimharris name = argv[optind]; 560240620Sjimharris 561240620Sjimharris if (!nflag || !oflag || !sflag || !tflag || name == NULL) 562240620Sjimharris perftest_usage(); 563240620Sjimharris 564240620Sjimharris sprintf(path, "/dev/%s", name); 565240620Sjimharris 566240620Sjimharris fd = open(path, O_RDWR); 567240620Sjimharris if (fd < 0) { 568240620Sjimharris fprintf(stderr, "%s not valid device.\n", path); 569240620Sjimharris perftest_usage(); 570240620Sjimharris } 571240620Sjimharris 572240620Sjimharris err = ioctl(fd, ioctl_cmd, &io_test); 573240620Sjimharris 574240620Sjimharris if (err) { 575240620Sjimharris fprintf(stderr, "NVME_IO_TEST returned %d\n", errno); 576240620Sjimharris exit(EX_IOERR); 577240620Sjimharris } 578240620Sjimharris 579240620Sjimharris print_perftest(&io_test, perthread); 580240620Sjimharris exit(EX_OK); 581240620Sjimharris} 582240620Sjimharris 583240620Sjimharrisint 584240620Sjimharrismain(int argc, char *argv[]) 585240620Sjimharris{ 586240620Sjimharris 587240620Sjimharris if (argc < 2) 588240620Sjimharris usage(); 589240620Sjimharris 590240620Sjimharris if (strcmp(argv[1], "devlist") == 0) 591240620Sjimharris devlist(argc-1, &argv[1]); 592240620Sjimharris else if (strcmp(argv[1], "identify") == 0) 593240620Sjimharris identify(argc-1, &argv[1]); 594240620Sjimharris else if (strcmp(argv[1], "perftest") == 0) 595240620Sjimharris perftest(argc-1, &argv[1]); 596240620Sjimharris 597240620Sjimharris usage(); 598240620Sjimharris 599240620Sjimharris return (0); 600240620Sjimharris} 601