identify.c revision 253109
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: head/sbin/nvmecontrol/identify.c 253109 2013-07-09 21:14:15Z jimharris $"); 29252266Sjimharris 30252266Sjimharris#include <sys/param.h> 31252266Sjimharris 32252266Sjimharris#include <ctype.h> 33253109Sjimharris#include <err.h> 34252266Sjimharris#include <errno.h> 35252266Sjimharris#include <fcntl.h> 36252266Sjimharris#include <stddef.h> 37252266Sjimharris#include <stdio.h> 38252266Sjimharris#include <stdlib.h> 39252266Sjimharris#include <string.h> 40252266Sjimharris#include <unistd.h> 41252266Sjimharris 42252266Sjimharris#include "nvmecontrol.h" 43252266Sjimharris 44252266Sjimharrisstatic void 45252266Sjimharrisprint_controller(struct nvme_controller_data *cdata) 46252266Sjimharris{ 47252266Sjimharris printf("Controller Capabilities/Features\n"); 48252266Sjimharris printf("================================\n"); 49252266Sjimharris printf("Vendor ID: %04x\n", cdata->vid); 50252266Sjimharris printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 51252266Sjimharris printf("Serial Number: %s\n", cdata->sn); 52252266Sjimharris printf("Model Number: %s\n", cdata->mn); 53252266Sjimharris printf("Firmware Version: %s\n", cdata->fr); 54252266Sjimharris printf("Recommended Arb Burst: %d\n", cdata->rab); 55252266Sjimharris printf("IEEE OUI Identifier: %02x %02x %02x\n", 56252266Sjimharris cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 57252266Sjimharris printf("Multi-Interface Cap: %02x\n", cdata->mic); 58252266Sjimharris /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 59252266Sjimharris printf("Max Data Transfer Size: "); 60252266Sjimharris if (cdata->mdts == 0) 61252266Sjimharris printf("Unlimited\n"); 62252266Sjimharris else 63252266Sjimharris printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); 64252266Sjimharris printf("\n"); 65252266Sjimharris 66252266Sjimharris printf("Admin Command Set Attributes\n"); 67252266Sjimharris printf("============================\n"); 68252266Sjimharris printf("Security Send/Receive: %s\n", 69252266Sjimharris cdata->oacs.security ? "Supported" : "Not Supported"); 70252266Sjimharris printf("Format NVM: %s\n", 71252266Sjimharris cdata->oacs.format ? "Supported" : "Not Supported"); 72252266Sjimharris printf("Firmware Activate/Download: %s\n", 73252266Sjimharris cdata->oacs.firmware ? "Supported" : "Not Supported"); 74252266Sjimharris printf("Abort Command Limit: %d\n", cdata->acl+1); 75252266Sjimharris printf("Async Event Request Limit: %d\n", cdata->aerl+1); 76252266Sjimharris printf("Number of Firmware Slots: "); 77252266Sjimharris if (cdata->oacs.firmware != 0) 78252266Sjimharris printf("%d\n", cdata->frmw.num_slots); 79252266Sjimharris else 80252266Sjimharris printf("N/A\n"); 81252266Sjimharris printf("Firmware Slot 1 Read-Only: "); 82252266Sjimharris if (cdata->oacs.firmware != 0) 83252266Sjimharris printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); 84252266Sjimharris else 85252266Sjimharris printf("N/A\n"); 86252266Sjimharris printf("Per-Namespace SMART Log: %s\n", 87252266Sjimharris cdata->lpa.ns_smart ? "Yes" : "No"); 88252266Sjimharris printf("Error Log Page Entries: %d\n", cdata->elpe+1); 89252266Sjimharris printf("Number of Power States: %d\n", cdata->npss+1); 90252266Sjimharris printf("\n"); 91252266Sjimharris 92252266Sjimharris printf("NVM Command Set Attributes\n"); 93252266Sjimharris printf("==========================\n"); 94252266Sjimharris printf("Submission Queue Entry Size\n"); 95252266Sjimharris printf(" Max: %d\n", 1 << cdata->sqes.max); 96252266Sjimharris printf(" Min: %d\n", 1 << cdata->sqes.min); 97252266Sjimharris printf("Completion Queue Entry Size\n"); 98252266Sjimharris printf(" Max: %d\n", 1 << cdata->cqes.max); 99252266Sjimharris printf(" Min: %d\n", 1 << cdata->cqes.min); 100252266Sjimharris printf("Number of Namespaces: %d\n", cdata->nn); 101252266Sjimharris printf("Compare Command: %s\n", 102252266Sjimharris cdata->oncs.compare ? "Supported" : "Not Supported"); 103252266Sjimharris printf("Write Uncorrectable Command: %s\n", 104252266Sjimharris cdata->oncs.write_unc ? "Supported" : "Not Supported"); 105252266Sjimharris printf("Dataset Management Command: %s\n", 106252266Sjimharris cdata->oncs.dsm ? "Supported" : "Not Supported"); 107252266Sjimharris printf("Volatile Write Cache: %s\n", 108252266Sjimharris cdata->vwc.present ? "Present" : "Not Present"); 109252266Sjimharris} 110252266Sjimharris 111252266Sjimharrisstatic void 112252266Sjimharrisprint_namespace(struct nvme_namespace_data *nsdata) 113252266Sjimharris{ 114252266Sjimharris uint32_t i; 115252266Sjimharris 116252266Sjimharris printf("Size (in LBAs): %lld (%lldM)\n", 117252266Sjimharris (long long)nsdata->nsze, 118252266Sjimharris (long long)nsdata->nsze / 1024 / 1024); 119252266Sjimharris printf("Capacity (in LBAs): %lld (%lldM)\n", 120252266Sjimharris (long long)nsdata->ncap, 121252266Sjimharris (long long)nsdata->ncap / 1024 / 1024); 122252266Sjimharris printf("Utilization (in LBAs): %lld (%lldM)\n", 123252266Sjimharris (long long)nsdata->nuse, 124252266Sjimharris (long long)nsdata->nuse / 1024 / 1024); 125252266Sjimharris printf("Thin Provisioning: %s\n", 126252266Sjimharris nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); 127252266Sjimharris printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 128252266Sjimharris printf("Current LBA Format: LBA Format #%d\n", 129252266Sjimharris nsdata->flbas.format); 130252266Sjimharris for (i = 0; i <= nsdata->nlbaf; i++) { 131252266Sjimharris printf("LBA Format #%d:\n", i); 132252266Sjimharris printf(" LBA Data Size: %d\n", 133252266Sjimharris 1 << nsdata->lbaf[i].lbads); 134252266Sjimharris } 135252266Sjimharris} 136252266Sjimharris 137252266Sjimharrisstatic void 138252266Sjimharrisidentify_usage(void) 139252266Sjimharris{ 140252266Sjimharris fprintf(stderr, "usage:\n"); 141252266Sjimharris fprintf(stderr, IDENTIFY_USAGE); 142253109Sjimharris exit(1); 143252266Sjimharris} 144252266Sjimharris 145252266Sjimharrisstatic void 146252266Sjimharrisidentify_ctrlr(int argc, char *argv[]) 147252266Sjimharris{ 148252266Sjimharris struct nvme_controller_data cdata; 149252266Sjimharris int ch, fd, hexflag = 0, hexlength; 150252266Sjimharris int verboseflag = 0; 151252266Sjimharris 152252266Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 153252266Sjimharris switch ((char)ch) { 154252266Sjimharris case 'v': 155252266Sjimharris verboseflag = 1; 156252266Sjimharris break; 157252266Sjimharris case 'x': 158252266Sjimharris hexflag = 1; 159252266Sjimharris break; 160252266Sjimharris default: 161252266Sjimharris identify_usage(); 162252266Sjimharris } 163252266Sjimharris } 164252266Sjimharris 165252274Sjimharris /* Check that a controller was specified. */ 166252274Sjimharris if (optind >= argc) 167252274Sjimharris identify_usage(); 168252274Sjimharris 169252266Sjimharris open_dev(argv[optind], &fd, 1, 1); 170252266Sjimharris read_controller_data(fd, &cdata); 171252266Sjimharris close(fd); 172252266Sjimharris 173252266Sjimharris if (hexflag == 1) { 174252266Sjimharris if (verboseflag == 1) 175252266Sjimharris hexlength = sizeof(struct nvme_controller_data); 176252266Sjimharris else 177252266Sjimharris hexlength = offsetof(struct nvme_controller_data, 178252266Sjimharris reserved5); 179252275Sjimharris print_hex(&cdata, hexlength); 180253109Sjimharris exit(0); 181252266Sjimharris } 182252266Sjimharris 183252266Sjimharris if (verboseflag == 1) { 184253109Sjimharris fprintf(stderr, "-v not currently supported without -x\n"); 185252266Sjimharris identify_usage(); 186252266Sjimharris } 187252266Sjimharris 188252266Sjimharris print_controller(&cdata); 189253109Sjimharris exit(0); 190252266Sjimharris} 191252266Sjimharris 192252266Sjimharrisstatic void 193252266Sjimharrisidentify_ns(int argc, char *argv[]) 194252266Sjimharris{ 195252266Sjimharris struct nvme_namespace_data nsdata; 196252266Sjimharris char path[64]; 197252266Sjimharris char *nsloc; 198252266Sjimharris int ch, fd, hexflag = 0, hexlength, nsid; 199252266Sjimharris int verboseflag = 0; 200252266Sjimharris 201252266Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 202252266Sjimharris switch ((char)ch) { 203252266Sjimharris case 'v': 204252266Sjimharris verboseflag = 1; 205252266Sjimharris break; 206252266Sjimharris case 'x': 207252266Sjimharris hexflag = 1; 208252266Sjimharris break; 209252266Sjimharris default: 210252266Sjimharris identify_usage(); 211252266Sjimharris } 212252266Sjimharris } 213252266Sjimharris 214252274Sjimharris /* Check that a namespace was specified. */ 215252274Sjimharris if (optind >= argc) 216252274Sjimharris identify_usage(); 217252274Sjimharris 218252266Sjimharris /* 219252266Sjimharris * Check if the specified device node exists before continuing. 220252266Sjimharris * This is a cleaner check for cases where the correct controller 221252266Sjimharris * is specified, but an invalid namespace on that controller. 222252266Sjimharris */ 223252266Sjimharris open_dev(argv[optind], &fd, 1, 1); 224252266Sjimharris close(fd); 225252266Sjimharris 226252266Sjimharris /* 227252266Sjimharris * Pull the namespace id from the string. +2 skips past the "ns" part 228252266Sjimharris * of the string. Don't search past 10 characters into the string, 229252266Sjimharris * otherwise we know it is malformed. 230252266Sjimharris */ 231252270Sjimharris nsloc = strnstr(argv[optind], NVME_NS_PREFIX, 10); 232252266Sjimharris if (nsloc != NULL) 233252266Sjimharris nsid = strtol(nsloc + 2, NULL, 10); 234253109Sjimharris if (nsloc == NULL || (nsid == 0 && errno != 0)) 235253109Sjimharris errx(1, "invalid namespace ID '%s'", argv[optind]); 236252266Sjimharris 237252266Sjimharris /* 238252266Sjimharris * We send IDENTIFY commands to the controller, not the namespace, 239252266Sjimharris * since it is an admin cmd. So the path should only include the 240252266Sjimharris * nvmeX part of the nvmeXnsY string. 241252266Sjimharris */ 242252266Sjimharris snprintf(path, nsloc - argv[optind] + 1, "%s", argv[optind]); 243252266Sjimharris open_dev(path, &fd, 1, 1); 244252266Sjimharris read_namespace_data(fd, nsid, &nsdata); 245252266Sjimharris close(fd); 246252266Sjimharris 247252266Sjimharris if (hexflag == 1) { 248252266Sjimharris if (verboseflag == 1) 249252266Sjimharris hexlength = sizeof(struct nvme_namespace_data); 250252266Sjimharris else 251252266Sjimharris hexlength = offsetof(struct nvme_namespace_data, 252252266Sjimharris reserved6); 253252275Sjimharris print_hex(&nsdata, hexlength); 254253109Sjimharris exit(0); 255252266Sjimharris } 256252266Sjimharris 257252266Sjimharris if (verboseflag == 1) { 258253109Sjimharris fprintf(stderr, "-v not currently supported without -x\n"); 259252266Sjimharris identify_usage(); 260252266Sjimharris } 261252266Sjimharris 262252266Sjimharris print_namespace(&nsdata); 263253109Sjimharris exit(0); 264252266Sjimharris} 265252266Sjimharris 266252266Sjimharrisvoid 267252266Sjimharrisidentify(int argc, char *argv[]) 268252266Sjimharris{ 269252266Sjimharris char *target; 270252266Sjimharris 271252266Sjimharris if (argc < 2) 272252266Sjimharris identify_usage(); 273252266Sjimharris 274252266Sjimharris while (getopt(argc, argv, "vx") != -1) ; 275252266Sjimharris 276252266Sjimharris target = argv[optind]; 277252266Sjimharris 278252266Sjimharris optreset = 1; 279252266Sjimharris optind = 1; 280252266Sjimharris 281252266Sjimharris /* 282252266Sjimharris * If device node contains "ns", we consider it a namespace, 283252266Sjimharris * otherwise, consider it a controller. 284252266Sjimharris */ 285252270Sjimharris if (strstr(target, NVME_NS_PREFIX) == NULL) 286252266Sjimharris identify_ctrlr(argc, argv); 287252266Sjimharris else 288252266Sjimharris identify_ns(argc, argv); 289252266Sjimharris} 290