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