identify.c revision 253114
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 253114 2013-07-09 21:31:21Z jimharris $"); 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{ 46252266Sjimharris printf("Controller Capabilities/Features\n"); 47252266Sjimharris printf("================================\n"); 48252266Sjimharris printf("Vendor ID: %04x\n", cdata->vid); 49252266Sjimharris printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 50252266Sjimharris printf("Serial Number: %s\n", cdata->sn); 51252266Sjimharris printf("Model Number: %s\n", cdata->mn); 52252266Sjimharris printf("Firmware Version: %s\n", cdata->fr); 53252266Sjimharris printf("Recommended Arb Burst: %d\n", cdata->rab); 54252266Sjimharris printf("IEEE OUI Identifier: %02x %02x %02x\n", 55252266Sjimharris cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 56252266Sjimharris printf("Multi-Interface Cap: %02x\n", cdata->mic); 57252266Sjimharris /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 58252266Sjimharris printf("Max Data Transfer Size: "); 59252266Sjimharris if (cdata->mdts == 0) 60252266Sjimharris printf("Unlimited\n"); 61252266Sjimharris else 62252266Sjimharris printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); 63252266Sjimharris printf("\n"); 64252266Sjimharris 65252266Sjimharris printf("Admin Command Set Attributes\n"); 66252266Sjimharris printf("============================\n"); 67252266Sjimharris printf("Security Send/Receive: %s\n", 68252266Sjimharris cdata->oacs.security ? "Supported" : "Not Supported"); 69252266Sjimharris printf("Format NVM: %s\n", 70252266Sjimharris cdata->oacs.format ? "Supported" : "Not Supported"); 71252266Sjimharris printf("Firmware Activate/Download: %s\n", 72252266Sjimharris cdata->oacs.firmware ? "Supported" : "Not Supported"); 73252266Sjimharris printf("Abort Command Limit: %d\n", cdata->acl+1); 74252266Sjimharris printf("Async Event Request Limit: %d\n", cdata->aerl+1); 75252266Sjimharris printf("Number of Firmware Slots: "); 76252266Sjimharris if (cdata->oacs.firmware != 0) 77252266Sjimharris printf("%d\n", cdata->frmw.num_slots); 78252266Sjimharris else 79252266Sjimharris printf("N/A\n"); 80252266Sjimharris printf("Firmware Slot 1 Read-Only: "); 81252266Sjimharris if (cdata->oacs.firmware != 0) 82252266Sjimharris printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); 83252266Sjimharris else 84252266Sjimharris printf("N/A\n"); 85252266Sjimharris printf("Per-Namespace SMART Log: %s\n", 86252266Sjimharris cdata->lpa.ns_smart ? "Yes" : "No"); 87252266Sjimharris printf("Error Log Page Entries: %d\n", cdata->elpe+1); 88252266Sjimharris printf("Number of Power States: %d\n", cdata->npss+1); 89252266Sjimharris printf("\n"); 90252266Sjimharris 91252266Sjimharris printf("NVM Command Set Attributes\n"); 92252266Sjimharris printf("==========================\n"); 93252266Sjimharris printf("Submission Queue Entry Size\n"); 94252266Sjimharris printf(" Max: %d\n", 1 << cdata->sqes.max); 95252266Sjimharris printf(" Min: %d\n", 1 << cdata->sqes.min); 96252266Sjimharris printf("Completion Queue Entry Size\n"); 97252266Sjimharris printf(" Max: %d\n", 1 << cdata->cqes.max); 98252266Sjimharris printf(" Min: %d\n", 1 << cdata->cqes.min); 99252266Sjimharris printf("Number of Namespaces: %d\n", cdata->nn); 100252266Sjimharris printf("Compare Command: %s\n", 101252266Sjimharris cdata->oncs.compare ? "Supported" : "Not Supported"); 102252266Sjimharris printf("Write Uncorrectable Command: %s\n", 103252266Sjimharris cdata->oncs.write_unc ? "Supported" : "Not Supported"); 104252266Sjimharris printf("Dataset Management Command: %s\n", 105252266Sjimharris cdata->oncs.dsm ? "Supported" : "Not Supported"); 106252266Sjimharris printf("Volatile Write Cache: %s\n", 107252266Sjimharris cdata->vwc.present ? "Present" : "Not Present"); 108252266Sjimharris} 109252266Sjimharris 110252266Sjimharrisstatic void 111252266Sjimharrisprint_namespace(struct nvme_namespace_data *nsdata) 112252266Sjimharris{ 113252266Sjimharris uint32_t i; 114252266Sjimharris 115252266Sjimharris printf("Size (in LBAs): %lld (%lldM)\n", 116252266Sjimharris (long long)nsdata->nsze, 117252266Sjimharris (long long)nsdata->nsze / 1024 / 1024); 118252266Sjimharris printf("Capacity (in LBAs): %lld (%lldM)\n", 119252266Sjimharris (long long)nsdata->ncap, 120252266Sjimharris (long long)nsdata->ncap / 1024 / 1024); 121252266Sjimharris printf("Utilization (in LBAs): %lld (%lldM)\n", 122252266Sjimharris (long long)nsdata->nuse, 123252266Sjimharris (long long)nsdata->nuse / 1024 / 1024); 124252266Sjimharris printf("Thin Provisioning: %s\n", 125252266Sjimharris nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); 126252266Sjimharris printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 127252266Sjimharris printf("Current LBA Format: LBA Format #%d\n", 128252266Sjimharris nsdata->flbas.format); 129252266Sjimharris for (i = 0; i <= nsdata->nlbaf; i++) { 130252266Sjimharris printf("LBA Format #%d:\n", i); 131252266Sjimharris printf(" LBA Data Size: %d\n", 132252266Sjimharris 1 << nsdata->lbaf[i].lbads); 133252266Sjimharris } 134252266Sjimharris} 135252266Sjimharris 136252266Sjimharrisstatic void 137252266Sjimharrisidentify_usage(void) 138252266Sjimharris{ 139252266Sjimharris fprintf(stderr, "usage:\n"); 140252266Sjimharris fprintf(stderr, IDENTIFY_USAGE); 141253109Sjimharris exit(1); 142252266Sjimharris} 143252266Sjimharris 144252266Sjimharrisstatic void 145252266Sjimharrisidentify_ctrlr(int argc, char *argv[]) 146252266Sjimharris{ 147252266Sjimharris struct nvme_controller_data cdata; 148252266Sjimharris int ch, fd, hexflag = 0, hexlength; 149252266Sjimharris int verboseflag = 0; 150252266Sjimharris 151252266Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 152252266Sjimharris switch ((char)ch) { 153252266Sjimharris case 'v': 154252266Sjimharris verboseflag = 1; 155252266Sjimharris break; 156252266Sjimharris case 'x': 157252266Sjimharris hexflag = 1; 158252266Sjimharris break; 159252266Sjimharris default: 160252266Sjimharris identify_usage(); 161252266Sjimharris } 162252266Sjimharris } 163252266Sjimharris 164252274Sjimharris /* Check that a controller was specified. */ 165252274Sjimharris if (optind >= argc) 166252274Sjimharris identify_usage(); 167252274Sjimharris 168252266Sjimharris open_dev(argv[optind], &fd, 1, 1); 169252266Sjimharris read_controller_data(fd, &cdata); 170252266Sjimharris close(fd); 171252266Sjimharris 172252266Sjimharris if (hexflag == 1) { 173252266Sjimharris if (verboseflag == 1) 174252266Sjimharris hexlength = sizeof(struct nvme_controller_data); 175252266Sjimharris else 176252266Sjimharris hexlength = offsetof(struct nvme_controller_data, 177252266Sjimharris reserved5); 178252275Sjimharris print_hex(&cdata, hexlength); 179253109Sjimharris exit(0); 180252266Sjimharris } 181252266Sjimharris 182252266Sjimharris if (verboseflag == 1) { 183253109Sjimharris fprintf(stderr, "-v not currently supported without -x\n"); 184252266Sjimharris identify_usage(); 185252266Sjimharris } 186252266Sjimharris 187252266Sjimharris print_controller(&cdata); 188253109Sjimharris exit(0); 189252266Sjimharris} 190252266Sjimharris 191252266Sjimharrisstatic void 192252266Sjimharrisidentify_ns(int argc, char *argv[]) 193252266Sjimharris{ 194252266Sjimharris struct nvme_namespace_data nsdata; 195252266Sjimharris char path[64]; 196252266Sjimharris int ch, fd, hexflag = 0, hexlength, nsid; 197252266Sjimharris int verboseflag = 0; 198252266Sjimharris 199252266Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 200252266Sjimharris switch ((char)ch) { 201252266Sjimharris case 'v': 202252266Sjimharris verboseflag = 1; 203252266Sjimharris break; 204252266Sjimharris case 'x': 205252266Sjimharris hexflag = 1; 206252266Sjimharris break; 207252266Sjimharris default: 208252266Sjimharris identify_usage(); 209252266Sjimharris } 210252266Sjimharris } 211252266Sjimharris 212252274Sjimharris /* Check that a namespace was specified. */ 213252274Sjimharris if (optind >= argc) 214252274Sjimharris identify_usage(); 215252274Sjimharris 216252266Sjimharris /* 217252266Sjimharris * Check if the specified device node exists before continuing. 218252266Sjimharris * This is a cleaner check for cases where the correct controller 219252266Sjimharris * is specified, but an invalid namespace on that controller. 220252266Sjimharris */ 221252266Sjimharris open_dev(argv[optind], &fd, 1, 1); 222252266Sjimharris close(fd); 223252266Sjimharris 224252266Sjimharris /* 225252266Sjimharris * We send IDENTIFY commands to the controller, not the namespace, 226253114Sjimharris * since it is an admin cmd. The namespace ID will be specified in 227253114Sjimharris * the IDENTIFY command itself. So parse the namespace's device node 228253114Sjimharris * string to get the controller substring and namespace ID. 229252266Sjimharris */ 230253114Sjimharris parse_ns_str(argv[optind], path, &nsid); 231252266Sjimharris open_dev(path, &fd, 1, 1); 232252266Sjimharris read_namespace_data(fd, nsid, &nsdata); 233252266Sjimharris close(fd); 234252266Sjimharris 235252266Sjimharris if (hexflag == 1) { 236252266Sjimharris if (verboseflag == 1) 237252266Sjimharris hexlength = sizeof(struct nvme_namespace_data); 238252266Sjimharris else 239252266Sjimharris hexlength = offsetof(struct nvme_namespace_data, 240252266Sjimharris reserved6); 241252275Sjimharris print_hex(&nsdata, hexlength); 242253109Sjimharris exit(0); 243252266Sjimharris } 244252266Sjimharris 245252266Sjimharris if (verboseflag == 1) { 246253109Sjimharris fprintf(stderr, "-v not currently supported without -x\n"); 247252266Sjimharris identify_usage(); 248252266Sjimharris } 249252266Sjimharris 250252266Sjimharris print_namespace(&nsdata); 251253109Sjimharris exit(0); 252252266Sjimharris} 253252266Sjimharris 254252266Sjimharrisvoid 255252266Sjimharrisidentify(int argc, char *argv[]) 256252266Sjimharris{ 257252266Sjimharris char *target; 258252266Sjimharris 259252266Sjimharris if (argc < 2) 260252266Sjimharris identify_usage(); 261252266Sjimharris 262252266Sjimharris while (getopt(argc, argv, "vx") != -1) ; 263252266Sjimharris 264252266Sjimharris target = argv[optind]; 265252266Sjimharris 266252266Sjimharris optreset = 1; 267252266Sjimharris optind = 1; 268252266Sjimharris 269252266Sjimharris /* 270252266Sjimharris * If device node contains "ns", we consider it a namespace, 271252266Sjimharris * otherwise, consider it a controller. 272252266Sjimharris */ 273252270Sjimharris if (strstr(target, NVME_NS_PREFIX) == NULL) 274252266Sjimharris identify_ctrlr(argc, argv); 275252266Sjimharris else 276252266Sjimharris identify_ns(argc, argv); 277252266Sjimharris} 278