1240620Sjimharris/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4252263Sjimharris * Copyright (C) 2012-2013 Intel Corporation 5240620Sjimharris * All rights reserved. 6240620Sjimharris * 7240620Sjimharris * Redistribution and use in source and binary forms, with or without 8240620Sjimharris * modification, are permitted provided that the following conditions 9240620Sjimharris * are met: 10240620Sjimharris * 1. Redistributions of source code must retain the above copyright 11240620Sjimharris * notice, this list of conditions and the following disclaimer. 12240620Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 13240620Sjimharris * notice, this list of conditions and the following disclaimer in the 14240620Sjimharris * documentation and/or other materials provided with the distribution. 15240620Sjimharris * 16240620Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17240620Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18240620Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19240620Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20240620Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21240620Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22240620Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23240620Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24240620Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25240620Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26240620Sjimharris * SUCH DAMAGE. 27240620Sjimharris */ 28240620Sjimharris 29240620Sjimharris#include <sys/cdefs.h> 30240620Sjimharris__FBSDID("$FreeBSD: stable/11/sbin/nvmecontrol/nvmecontrol.c 330449 2018-03-05 07:26:05Z eadler $"); 31240620Sjimharris 32240620Sjimharris#include <sys/param.h> 33240620Sjimharris#include <sys/ioccom.h> 34240620Sjimharris#include <sys/stat.h> 35240620Sjimharris 36240620Sjimharris#include <ctype.h> 37253109Sjimharris#include <err.h> 38253114Sjimharris#include <errno.h> 39240620Sjimharris#include <fcntl.h> 40253459Sjimharris#include <paths.h> 41240620Sjimharris#include <stdbool.h> 42240620Sjimharris#include <stddef.h> 43240620Sjimharris#include <stdio.h> 44240620Sjimharris#include <stdlib.h> 45240620Sjimharris#include <string.h> 46240620Sjimharris#include <unistd.h> 47240620Sjimharris 48252265Sjimharris#include "nvmecontrol.h" 49240620Sjimharris 50252269Sjimharris 51328715Smavstatic struct nvme_function funcs[] = { 52252269Sjimharris {"devlist", devlist, DEVLIST_USAGE}, 53252269Sjimharris {"identify", identify, IDENTIFY_USAGE}, 54252269Sjimharris {"perftest", perftest, PERFTEST_USAGE}, 55252269Sjimharris {"reset", reset, RESET_USAGE}, 56252277Sjimharris {"logpage", logpage, LOGPAGE_USAGE}, 57252278Sjimharris {"firmware", firmware, FIRMWARE_USAGE}, 58295087Simp {"power", power, POWER_USAGE}, 59328716Smav {"wdc", wdc, WDC_USAGE}, 60252269Sjimharris {NULL, NULL, NULL}, 61252269Sjimharris}; 62252269Sjimharris 63328715Smavvoid 64328715Smavgen_usage(struct nvme_function *f) 65240620Sjimharris{ 66252269Sjimharris 67240620Sjimharris fprintf(stderr, "usage:\n"); 68252269Sjimharris while (f->name != NULL) { 69252269Sjimharris fprintf(stderr, "%s", f->usage); 70252269Sjimharris f++; 71252269Sjimharris } 72253109Sjimharris exit(1); 73240620Sjimharris} 74240620Sjimharris 75328715Smavvoid 76328715Smavdispatch(int argc, char *argv[], struct nvme_function *tbl) 77328715Smav{ 78328715Smav struct nvme_function *f = tbl; 79328715Smav 80328724Smav if (argv[1] == NULL) { 81328724Smav gen_usage(tbl); 82328724Smav return; 83328724Smav } 84328724Smav 85328715Smav while (f->name != NULL) { 86328715Smav if (strcmp(argv[1], f->name) == 0) 87328715Smav f->fn(argc-1, &argv[1]); 88328715Smav f++; 89328715Smav } 90328715Smav 91328715Smav fprintf(stderr, "Unknown command: %s\n", argv[1]); 92328715Smav gen_usage(tbl); 93328715Smav} 94328715Smav 95252275Sjimharrisstatic void 96252275Sjimharrisprint_bytes(void *data, uint32_t length) 97252275Sjimharris{ 98252275Sjimharris uint32_t i, j; 99252275Sjimharris uint8_t *p, *end; 100252275Sjimharris 101252275Sjimharris end = (uint8_t *)data + length; 102252275Sjimharris 103252275Sjimharris for (i = 0; i < length; i++) { 104252275Sjimharris p = (uint8_t *)data + (i*16); 105252275Sjimharris printf("%03x: ", i*16); 106252275Sjimharris for (j = 0; j < 16 && p < end; j++) 107252275Sjimharris printf("%02x ", *p++); 108252275Sjimharris if (p >= end) 109252275Sjimharris break; 110252275Sjimharris printf("\n"); 111252275Sjimharris } 112252275Sjimharris printf("\n"); 113252275Sjimharris} 114252275Sjimharris 115252275Sjimharrisstatic void 116252275Sjimharrisprint_dwords(void *data, uint32_t length) 117252275Sjimharris{ 118252275Sjimharris uint32_t *p; 119252275Sjimharris uint32_t i, j; 120252275Sjimharris 121252275Sjimharris p = (uint32_t *)data; 122252275Sjimharris length /= sizeof(uint32_t); 123252275Sjimharris 124252275Sjimharris for (i = 0; i < length; i+=8) { 125252275Sjimharris printf("%03x: ", i*4); 126252275Sjimharris for (j = 0; j < 8; j++) 127252275Sjimharris printf("%08x ", p[i+j]); 128252275Sjimharris printf("\n"); 129252275Sjimharris } 130252275Sjimharris 131252275Sjimharris printf("\n"); 132252275Sjimharris} 133252275Sjimharris 134252265Sjimharrisvoid 135252275Sjimharrisprint_hex(void *data, uint32_t length) 136252275Sjimharris{ 137252275Sjimharris if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0) 138252275Sjimharris print_dwords(data, length); 139252275Sjimharris else 140252275Sjimharris print_bytes(data, length); 141252275Sjimharris} 142252275Sjimharris 143252275Sjimharrisvoid 144249422Sjimharrisread_controller_data(int fd, struct nvme_controller_data *cdata) 145249422Sjimharris{ 146249422Sjimharris struct nvme_pt_command pt; 147240620Sjimharris 148249422Sjimharris memset(&pt, 0, sizeof(pt)); 149249422Sjimharris pt.cmd.opc = NVME_OPC_IDENTIFY; 150249422Sjimharris pt.cmd.cdw10 = 1; 151249422Sjimharris pt.buf = cdata; 152249422Sjimharris pt.len = sizeof(*cdata); 153249422Sjimharris pt.is_read = 1; 154249422Sjimharris 155253109Sjimharris if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 156253109Sjimharris err(1, "identify request failed"); 157249422Sjimharris 158253109Sjimharris if (nvme_completion_is_error(&pt.cpl)) 159253109Sjimharris errx(1, "identify request returned error"); 160249422Sjimharris} 161249422Sjimharris 162252265Sjimharrisvoid 163249422Sjimharrisread_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata) 164249422Sjimharris{ 165249422Sjimharris struct nvme_pt_command pt; 166249422Sjimharris 167249422Sjimharris memset(&pt, 0, sizeof(pt)); 168249422Sjimharris pt.cmd.opc = NVME_OPC_IDENTIFY; 169249422Sjimharris pt.cmd.nsid = nsid; 170249422Sjimharris pt.buf = nsdata; 171249422Sjimharris pt.len = sizeof(*nsdata); 172249422Sjimharris pt.is_read = 1; 173249422Sjimharris 174253109Sjimharris if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 175253109Sjimharris err(1, "identify request failed"); 176249422Sjimharris 177253109Sjimharris if (nvme_completion_is_error(&pt.cpl)) 178253109Sjimharris errx(1, "identify request returned error"); 179249422Sjimharris} 180249422Sjimharris 181252265Sjimharrisint 182252263Sjimharrisopen_dev(const char *str, int *fd, int show_error, int exit_on_error) 183252263Sjimharris{ 184252263Sjimharris char full_path[64]; 185252263Sjimharris 186252274Sjimharris if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) { 187252274Sjimharris if (show_error) 188253109Sjimharris warnx("controller/namespace ids must begin with '%s'", 189252274Sjimharris NVME_CTRLR_PREFIX); 190252274Sjimharris if (exit_on_error) 191253109Sjimharris exit(1); 192252274Sjimharris else 193253458Sjimharris return (EINVAL); 194252274Sjimharris } 195252274Sjimharris 196253459Sjimharris snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str); 197252263Sjimharris *fd = open(full_path, O_RDWR); 198252263Sjimharris if (*fd < 0) { 199252263Sjimharris if (show_error) 200253109Sjimharris warn("could not open %s", full_path); 201252263Sjimharris if (exit_on_error) 202253109Sjimharris exit(1); 203252263Sjimharris else 204253458Sjimharris return (errno); 205252263Sjimharris } 206252263Sjimharris 207253109Sjimharris return (0); 208252263Sjimharris} 209252263Sjimharris 210253114Sjimharrisvoid 211253114Sjimharrisparse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid) 212253114Sjimharris{ 213253114Sjimharris char *nsloc; 214253114Sjimharris 215253114Sjimharris /* 216253114Sjimharris * Pull the namespace id from the string. +2 skips past the "ns" part 217253114Sjimharris * of the string. Don't search past 10 characters into the string, 218253114Sjimharris * otherwise we know it is malformed. 219253114Sjimharris */ 220253114Sjimharris nsloc = strnstr(ns_str, NVME_NS_PREFIX, 10); 221253114Sjimharris if (nsloc != NULL) 222253114Sjimharris *nsid = strtol(nsloc + 2, NULL, 10); 223253114Sjimharris if (nsloc == NULL || (*nsid == 0 && errno != 0)) 224253114Sjimharris errx(1, "invalid namespace ID '%s'", ns_str); 225253114Sjimharris 226253114Sjimharris /* 227253114Sjimharris * The controller string will include only the nvmX part of the 228253114Sjimharris * nvmeXnsY string. 229253114Sjimharris */ 230253114Sjimharris snprintf(ctrlr_str, nsloc - ns_str + 1, "%s", ns_str); 231253114Sjimharris} 232253114Sjimharris 233240620Sjimharrisint 234240620Sjimharrismain(int argc, char *argv[]) 235240620Sjimharris{ 236240620Sjimharris 237240620Sjimharris if (argc < 2) 238328715Smav gen_usage(funcs); 239240620Sjimharris 240328715Smav dispatch(argc, argv, funcs); 241240620Sjimharris 242240620Sjimharris return (0); 243240620Sjimharris} 244