nvmecontrol.c revision 252278
1139749Simp/*- 2197404Sjoel * Copyright (C) 2012-2013 Intel Corporation 3197404Sjoel * All rights reserved. 4197404Sjoel * 550724Scg * Redistribution and use in source and binary forms, with or without 6197404Sjoel * modification, are permitted provided that the following conditions 7197404Sjoel * are met: 8197404Sjoel * 1. Redistributions of source code must retain the above copyright 9197404Sjoel * notice, this list of conditions and the following disclaimer. 10197404Sjoel * 2. Redistributions in binary form must reproduce the above copyright 11197404Sjoel * notice, this list of conditions and the following disclaimer in the 12197404Sjoel * documentation and/or other materials provided with the distribution. 13197404Sjoel * 14197404Sjoel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15197404Sjoel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16197404Sjoel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17197404Sjoel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18197404Sjoel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19197404Sjoel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20197404Sjoel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21197404Sjoel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22197404Sjoel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23197404Sjoel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24197404Sjoel * SUCH DAMAGE. 25197404Sjoel */ 26197404Sjoel 27197404Sjoel#include <sys/cdefs.h> 28197404Sjoel__FBSDID("$FreeBSD: head/sbin/nvmecontrol/nvmecontrol.c 252278 2013-06-27 00:08:25Z jimharris $"); 29119853Scg 30197404Sjoel#include <sys/param.h> 3150724Scg#include <sys/ioccom.h> 3250724Scg#include <sys/stat.h> 3350724Scg 3450724Scg#include <ctype.h> 3550724Scg#include <errno.h> 3650724Scg#include <fcntl.h> 3750724Scg#include <stdbool.h> 3850724Scg#include <stddef.h> 3950724Scg#include <stdio.h> 4050724Scg#include <stdlib.h> 4150724Scg#include <string.h> 4250724Scg#include <sysexits.h> 4350724Scg#include <unistd.h> 4450724Scg 4550724Scg#include "nvmecontrol.h" 4650724Scg 4750724Scgtypedef void (*nvme_fn_t)(int argc, char *argv[]); 4850724Scg 4950724Scgstruct nvme_function { 5050724Scg const char *name; 5150724Scg nvme_fn_t fn; 5250724Scg const char *usage; 5350724Scg} funcs[] = { 5450724Scg {"devlist", devlist, DEVLIST_USAGE}, 5550724Scg {"identify", identify, IDENTIFY_USAGE}, 5650724Scg {"perftest", perftest, PERFTEST_USAGE}, 5750724Scg {"reset", reset, RESET_USAGE}, 5850724Scg {"logpage", logpage, LOGPAGE_USAGE}, 5950724Scg {"firmware", firmware, FIRMWARE_USAGE}, 6050724Scg {NULL, NULL, NULL}, 6150724Scg}; 6250724Scg 6350724Scgstatic void 6450724Scgusage(void) 6553413Sroger{ 66197404Sjoel struct nvme_function *f; 67197404Sjoel 68197404Sjoel f = funcs; 6953413Sroger fprintf(stderr, "usage:\n"); 7053413Sroger while (f->name != NULL) { 7154831Scg fprintf(stderr, "%s", f->usage); 7254831Scg f++; 7353413Sroger } 7453413Sroger exit(EX_USAGE); 7553413Sroger} 76193640Sariff 77193640Sariffstatic void 78193640Sariffprint_bytes(void *data, uint32_t length) 79193640Sariff{ 8053465Scg uint32_t i, j; 8153465Scg uint8_t *p, *end; 8253465Scg 8350724Scg end = (uint8_t *)data + length; 84119287Simp 85119287Simp for (i = 0; i < length; i++) { 8650724Scg p = (uint8_t *)data + (i*16); 8753413Sroger printf("%03x: ", i*16); 8853413Sroger for (j = 0; j < 16 && p < end; j++) 8970134Scg printf("%02x ", *p++); 9070134Scg if (p >= end) 9182180Scg break; 9282180Scg printf("\n"); 9350724Scg } 9450724Scg printf("\n"); 9550724Scg} 9650724Scg 9753413Srogerstatic void 9856154Speterprint_dwords(void *data, uint32_t length) 9976086Scg{ 100119548Sorion uint32_t *p; 10150724Scg uint32_t i, j; 10278033Scg 10376086Scg p = (uint32_t *)data; 10476086Scg length /= sizeof(uint32_t); 10576086Scg 10676086Scg for (i = 0; i < length; i+=8) { 10776086Scg printf("%03x: ", i*4); 10876086Scg for (j = 0; j < 8; j++) 10976086Scg printf("%08x ", p[i+j]); 11076086Scg printf("\n"); 11176086Scg } 11276086Scg 11395678Scg printf("\n"); 11476086Scg} 115119548Sorion 116119548Sorionvoid 11784658Scgprint_hex(void *data, uint32_t length) 11859019Scg{ 119152419Sariff if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0) 120152419Sariff print_dwords(data, length); 121152419Sariff else 122152419Sariff print_bytes(data, length); 123152419Sariff} 124152419Sariff 125167648Sariffvoid 126167648Sariffread_controller_data(int fd, struct nvme_controller_data *cdata) 127167648Sariff{ 128167648Sariff struct nvme_pt_command pt; 129167648Sariff 130152419Sariff memset(&pt, 0, sizeof(pt)); 131152419Sariff pt.cmd.opc = NVME_OPC_IDENTIFY; 132152419Sariff pt.cmd.cdw10 = 1; 13350724Scg pt.buf = cdata; 13450724Scg pt.len = sizeof(*cdata); 13550724Scg pt.is_read = 1; 13655209Scg 13750724Scg if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) { 13874763Scg printf("Identify request failed. errno=%d (%s)\n", 13974763Scg errno, strerror(errno)); 140152419Sariff exit(EX_IOERR); 141152419Sariff } 142164614Sariff 143164614Sariff if (nvme_completion_is_error(&pt.cpl)) { 144164614Sariff printf("Passthrough command returned error.\n"); 14555209Scg exit(EX_IOERR); 14650724Scg } 147152419Sariff} 148152419Sariff 149152419Sariffvoid 150152419Sariffread_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata) 151152419Sariff{ 152152419Sariff struct nvme_pt_command pt; 153152419Sariff 154152419Sariff memset(&pt, 0, sizeof(pt)); 155152419Sariff pt.cmd.opc = NVME_OPC_IDENTIFY; 156152419Sariff pt.cmd.nsid = nsid; 157152419Sariff pt.buf = nsdata; 158152419Sariff pt.len = sizeof(*nsdata); 159152419Sariff pt.is_read = 1; 160152419Sariff 161152419Sariff if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) { 162152419Sariff printf("Identify request failed. errno=%d (%s)\n", 163152419Sariff errno, strerror(errno)); 164152419Sariff exit(EX_IOERR); 165152419Sariff } 166152419Sariff 167152419Sariff if (nvme_completion_is_error(&pt.cpl)) { 168152419Sariff printf("Passthrough command returned error.\n"); 169152419Sariff exit(EX_IOERR); 170152419Sariff } 171152419Sariff} 172152419Sariff 173152419Sariffint 174152419Sariffopen_dev(const char *str, int *fd, int show_error, int exit_on_error) 175152419Sariff{ 176152419Sariff struct stat devstat; 177152419Sariff char full_path[64]; 178152419Sariff 179152419Sariff if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) { 180152419Sariff if (show_error) 181152419Sariff fprintf(stderr, 182152419Sariff "Controller/namespace IDs must begin with '%s'.\n", 183152419Sariff NVME_CTRLR_PREFIX); 184152419Sariff if (exit_on_error) 185152419Sariff exit(EX_USAGE); 186152419Sariff else 187152419Sariff return (EX_USAGE); 188152419Sariff } 189152419Sariff 190152419Sariff snprintf(full_path, sizeof(full_path), "/dev/%s", str); 191152419Sariff if (stat(full_path, &devstat) != 0) { 192152419Sariff if (show_error) 193152419Sariff fprintf(stderr, "Could not stat %s. errno=%d (%s)\n", 194152419Sariff full_path, errno, strerror(errno)); 195152419Sariff if (exit_on_error) 196152419Sariff exit(EX_NOINPUT); 197152419Sariff else 198152419Sariff return (EX_NOINPUT); 199152419Sariff } 200152419Sariff 201152419Sariff *fd = open(full_path, O_RDWR); 202152419Sariff if (*fd < 0) { 203152419Sariff if (show_error) 204152419Sariff fprintf(stderr, "Could not open %s. errno=%d (%s)\n", 205152419Sariff full_path, errno, strerror(errno)); 206152419Sariff if (exit_on_error) 207152419Sariff exit(EX_NOPERM); 208152419Sariff else 20955209Scg return (EX_NOPERM); 21050724Scg } 21150724Scg 21250724Scg return (EX_OK); 21350724Scg} 21465644Scg 21565644Scgint 21665644Scgmain(int argc, char *argv[]) 21765644Scg{ 21859019Scg struct nvme_function *f; 21954831Scg 220164614Sariff if (argc < 2) 22184658Scg usage(); 22250724Scg 223150832Snetchild f = funcs; 224150832Snetchild while (f->name != NULL) { 225152419Sariff if (strcmp(argv[1], f->name) == 0) 226152419Sariff f->fn(argc-1, &argv[1]); 227148591Snetchild f++; 228164614Sariff } 229164614Sariff 23055209Scg usage(); 23150724Scg 232150832Snetchild return (0); 233150832Snetchild} 234150832Snetchild