1252266Sjimharris/*- 2252266Sjimharris * Copyright (C) 2012-2013 Intel Corporation 3252266Sjimharris * All rights reserved. 4252266Sjimharris * 5252266Sjimharris * Redistribution and use in source and binary forms, with or without 6252266Sjimharris * modification, are permitted provided that the following conditions 7252266Sjimharris * are met: 8252266Sjimharris * 1. Redistributions of source code must retain the above copyright 9252266Sjimharris * notice, this list of conditions and the following disclaimer. 10252266Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 11252266Sjimharris * notice, this list of conditions and the following disclaimer in the 12252266Sjimharris * documentation and/or other materials provided with the distribution. 13252266Sjimharris * 14252266Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15252266Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16252266Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17252266Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18252266Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19252266Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20252266Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21252266Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22252266Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23252266Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24252266Sjimharris * SUCH DAMAGE. 25252266Sjimharris */ 26252266Sjimharris 27252266Sjimharris#include <sys/cdefs.h> 28252266Sjimharris__FBSDID("$FreeBSD$"); 29252266Sjimharris 30252266Sjimharris#include <sys/param.h> 31252266Sjimharris 32252266Sjimharris#include <ctype.h> 33253109Sjimharris#include <err.h> 34252266Sjimharris#include <fcntl.h> 35252266Sjimharris#include <stddef.h> 36252266Sjimharris#include <stdio.h> 37252266Sjimharris#include <stdlib.h> 38252266Sjimharris#include <string.h> 39252266Sjimharris#include <unistd.h> 40252266Sjimharris 41252266Sjimharris#include "nvmecontrol.h" 42252266Sjimharris 43252266Sjimharrisstatic void 44252266Sjimharrisprint_controller(struct nvme_controller_data *cdata) 45252266Sjimharris{ 46253476Sjimharris uint8_t str[128]; 47253476Sjimharris 48252266Sjimharris printf("Controller Capabilities/Features\n"); 49252266Sjimharris printf("================================\n"); 50252266Sjimharris printf("Vendor ID: %04x\n", cdata->vid); 51252266Sjimharris printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 52253476Sjimharris nvme_strvis(str, cdata->sn, sizeof(str), NVME_SERIAL_NUMBER_LENGTH); 53253476Sjimharris printf("Serial Number: %s\n", str); 54253476Sjimharris nvme_strvis(str, cdata->mn, sizeof(str), NVME_MODEL_NUMBER_LENGTH); 55253476Sjimharris printf("Model Number: %s\n", str); 56253476Sjimharris nvme_strvis(str, cdata->fr, sizeof(str), NVME_FIRMWARE_REVISION_LENGTH); 57253476Sjimharris printf("Firmware Version: %s\n", str); 58252266Sjimharris printf("Recommended Arb Burst: %d\n", cdata->rab); 59252266Sjimharris printf("IEEE OUI Identifier: %02x %02x %02x\n", 60252266Sjimharris cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 61252266Sjimharris printf("Multi-Interface Cap: %02x\n", cdata->mic); 62252266Sjimharris /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 63252266Sjimharris printf("Max Data Transfer Size: "); 64252266Sjimharris if (cdata->mdts == 0) 65252266Sjimharris printf("Unlimited\n"); 66252266Sjimharris else 67252266Sjimharris printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); 68252266Sjimharris printf("\n"); 69252266Sjimharris 70252266Sjimharris printf("Admin Command Set Attributes\n"); 71252266Sjimharris printf("============================\n"); 72252266Sjimharris printf("Security Send/Receive: %s\n", 73252266Sjimharris cdata->oacs.security ? "Supported" : "Not Supported"); 74252266Sjimharris printf("Format NVM: %s\n", 75252266Sjimharris cdata->oacs.format ? "Supported" : "Not Supported"); 76252266Sjimharris printf("Firmware Activate/Download: %s\n", 77252266Sjimharris cdata->oacs.firmware ? "Supported" : "Not Supported"); 78252266Sjimharris printf("Abort Command Limit: %d\n", cdata->acl+1); 79252266Sjimharris printf("Async Event Request Limit: %d\n", cdata->aerl+1); 80252266Sjimharris printf("Number of Firmware Slots: "); 81252266Sjimharris if (cdata->oacs.firmware != 0) 82252266Sjimharris printf("%d\n", cdata->frmw.num_slots); 83252266Sjimharris else 84252266Sjimharris printf("N/A\n"); 85252266Sjimharris printf("Firmware Slot 1 Read-Only: "); 86252266Sjimharris if (cdata->oacs.firmware != 0) 87252266Sjimharris printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); 88252266Sjimharris else 89252266Sjimharris printf("N/A\n"); 90252266Sjimharris printf("Per-Namespace SMART Log: %s\n", 91252266Sjimharris cdata->lpa.ns_smart ? "Yes" : "No"); 92252266Sjimharris printf("Error Log Page Entries: %d\n", cdata->elpe+1); 93252266Sjimharris printf("Number of Power States: %d\n", cdata->npss+1); 94252266Sjimharris printf("\n"); 95252266Sjimharris 96252266Sjimharris printf("NVM Command Set Attributes\n"); 97252266Sjimharris printf("==========================\n"); 98252266Sjimharris printf("Submission Queue Entry Size\n"); 99252266Sjimharris printf(" Max: %d\n", 1 << cdata->sqes.max); 100252266Sjimharris printf(" Min: %d\n", 1 << cdata->sqes.min); 101252266Sjimharris printf("Completion Queue Entry Size\n"); 102252266Sjimharris printf(" Max: %d\n", 1 << cdata->cqes.max); 103252266Sjimharris printf(" Min: %d\n", 1 << cdata->cqes.min); 104252266Sjimharris printf("Number of Namespaces: %d\n", cdata->nn); 105252266Sjimharris printf("Compare Command: %s\n", 106252266Sjimharris cdata->oncs.compare ? "Supported" : "Not Supported"); 107252266Sjimharris printf("Write Uncorrectable Command: %s\n", 108252266Sjimharris cdata->oncs.write_unc ? "Supported" : "Not Supported"); 109252266Sjimharris printf("Dataset Management Command: %s\n", 110252266Sjimharris cdata->oncs.dsm ? "Supported" : "Not Supported"); 111252266Sjimharris printf("Volatile Write Cache: %s\n", 112252266Sjimharris cdata->vwc.present ? "Present" : "Not Present"); 113252266Sjimharris} 114252266Sjimharris 115252266Sjimharrisstatic void 116252266Sjimharrisprint_namespace(struct nvme_namespace_data *nsdata) 117252266Sjimharris{ 118252266Sjimharris uint32_t i; 119252266Sjimharris 120252266Sjimharris printf("Size (in LBAs): %lld (%lldM)\n", 121252266Sjimharris (long long)nsdata->nsze, 122252266Sjimharris (long long)nsdata->nsze / 1024 / 1024); 123252266Sjimharris printf("Capacity (in LBAs): %lld (%lldM)\n", 124252266Sjimharris (long long)nsdata->ncap, 125252266Sjimharris (long long)nsdata->ncap / 1024 / 1024); 126252266Sjimharris printf("Utilization (in LBAs): %lld (%lldM)\n", 127252266Sjimharris (long long)nsdata->nuse, 128252266Sjimharris (long long)nsdata->nuse / 1024 / 1024); 129252266Sjimharris printf("Thin Provisioning: %s\n", 130252266Sjimharris nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); 131252266Sjimharris printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 132253115Sjimharris printf("Current LBA Format: LBA Format #%02d\n", 133252266Sjimharris nsdata->flbas.format); 134253115Sjimharris for (i = 0; i <= nsdata->nlbaf; i++) 135253115Sjimharris printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n", 136253115Sjimharris i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms); 137252266Sjimharris} 138252266Sjimharris 139252266Sjimharrisstatic void 140252266Sjimharrisidentify_usage(void) 141252266Sjimharris{ 142252266Sjimharris fprintf(stderr, "usage:\n"); 143252266Sjimharris fprintf(stderr, IDENTIFY_USAGE); 144253109Sjimharris exit(1); 145252266Sjimharris} 146252266Sjimharris 147252266Sjimharrisstatic void 148252266Sjimharrisidentify_ctrlr(int argc, char *argv[]) 149252266Sjimharris{ 150252266Sjimharris struct nvme_controller_data cdata; 151252266Sjimharris int ch, fd, hexflag = 0, hexlength; 152252266Sjimharris int verboseflag = 0; 153252266Sjimharris 154252266Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 155252266Sjimharris switch ((char)ch) { 156252266Sjimharris case 'v': 157252266Sjimharris verboseflag = 1; 158252266Sjimharris break; 159252266Sjimharris case 'x': 160252266Sjimharris hexflag = 1; 161252266Sjimharris break; 162252266Sjimharris default: 163252266Sjimharris identify_usage(); 164252266Sjimharris } 165252266Sjimharris } 166252266Sjimharris 167252274Sjimharris /* Check that a controller was specified. */ 168252274Sjimharris if (optind >= argc) 169252274Sjimharris identify_usage(); 170252274Sjimharris 171252266Sjimharris open_dev(argv[optind], &fd, 1, 1); 172252266Sjimharris read_controller_data(fd, &cdata); 173252266Sjimharris close(fd); 174252266Sjimharris 175252266Sjimharris if (hexflag == 1) { 176252266Sjimharris if (verboseflag == 1) 177252266Sjimharris hexlength = sizeof(struct nvme_controller_data); 178252266Sjimharris else 179252266Sjimharris hexlength = offsetof(struct nvme_controller_data, 180252266Sjimharris reserved5); 181252275Sjimharris print_hex(&cdata, hexlength); 182253109Sjimharris exit(0); 183252266Sjimharris } 184252266Sjimharris 185252266Sjimharris if (verboseflag == 1) { 186253109Sjimharris fprintf(stderr, "-v not currently supported without -x\n"); 187252266Sjimharris identify_usage(); 188252266Sjimharris } 189252266Sjimharris 190252266Sjimharris print_controller(&cdata); 191253109Sjimharris exit(0); 192252266Sjimharris} 193252266Sjimharris 194252266Sjimharrisstatic void 195252266Sjimharrisidentify_ns(int argc, char *argv[]) 196252266Sjimharris{ 197252266Sjimharris struct nvme_namespace_data nsdata; 198252266Sjimharris char path[64]; 199252266Sjimharris int ch, fd, hexflag = 0, hexlength, nsid; 200252266Sjimharris int verboseflag = 0; 201252266Sjimharris 202252266Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 203252266Sjimharris switch ((char)ch) { 204252266Sjimharris case 'v': 205252266Sjimharris verboseflag = 1; 206252266Sjimharris break; 207252266Sjimharris case 'x': 208252266Sjimharris hexflag = 1; 209252266Sjimharris break; 210252266Sjimharris default: 211252266Sjimharris identify_usage(); 212252266Sjimharris } 213252266Sjimharris } 214252266Sjimharris 215252274Sjimharris /* Check that a namespace was specified. */ 216252274Sjimharris if (optind >= argc) 217252274Sjimharris identify_usage(); 218252274Sjimharris 219252266Sjimharris /* 220252266Sjimharris * Check if the specified device node exists before continuing. 221252266Sjimharris * This is a cleaner check for cases where the correct controller 222252266Sjimharris * is specified, but an invalid namespace on that controller. 223252266Sjimharris */ 224252266Sjimharris open_dev(argv[optind], &fd, 1, 1); 225252266Sjimharris close(fd); 226252266Sjimharris 227252266Sjimharris /* 228252266Sjimharris * We send IDENTIFY commands to the controller, not the namespace, 229253114Sjimharris * since it is an admin cmd. The namespace ID will be specified in 230253114Sjimharris * the IDENTIFY command itself. So parse the namespace's device node 231253114Sjimharris * string to get the controller substring and namespace ID. 232252266Sjimharris */ 233253114Sjimharris parse_ns_str(argv[optind], path, &nsid); 234252266Sjimharris open_dev(path, &fd, 1, 1); 235252266Sjimharris read_namespace_data(fd, nsid, &nsdata); 236252266Sjimharris close(fd); 237252266Sjimharris 238252266Sjimharris if (hexflag == 1) { 239252266Sjimharris if (verboseflag == 1) 240252266Sjimharris hexlength = sizeof(struct nvme_namespace_data); 241252266Sjimharris else 242252266Sjimharris hexlength = offsetof(struct nvme_namespace_data, 243252266Sjimharris reserved6); 244252275Sjimharris print_hex(&nsdata, hexlength); 245253109Sjimharris exit(0); 246252266Sjimharris } 247252266Sjimharris 248252266Sjimharris if (verboseflag == 1) { 249253109Sjimharris fprintf(stderr, "-v not currently supported without -x\n"); 250252266Sjimharris identify_usage(); 251252266Sjimharris } 252252266Sjimharris 253252266Sjimharris print_namespace(&nsdata); 254253109Sjimharris exit(0); 255252266Sjimharris} 256252266Sjimharris 257252266Sjimharrisvoid 258252266Sjimharrisidentify(int argc, char *argv[]) 259252266Sjimharris{ 260252266Sjimharris char *target; 261252266Sjimharris 262252266Sjimharris if (argc < 2) 263252266Sjimharris identify_usage(); 264252266Sjimharris 265252266Sjimharris while (getopt(argc, argv, "vx") != -1) ; 266252266Sjimharris 267253116Sjimharris /* Check that a controller or namespace was specified. */ 268253116Sjimharris if (optind >= argc) 269253116Sjimharris identify_usage(); 270253116Sjimharris 271252266Sjimharris target = argv[optind]; 272252266Sjimharris 273252266Sjimharris optreset = 1; 274252266Sjimharris optind = 1; 275252266Sjimharris 276252266Sjimharris /* 277252266Sjimharris * If device node contains "ns", we consider it a namespace, 278252266Sjimharris * otherwise, consider it a controller. 279252266Sjimharris */ 280252270Sjimharris if (strstr(target, NVME_NS_PREFIX) == NULL) 281252266Sjimharris identify_ctrlr(argc, argv); 282252266Sjimharris else 283252266Sjimharris identify_ns(argc, argv); 284252266Sjimharris} 285