1252266Sjimharris/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4252266Sjimharris * Copyright (C) 2012-2013 Intel Corporation 5252266Sjimharris * All rights reserved. 6252266Sjimharris * 7252266Sjimharris * Redistribution and use in source and binary forms, with or without 8252266Sjimharris * modification, are permitted provided that the following conditions 9252266Sjimharris * are met: 10252266Sjimharris * 1. Redistributions of source code must retain the above copyright 11252266Sjimharris * notice, this list of conditions and the following disclaimer. 12252266Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 13252266Sjimharris * notice, this list of conditions and the following disclaimer in the 14252266Sjimharris * documentation and/or other materials provided with the distribution. 15252266Sjimharris * 16252266Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17252266Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18252266Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19252266Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20252266Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21252266Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22252266Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23252266Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24252266Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25252266Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26252266Sjimharris * SUCH DAMAGE. 27252266Sjimharris */ 28252266Sjimharris 29252266Sjimharris#include <sys/cdefs.h> 30252266Sjimharris__FBSDID("$FreeBSD: stable/11/sbin/nvmecontrol/identify.c 330449 2018-03-05 07:26:05Z eadler $"); 31252266Sjimharris 32252266Sjimharris#include <sys/param.h> 33252266Sjimharris 34252266Sjimharris#include <ctype.h> 35253109Sjimharris#include <err.h> 36252266Sjimharris#include <fcntl.h> 37252266Sjimharris#include <stddef.h> 38252266Sjimharris#include <stdio.h> 39252266Sjimharris#include <stdlib.h> 40252266Sjimharris#include <string.h> 41252266Sjimharris#include <unistd.h> 42252266Sjimharris 43252266Sjimharris#include "nvmecontrol.h" 44252266Sjimharris 45252266Sjimharrisstatic void 46252266Sjimharrisprint_controller(struct nvme_controller_data *cdata) 47252266Sjimharris{ 48253476Sjimharris uint8_t str[128]; 49328729Smav char cbuf[UINT128_DIG + 1]; 50253476Sjimharris 51252266Sjimharris printf("Controller Capabilities/Features\n"); 52252266Sjimharris printf("================================\n"); 53252266Sjimharris printf("Vendor ID: %04x\n", cdata->vid); 54252266Sjimharris printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 55253476Sjimharris nvme_strvis(str, cdata->sn, sizeof(str), NVME_SERIAL_NUMBER_LENGTH); 56253476Sjimharris printf("Serial Number: %s\n", str); 57253476Sjimharris nvme_strvis(str, cdata->mn, sizeof(str), NVME_MODEL_NUMBER_LENGTH); 58253476Sjimharris printf("Model Number: %s\n", str); 59253476Sjimharris nvme_strvis(str, cdata->fr, sizeof(str), NVME_FIRMWARE_REVISION_LENGTH); 60253476Sjimharris printf("Firmware Version: %s\n", str); 61252266Sjimharris printf("Recommended Arb Burst: %d\n", cdata->rab); 62252266Sjimharris printf("IEEE OUI Identifier: %02x %02x %02x\n", 63252266Sjimharris cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 64252266Sjimharris printf("Multi-Interface Cap: %02x\n", cdata->mic); 65252266Sjimharris /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 66252266Sjimharris printf("Max Data Transfer Size: "); 67252266Sjimharris if (cdata->mdts == 0) 68252266Sjimharris printf("Unlimited\n"); 69252266Sjimharris else 70252266Sjimharris printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); 71328733Smav printf("Controller ID: 0x%02x\n", cdata->ctrlr_id); 72328733Smav printf("\n"); 73328729Smav 74252266Sjimharris printf("Admin Command Set Attributes\n"); 75252266Sjimharris printf("============================\n"); 76252266Sjimharris printf("Security Send/Receive: %s\n", 77252266Sjimharris cdata->oacs.security ? "Supported" : "Not Supported"); 78252266Sjimharris printf("Format NVM: %s\n", 79252266Sjimharris cdata->oacs.format ? "Supported" : "Not Supported"); 80252266Sjimharris printf("Firmware Activate/Download: %s\n", 81252266Sjimharris cdata->oacs.firmware ? "Supported" : "Not Supported"); 82328729Smav printf("Namespace Managment: %s\n", 83328729Smav cdata->oacs.nsmgmt ? "Supported" : "Not Supported"); 84252266Sjimharris printf("Abort Command Limit: %d\n", cdata->acl+1); 85252266Sjimharris printf("Async Event Request Limit: %d\n", cdata->aerl+1); 86252266Sjimharris printf("Number of Firmware Slots: "); 87252266Sjimharris if (cdata->oacs.firmware != 0) 88252266Sjimharris printf("%d\n", cdata->frmw.num_slots); 89252266Sjimharris else 90252266Sjimharris printf("N/A\n"); 91252266Sjimharris printf("Firmware Slot 1 Read-Only: "); 92252266Sjimharris if (cdata->oacs.firmware != 0) 93252266Sjimharris printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); 94252266Sjimharris else 95252266Sjimharris printf("N/A\n"); 96252266Sjimharris printf("Per-Namespace SMART Log: %s\n", 97252266Sjimharris cdata->lpa.ns_smart ? "Yes" : "No"); 98252266Sjimharris printf("Error Log Page Entries: %d\n", cdata->elpe+1); 99252266Sjimharris printf("Number of Power States: %d\n", cdata->npss+1); 100328729Smav 101252266Sjimharris printf("\n"); 102252266Sjimharris printf("NVM Command Set Attributes\n"); 103252266Sjimharris printf("==========================\n"); 104252266Sjimharris printf("Submission Queue Entry Size\n"); 105252266Sjimharris printf(" Max: %d\n", 1 << cdata->sqes.max); 106252266Sjimharris printf(" Min: %d\n", 1 << cdata->sqes.min); 107252266Sjimharris printf("Completion Queue Entry Size\n"); 108252266Sjimharris printf(" Max: %d\n", 1 << cdata->cqes.max); 109252266Sjimharris printf(" Min: %d\n", 1 << cdata->cqes.min); 110252266Sjimharris printf("Number of Namespaces: %d\n", cdata->nn); 111252266Sjimharris printf("Compare Command: %s\n", 112252266Sjimharris cdata->oncs.compare ? "Supported" : "Not Supported"); 113252266Sjimharris printf("Write Uncorrectable Command: %s\n", 114252266Sjimharris cdata->oncs.write_unc ? "Supported" : "Not Supported"); 115252266Sjimharris printf("Dataset Management Command: %s\n", 116252266Sjimharris cdata->oncs.dsm ? "Supported" : "Not Supported"); 117252266Sjimharris printf("Volatile Write Cache: %s\n", 118252266Sjimharris cdata->vwc.present ? "Present" : "Not Present"); 119328729Smav 120328729Smav if (cdata->oacs.nsmgmt) { 121328729Smav printf("\n"); 122328729Smav printf("Namespace Drive Attributes\n"); 123328729Smav printf("==========================\n"); 124328729Smav printf("NVM total cap: %s\n", 125328729Smav uint128_to_str(to128(cdata->untncap.tnvmcap), cbuf, sizeof(cbuf))); 126328729Smav printf("NVM unallocated cap: %s\n", 127328729Smav uint128_to_str(to128(cdata->untncap.unvmcap), cbuf, sizeof(cbuf))); 128328729Smav } 129252266Sjimharris} 130252266Sjimharris 131252266Sjimharrisstatic void 132252266Sjimharrisprint_namespace(struct nvme_namespace_data *nsdata) 133252266Sjimharris{ 134252266Sjimharris uint32_t i; 135252266Sjimharris 136252266Sjimharris printf("Size (in LBAs): %lld (%lldM)\n", 137252266Sjimharris (long long)nsdata->nsze, 138252266Sjimharris (long long)nsdata->nsze / 1024 / 1024); 139252266Sjimharris printf("Capacity (in LBAs): %lld (%lldM)\n", 140252266Sjimharris (long long)nsdata->ncap, 141252266Sjimharris (long long)nsdata->ncap / 1024 / 1024); 142252266Sjimharris printf("Utilization (in LBAs): %lld (%lldM)\n", 143252266Sjimharris (long long)nsdata->nuse, 144252266Sjimharris (long long)nsdata->nuse / 1024 / 1024); 145252266Sjimharris printf("Thin Provisioning: %s\n", 146252266Sjimharris nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); 147252266Sjimharris printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 148253115Sjimharris printf("Current LBA Format: LBA Format #%02d\n", 149252266Sjimharris nsdata->flbas.format); 150253115Sjimharris for (i = 0; i <= nsdata->nlbaf; i++) 151253115Sjimharris printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n", 152253115Sjimharris i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms); 153252266Sjimharris} 154252266Sjimharris 155252266Sjimharrisstatic void 156252266Sjimharrisidentify_usage(void) 157252266Sjimharris{ 158252266Sjimharris fprintf(stderr, "usage:\n"); 159252266Sjimharris fprintf(stderr, IDENTIFY_USAGE); 160253109Sjimharris exit(1); 161252266Sjimharris} 162252266Sjimharris 163252266Sjimharrisstatic void 164252266Sjimharrisidentify_ctrlr(int argc, char *argv[]) 165252266Sjimharris{ 166252266Sjimharris struct nvme_controller_data cdata; 167252266Sjimharris int ch, fd, hexflag = 0, hexlength; 168252266Sjimharris int verboseflag = 0; 169252266Sjimharris 170252266Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 171252266Sjimharris switch ((char)ch) { 172252266Sjimharris case 'v': 173252266Sjimharris verboseflag = 1; 174252266Sjimharris break; 175252266Sjimharris case 'x': 176252266Sjimharris hexflag = 1; 177252266Sjimharris break; 178252266Sjimharris default: 179252266Sjimharris identify_usage(); 180252266Sjimharris } 181252266Sjimharris } 182252266Sjimharris 183252274Sjimharris /* Check that a controller was specified. */ 184252274Sjimharris if (optind >= argc) 185252274Sjimharris identify_usage(); 186252274Sjimharris 187252266Sjimharris open_dev(argv[optind], &fd, 1, 1); 188252266Sjimharris read_controller_data(fd, &cdata); 189252266Sjimharris close(fd); 190252266Sjimharris 191252266Sjimharris if (hexflag == 1) { 192252266Sjimharris if (verboseflag == 1) 193252266Sjimharris hexlength = sizeof(struct nvme_controller_data); 194252266Sjimharris else 195252266Sjimharris hexlength = offsetof(struct nvme_controller_data, 196252266Sjimharris reserved5); 197252275Sjimharris print_hex(&cdata, hexlength); 198253109Sjimharris exit(0); 199252266Sjimharris } 200252266Sjimharris 201252266Sjimharris if (verboseflag == 1) { 202253109Sjimharris fprintf(stderr, "-v not currently supported without -x\n"); 203252266Sjimharris identify_usage(); 204252266Sjimharris } 205252266Sjimharris 206252266Sjimharris print_controller(&cdata); 207253109Sjimharris exit(0); 208252266Sjimharris} 209252266Sjimharris 210252266Sjimharrisstatic void 211252266Sjimharrisidentify_ns(int argc, char *argv[]) 212252266Sjimharris{ 213252266Sjimharris struct nvme_namespace_data nsdata; 214252266Sjimharris char path[64]; 215252266Sjimharris int ch, fd, hexflag = 0, hexlength, nsid; 216252266Sjimharris int verboseflag = 0; 217252266Sjimharris 218252266Sjimharris while ((ch = getopt(argc, argv, "vx")) != -1) { 219252266Sjimharris switch ((char)ch) { 220252266Sjimharris case 'v': 221252266Sjimharris verboseflag = 1; 222252266Sjimharris break; 223252266Sjimharris case 'x': 224252266Sjimharris hexflag = 1; 225252266Sjimharris break; 226252266Sjimharris default: 227252266Sjimharris identify_usage(); 228252266Sjimharris } 229252266Sjimharris } 230252266Sjimharris 231252274Sjimharris /* Check that a namespace was specified. */ 232252274Sjimharris if (optind >= argc) 233252274Sjimharris identify_usage(); 234252274Sjimharris 235252266Sjimharris /* 236252266Sjimharris * Check if the specified device node exists before continuing. 237252266Sjimharris * This is a cleaner check for cases where the correct controller 238252266Sjimharris * is specified, but an invalid namespace on that controller. 239252266Sjimharris */ 240252266Sjimharris open_dev(argv[optind], &fd, 1, 1); 241252266Sjimharris close(fd); 242252266Sjimharris 243252266Sjimharris /* 244252266Sjimharris * We send IDENTIFY commands to the controller, not the namespace, 245253114Sjimharris * since it is an admin cmd. The namespace ID will be specified in 246253114Sjimharris * the IDENTIFY command itself. So parse the namespace's device node 247253114Sjimharris * string to get the controller substring and namespace ID. 248252266Sjimharris */ 249253114Sjimharris parse_ns_str(argv[optind], path, &nsid); 250252266Sjimharris open_dev(path, &fd, 1, 1); 251252266Sjimharris read_namespace_data(fd, nsid, &nsdata); 252252266Sjimharris close(fd); 253252266Sjimharris 254252266Sjimharris if (hexflag == 1) { 255252266Sjimharris if (verboseflag == 1) 256252266Sjimharris hexlength = sizeof(struct nvme_namespace_data); 257252266Sjimharris else 258252266Sjimharris hexlength = offsetof(struct nvme_namespace_data, 259252266Sjimharris reserved6); 260252275Sjimharris print_hex(&nsdata, hexlength); 261253109Sjimharris exit(0); 262252266Sjimharris } 263252266Sjimharris 264252266Sjimharris if (verboseflag == 1) { 265253109Sjimharris fprintf(stderr, "-v not currently supported without -x\n"); 266252266Sjimharris identify_usage(); 267252266Sjimharris } 268252266Sjimharris 269252266Sjimharris print_namespace(&nsdata); 270253109Sjimharris exit(0); 271252266Sjimharris} 272252266Sjimharris 273252266Sjimharrisvoid 274252266Sjimharrisidentify(int argc, char *argv[]) 275252266Sjimharris{ 276252266Sjimharris char *target; 277252266Sjimharris 278252266Sjimharris if (argc < 2) 279252266Sjimharris identify_usage(); 280252266Sjimharris 281252266Sjimharris while (getopt(argc, argv, "vx") != -1) ; 282252266Sjimharris 283253116Sjimharris /* Check that a controller or namespace was specified. */ 284253116Sjimharris if (optind >= argc) 285253116Sjimharris identify_usage(); 286253116Sjimharris 287252266Sjimharris target = argv[optind]; 288252266Sjimharris 289252266Sjimharris optreset = 1; 290252266Sjimharris optind = 1; 291252266Sjimharris 292252266Sjimharris /* 293252266Sjimharris * If device node contains "ns", we consider it a namespace, 294252266Sjimharris * otherwise, consider it a controller. 295252266Sjimharris */ 296252270Sjimharris if (strstr(target, NVME_NS_PREFIX) == NULL) 297252266Sjimharris identify_ctrlr(argc, argv); 298252266Sjimharris else 299252266Sjimharris identify_ns(argc, argv); 300252266Sjimharris} 301