nvmecontrol.c revision 252655
186227Stmm/*- 286227Stmm * Copyright (C) 2012-2013 Intel Corporation 386227Stmm * All rights reserved. 486227Stmm * 586227Stmm * Redistribution and use in source and binary forms, with or without 686227Stmm * modification, are permitted provided that the following conditions 786227Stmm * are met: 886227Stmm * 1. Redistributions of source code must retain the above copyright 986227Stmm * notice, this list of conditions and the following disclaimer. 1086227Stmm * 2. Redistributions in binary form must reproduce the above copyright 1186227Stmm * notice, this list of conditions and the following disclaimer in the 1286227Stmm * documentation and/or other materials provided with the distribution. 1386227Stmm * 1486227Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1586227Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1686227Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1786227Stmm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1886227Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1986227Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2086227Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2186227Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2286227Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2386227Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2486227Stmm * SUCH DAMAGE. 2586227Stmm */ 2686227Stmm 2786227Stmm#include <sys/cdefs.h> 2886227Stmm__FBSDID("$FreeBSD: stable/9/sbin/nvmecontrol/nvmecontrol.c 252655 2013-07-03 23:42:12Z jimharris $"); 2986227Stmm 3086227Stmm#include <sys/param.h> 3186227Stmm#include <sys/ioccom.h> 3286227Stmm#include <sys/stat.h> 3386227Stmm 3486227Stmm#include <dev/nvme/nvme.h> 3586227Stmm 3686227Stmm#include <ctype.h> 3786227Stmm#include <errno.h> 3886227Stmm#include <fcntl.h> 3986227Stmm#include <stdbool.h> 4086227Stmm#include <stddef.h> 4186227Stmm#include <stdio.h> 4286227Stmm#include <stdlib.h> 4386227Stmm#include <string.h> 4486227Stmm#include <sysexits.h> 4586227Stmm#include <unistd.h> 4686227Stmm 4786227Stmm#define DEVLIST_USAGE \ 4886227Stmm" nvmecontrol devlist\n" 4986227Stmm 5086227Stmm#define IDENTIFY_USAGE \ 5186227Stmm" nvmecontrol identify <controller id|namespace id>\n" 5286227Stmm 5386227Stmm#define PERFTEST_USAGE \ 5486227Stmm" nvmecontrol perftest <-n num_threads> <-o read|write>\n" \ 5586227Stmm" <-s size_in_bytes> <-t time_in_seconds>\n" \ 5686227Stmm" <-i intr|wait> [-f refthread] [-p]\n" \ 5786227Stmm" <namespace id>\n" 5886227Stmm 5986227Stmm#define RESET_USAGE \ 6086227Stmm" nvmecontrol reset <controller id>\n" 6186227Stmm 6286227Stmmstatic void perftest_usage(void); 6386227Stmm 6486227Stmmstatic void 6586227Stmmusage(void) 6686227Stmm{ 6786227Stmm fprintf(stderr, "usage:\n"); 6886227Stmm fprintf(stderr, DEVLIST_USAGE); 6986227Stmm fprintf(stderr, IDENTIFY_USAGE); 7086227Stmm fprintf(stderr, RESET_USAGE); 7188823Stmm fprintf(stderr, PERFTEST_USAGE); 7286227Stmm exit(EX_USAGE); 7388823Stmm} 7486227Stmm 7586227Stmmstatic void 7686227Stmmprint_controller_hex(struct nvme_controller_data *cdata, uint32_t length) 7786227Stmm{ 7886227Stmm uint32_t *p; 7986227Stmm uint32_t i, j; 8086227Stmm 8186227Stmm p = (uint32_t *)cdata; 8286227Stmm length /= sizeof(uint32_t); 8386227Stmm 8486227Stmm for (i = 0; i < length; i+=8) { 8586227Stmm printf("%03x: ", i*4); 8686227Stmm for (j = 0; j < 8; j++) 8786227Stmm printf("%08x ", p[i+j]); 8886227Stmm printf("\n"); 8986227Stmm } 9086227Stmm 9186227Stmm printf("\n"); 9286227Stmm} 9386227Stmm 9486227Stmmstatic void 9586227Stmmprint_controller(struct nvme_controller_data *cdata) 9686227Stmm{ 9786227Stmm printf("Controller Capabilities/Features\n"); 9886227Stmm printf("================================\n"); 9986227Stmm printf("Vendor ID: %04x\n", cdata->vid); 10086227Stmm printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 10188823Stmm printf("Serial Number: %s\n", cdata->sn); 10286227Stmm printf("Model Number: %s\n", cdata->mn); 10386227Stmm printf("Firmware Version: %s\n", cdata->fr); 10486227Stmm printf("Recommended Arb Burst: %d\n", cdata->rab); 10586227Stmm printf("IEEE OUI Identifier: %02x %02x %02x\n", 10686227Stmm cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 10786227Stmm printf("Multi-Interface Cap: %02x\n", cdata->mic); 10886227Stmm /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 10988823Stmm printf("Max Data Transfer Size: "); 11088823Stmm if (cdata->mdts == 0) 11188823Stmm printf("Unlimited\n"); 11288823Stmm else 11388823Stmm printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); 11486227Stmm printf("\n"); 11586227Stmm 11686227Stmm printf("Admin Command Set Attributes\n"); 11786227Stmm printf("============================\n"); 11886227Stmm printf("Security Send/Receive: %s\n", 11986227Stmm cdata->oacs.security ? "Supported" : "Not Supported"); 12086227Stmm printf("Format NVM: %s\n", 12186227Stmm cdata->oacs.format ? "Supported" : "Not Supported"); 12286227Stmm printf("Firmware Activate/Download: %s\n", 12386227Stmm cdata->oacs.firmware ? "Supported" : "Not Supported"); 12486227Stmm printf("Abort Command Limit: %d\n", cdata->acl+1); 12586227Stmm printf("Async Event Request Limit: %d\n", cdata->aerl+1); 12686227Stmm printf("Number of Firmware Slots: "); 12786227Stmm if (cdata->oacs.firmware != 0) 12886227Stmm printf("%d\n", cdata->frmw.num_slots); 12986227Stmm else 13086227Stmm printf("N/A\n"); 13186227Stmm printf("Firmware Slot 1 Read-Only: "); 13286227Stmm if (cdata->oacs.firmware != 0) 13386227Stmm printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); 13486227Stmm else 13586227Stmm printf("N/A\n"); 13686227Stmm printf("Per-Namespace SMART Log: %s\n", 13786227Stmm cdata->lpa.ns_smart ? "Yes" : "No"); 13886227Stmm printf("Error Log Page Entries: %d\n", cdata->elpe+1); 13986227Stmm printf("Number of Power States: %d\n", cdata->npss+1); 14086227Stmm printf("\n"); 14186227Stmm 14286227Stmm printf("NVM Command Set Attributes\n"); 14386227Stmm printf("==========================\n"); 14486227Stmm printf("Submission Queue Entry Size\n"); 14586227Stmm printf(" Max: %d\n", 1 << cdata->sqes.max); 14686227Stmm printf(" Min: %d\n", 1 << cdata->sqes.min); 14786227Stmm printf("Completion Queue Entry Size\n"); 14886227Stmm printf(" Max: %d\n", 1 << cdata->cqes.max); 14986227Stmm printf(" Min: %d\n", 1 << cdata->cqes.min); 15086227Stmm printf("Number of Namespaces: %d\n", cdata->nn); 15186227Stmm printf("Compare Command: %s\n", 15286227Stmm cdata->oncs.compare ? "Supported" : "Not Supported"); 15386227Stmm printf("Write Uncorrectable Command: %s\n", 15486227Stmm cdata->oncs.write_unc ? "Supported" : "Not Supported"); 15586227Stmm printf("Dataset Management Command: %s\n", 15686227Stmm cdata->oncs.dsm ? "Supported" : "Not Supported"); 15786227Stmm printf("Volatile Write Cache: %s\n", 15888823Stmm cdata->vwc.present ? "Present" : "Not Present"); 15986227Stmm} 16086227Stmm 16186227Stmmstatic void 16286227Stmmprint_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length) 16386227Stmm{ 16486227Stmm uint32_t *p; 16586227Stmm uint32_t i, j; 16690622Stmm 16790622Stmm p = (uint32_t *)nsdata; 16890622Stmm length /= sizeof(uint32_t); 16986227Stmm 17090622Stmm for (i = 0; i < length; i+=8) { 17186227Stmm printf("%03x: ", i*4); 17286227Stmm for (j = 0; j < 8; j++) 17390622Stmm printf("%08x ", p[i+j]); 17486227Stmm printf("\n"); 17586227Stmm } 17686227Stmm 17786227Stmm printf("\n"); 17886227Stmm} 17986227Stmm 18086227Stmmstatic void 18186227Stmmprint_namespace(struct nvme_namespace_data *nsdata) 18286227Stmm{ 18386227Stmm uint32_t i; 18486227Stmm 18586227Stmm printf("Size (in LBAs): %lld (%lldM)\n", 18686227Stmm (long long)nsdata->nsze, 18786227Stmm (long long)nsdata->nsze / 1024 / 1024); 18886227Stmm printf("Capacity (in LBAs): %lld (%lldM)\n", 18986227Stmm (long long)nsdata->ncap, 19086227Stmm (long long)nsdata->ncap / 1024 / 1024); 19186227Stmm printf("Utilization (in LBAs): %lld (%lldM)\n", 19286227Stmm (long long)nsdata->nuse, 19386227Stmm (long long)nsdata->nuse / 1024 / 1024); 19486227Stmm printf("Thin Provisioning: %s\n", 19586227Stmm nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); 19686227Stmm printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 19786227Stmm printf("Current LBA Format: LBA Format #%d\n", 19886227Stmm nsdata->flbas.format); 19986227Stmm for (i = 0; i <= nsdata->nlbaf; i++) { 20086227Stmm printf("LBA Format #%d:\n", i); 20186227Stmm printf(" LBA Data Size: %d\n", 20286227Stmm 1 << nsdata->lbaf[i].lbads); 20386227Stmm } 20486227Stmm} 20586227Stmm 20686227Stmmstatic uint32_t 20788823Stmmns_get_sector_size(struct nvme_namespace_data *nsdata) 20886227Stmm{ 20986227Stmm 21086227Stmm return (1 << nsdata->lbaf[0].lbads); 21186227Stmm} 21286227Stmm 21388823Stmmstatic void 21488823Stmmread_controller_data(int fd, struct nvme_controller_data *cdata) 21588823Stmm{ 21688823Stmm struct nvme_pt_command pt; 21788823Stmm 21888823Stmm memset(&pt, 0, sizeof(pt)); 21988823Stmm pt.cmd.opc = NVME_OPC_IDENTIFY; 22088823Stmm pt.cmd.cdw10 = 1; 22188823Stmm pt.buf = cdata; 22288823Stmm pt.len = sizeof(*cdata); 22386227Stmm pt.is_read = 1; 22486227Stmm 22586227Stmm if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) { 22686227Stmm printf("Identify request failed. errno=%d (%s)\n", 22786227Stmm errno, strerror(errno)); 22886227Stmm exit(EX_IOERR); 22986227Stmm } 23086227Stmm 23186227Stmm if (nvme_completion_is_error(&pt.cpl)) { 23286227Stmm printf("Passthrough command returned error.\n"); 23386227Stmm exit(EX_IOERR); 23488823Stmm } 23586227Stmm} 23686227Stmm 23786227Stmmstatic void 23886227Stmmread_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata) 23986227Stmm{ 24086227Stmm struct nvme_pt_command pt; 24186227Stmm 24286227Stmm memset(&pt, 0, sizeof(pt)); 24386227Stmm pt.cmd.opc = NVME_OPC_IDENTIFY; 24486227Stmm pt.cmd.nsid = nsid; 24586227Stmm pt.buf = nsdata; 24686227Stmm pt.len = sizeof(*nsdata); 24786227Stmm pt.is_read = 1; 24886227Stmm 24986227Stmm if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) { 25086227Stmm printf("Identify request failed. errno=%d (%s)\n", 25186227Stmm errno, strerror(errno)); 25286227Stmm exit(EX_IOERR); 25386227Stmm } 25486227Stmm 25586227Stmm if (nvme_completion_is_error(&pt.cpl)) { 25686227Stmm printf("Passthrough command returned error.\n"); 25786227Stmm exit(EX_IOERR); 25886227Stmm } 25986227Stmm} 26086227Stmm 26186227Stmmstatic int 26286227Stmmopen_dev(const char *str, int *fd, int show_error, int exit_on_error) 26386227Stmm{ 26486227Stmm struct stat devstat; 26586227Stmm char full_path[64]; 26686227Stmm 26786227Stmm snprintf(full_path, sizeof(full_path), "/dev/%s", str); 26886227Stmm if (stat(full_path, &devstat) != 0) { 26986227Stmm if (show_error) 27088823Stmm fprintf(stderr, "error\n"); 27186227Stmm if (exit_on_error) 27286227Stmm exit(EX_NOINPUT); 27386227Stmm else 27486227Stmm return (EX_NOINPUT); 27586227Stmm } 27686227Stmm 27786227Stmm *fd = open(full_path, O_RDWR); 27886227Stmm if (*fd < 0) { 27986227Stmm if (show_error) 28086227Stmm printf("Could not open %s. errno=%d (%s)\n", full_path, 28186227Stmm errno, strerror(errno)); 28286227Stmm if (exit_on_error) 28386227Stmm exit(EX_NOPERM); 28486227Stmm else 28586227Stmm return (EX_NOPERM); 28686227Stmm } 28786227Stmm 28886227Stmm return (EX_OK); 28986227Stmm} 29086227Stmm 29186227Stmmstatic void 29286227Stmmdevlist_usage(void) 29386227Stmm{ 29486227Stmm fprintf(stderr, "usage:\n"); 29586227Stmm fprintf(stderr, DEVLIST_USAGE); 29686227Stmm exit(EX_USAGE); 29786227Stmm} 29886227Stmm 29986227Stmmstatic void 30086227Stmmdevlist(int argc, char *argv[]) 30186227Stmm{ 30286227Stmm struct nvme_controller_data cdata; 30386227Stmm struct nvme_namespace_data nsdata; 30486227Stmm char name[64]; 30586227Stmm uint32_t i; 30686227Stmm int ch, ctrlr, exit_code, fd, found; 30786227Stmm 30886227Stmm exit_code = EX_OK; 30986227Stmm 31086227Stmm while ((ch = getopt(argc, argv, "")) != -1) { 31186227Stmm switch ((char)ch) { 31286227Stmm default: 31386227Stmm devlist_usage(); 31486227Stmm } 31586227Stmm } 31686227Stmm 31786227Stmm ctrlr = -1; 31886227Stmm found = 0; 31986227Stmm 32086227Stmm while (1) { 32186227Stmm ctrlr++; 32286227Stmm sprintf(name, "nvme%d", ctrlr); 32386227Stmm 32486227Stmm exit_code = open_dev(name, &fd, 0, 0); 32586227Stmm 32686227Stmm if (exit_code == EX_NOINPUT) 32786227Stmm break; 32886227Stmm else if (exit_code == EX_NOPERM) { 32986227Stmm printf("Could not open /dev/%s, errno = %d (%s)\n", 33086227Stmm name, errno, strerror(errno)); 33186227Stmm continue; 33286227Stmm } 33386227Stmm 33486227Stmm found++; 33586227Stmm read_controller_data(fd, &cdata); 33686227Stmm printf("%6s: %s\n", name, cdata.mn); 33786227Stmm 33886227Stmm for (i = 0; i < cdata.nn; i++) { 33986227Stmm sprintf(name, "nvme%dns%d", ctrlr, i+1); 34086227Stmm read_namespace_data(fd, i+1, &nsdata); 34186227Stmm printf(" %10s (%lldGB)\n", 34286227Stmm name, 34386227Stmm nsdata.nsze * 34486227Stmm (long long)ns_get_sector_size(&nsdata) / 34586227Stmm 1024 / 1024 / 1024); 34686227Stmm } 34786227Stmm 34888823Stmm close(fd); 34986227Stmm } 35086227Stmm 35186227Stmm if (found == 0) 35286227Stmm printf("No NVMe controllers found.\n"); 35386227Stmm 35486227Stmm exit(EX_OK); 35586227Stmm} 35686227Stmm 35786227Stmmstatic void 35886227Stmmidentify_usage(void) 35986227Stmm{ 36086227Stmm fprintf(stderr, "usage:\n"); 36186227Stmm fprintf(stderr, IDENTIFY_USAGE); 36286227Stmm exit(EX_USAGE); 36386227Stmm} 36486227Stmm 36586227Stmmstatic void 36686227Stmmidentify_ctrlr(int argc, char *argv[]) 36786227Stmm{ 36886227Stmm struct nvme_controller_data cdata; 36986227Stmm int ch, fd, hexflag = 0, hexlength; 37086227Stmm int verboseflag = 0; 37186227Stmm 37286227Stmm while ((ch = getopt(argc, argv, "vx")) != -1) { 37386227Stmm switch ((char)ch) { 37486227Stmm case 'v': 37586227Stmm verboseflag = 1; 37686227Stmm break; 37786227Stmm case 'x': 37886227Stmm hexflag = 1; 37986227Stmm break; 38086227Stmm default: 38186227Stmm identify_usage(); 38286227Stmm } 38386227Stmm } 38488823Stmm 38586227Stmm open_dev(argv[optind], &fd, 1, 1); 38686227Stmm read_controller_data(fd, &cdata); 38786227Stmm close(fd); 38886227Stmm 38986227Stmm if (hexflag == 1) { 39086227Stmm if (verboseflag == 1) 39186227Stmm hexlength = sizeof(struct nvme_controller_data); 39286227Stmm else 39388823Stmm hexlength = offsetof(struct nvme_controller_data, 39486227Stmm reserved5); 39588823Stmm print_controller_hex(&cdata, hexlength); 39688823Stmm exit(EX_OK); 39788823Stmm } 39886227Stmm 39986227Stmm if (verboseflag == 1) { 40086227Stmm printf("-v not currently supported without -x.\n"); 40186227Stmm identify_usage(); 40286227Stmm } 40386227Stmm 40486227Stmm print_controller(&cdata); 40588823Stmm exit(EX_OK); 40688823Stmm} 40788823Stmm 40888823Stmmstatic void 40986227Stmmidentify_ns(int argc, char *argv[]) 41086227Stmm{ 41186227Stmm struct nvme_namespace_data nsdata; 41286227Stmm char path[64]; 41386227Stmm char *nsloc; 41486227Stmm int ch, fd, hexflag = 0, hexlength, nsid; 41586227Stmm int verboseflag = 0; 41688823Stmm 41786227Stmm while ((ch = getopt(argc, argv, "vx")) != -1) { 41886227Stmm switch ((char)ch) { 41986227Stmm case 'v': 42086227Stmm verboseflag = 1; 42186227Stmm break; 42286227Stmm case 'x': 42386227Stmm hexflag = 1; 42486227Stmm break; 42586227Stmm default: 42686227Stmm identify_usage(); 42786227Stmm } 42886227Stmm } 42986227Stmm 43086227Stmm /* 43186227Stmm * Check if the specified device node exists before continuing. 43286227Stmm * This is a cleaner check for cases where the correct controller 43388823Stmm * is specified, but an invalid namespace on that controller. 43486227Stmm */ 43586227Stmm open_dev(argv[optind], &fd, 1, 1); 43686227Stmm close(fd); 43786227Stmm 43886227Stmm /* 43986227Stmm * Pull the namespace id from the string. +2 skips past the "ns" part 44086227Stmm * of the string. Don't search past 10 characters into the string, 44186227Stmm * otherwise we know it is malformed. 44286227Stmm */ 44386227Stmm nsloc = strnstr(argv[optind], "ns", 10); 44486227Stmm if (nsloc != NULL) 44586227Stmm nsid = strtol(nsloc + 2, NULL, 10); 44686227Stmm if (nsloc == NULL || (nsid == 0 && errno != 0)) { 44786227Stmm printf("Invalid namespace ID %s.\n", argv[optind]); 44886227Stmm exit(EX_IOERR); 44986227Stmm } 45086227Stmm 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 480static void 481identify(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 505static void 506print_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 529static void 530perftest_usage(void) 531{ 532 fprintf(stderr, "usage:\n"); 533 fprintf(stderr, PERFTEST_USAGE); 534 exit(EX_USAGE); 535} 536 537static void 538perftest(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 642static void 643reset_usage(void) 644{ 645 fprintf(stderr, "usage:\n"); 646 fprintf(stderr, RESET_USAGE); 647 exit(EX_USAGE); 648} 649 650static void 651reset_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 672int 673main(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 693