1 1.9 andvar /* $NetBSD: identify.c,v 1.9 2022/02/17 14:33:25 andvar Exp $ */ 2 1.1 nonaka 3 1.1 nonaka /*- 4 1.4 nonaka * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5 1.4 nonaka * 6 1.1 nonaka * Copyright (C) 2012-2013 Intel Corporation 7 1.1 nonaka * All rights reserved. 8 1.1 nonaka * 9 1.1 nonaka * Redistribution and use in source and binary forms, with or without 10 1.1 nonaka * modification, are permitted provided that the following conditions 11 1.1 nonaka * are met: 12 1.1 nonaka * 1. Redistributions of source code must retain the above copyright 13 1.1 nonaka * notice, this list of conditions and the following disclaimer. 14 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 nonaka * notice, this list of conditions and the following disclaimer in the 16 1.1 nonaka * documentation and/or other materials provided with the distribution. 17 1.1 nonaka * 18 1.1 nonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 1.1 nonaka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 1.1 nonaka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 1.1 nonaka * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 1.1 nonaka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 1.1 nonaka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 1.1 nonaka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.1 nonaka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 1.1 nonaka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 nonaka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 nonaka * SUCH DAMAGE. 29 1.1 nonaka */ 30 1.1 nonaka 31 1.1 nonaka #include <sys/cdefs.h> 32 1.1 nonaka #ifndef lint 33 1.9 andvar __RCSID("$NetBSD: identify.c,v 1.9 2022/02/17 14:33:25 andvar Exp $"); 34 1.1 nonaka #if 0 35 1.5 nonaka __FBSDID("$FreeBSD: head/sbin/nvmecontrol/identify.c 329824 2018-02-22 13:32:31Z wma $"); 36 1.1 nonaka #endif 37 1.1 nonaka #endif 38 1.1 nonaka 39 1.1 nonaka #include <sys/param.h> 40 1.1 nonaka 41 1.1 nonaka #include <ctype.h> 42 1.1 nonaka #include <err.h> 43 1.1 nonaka #include <fcntl.h> 44 1.1 nonaka #include <stddef.h> 45 1.1 nonaka #include <stdio.h> 46 1.1 nonaka #include <stdlib.h> 47 1.1 nonaka #include <string.h> 48 1.1 nonaka #include <unistd.h> 49 1.1 nonaka 50 1.1 nonaka #include "nvmectl.h" 51 1.1 nonaka 52 1.1 nonaka static void 53 1.1 nonaka print_controller(struct nvm_identify_controller *cdata) 54 1.1 nonaka { 55 1.1 nonaka uint8_t str[128]; 56 1.1 nonaka 57 1.1 nonaka printf("Controller Capabilities/Features\n"); 58 1.1 nonaka printf("================================\n"); 59 1.1 nonaka printf("Vendor ID: %04x\n", cdata->vid); 60 1.1 nonaka printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 61 1.1 nonaka nvme_strvis(str, sizeof(str), cdata->sn, sizeof(cdata->sn)); 62 1.1 nonaka printf("Serial Number: %s\n", str); 63 1.1 nonaka nvme_strvis(str, sizeof(str), cdata->mn, sizeof(cdata->mn)); 64 1.1 nonaka printf("Model Number: %s\n", str); 65 1.1 nonaka nvme_strvis(str, sizeof(str), cdata->fr, sizeof(cdata->fr)); 66 1.1 nonaka printf("Firmware Version: %s\n", str); 67 1.1 nonaka printf("Recommended Arb Burst: %d\n", cdata->rab); 68 1.1 nonaka printf("IEEE OUI Identifier: %02x %02x %02x\n", 69 1.1 nonaka cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 70 1.1 nonaka printf("Multi-Interface Cap: %02x\n", cdata->cmic); 71 1.1 nonaka /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 72 1.1 nonaka printf("Max Data Transfer Size: "); 73 1.1 nonaka if (cdata->mdts == 0) 74 1.1 nonaka printf("Unlimited\n"); 75 1.1 nonaka else 76 1.1 nonaka printf("%ld\n", sysconf(_SC_PAGESIZE) * (1 << cdata->mdts)); 77 1.4 nonaka printf("Controller ID: 0x%02x\n", cdata->cntlid); 78 1.1 nonaka printf("\n"); 79 1.1 nonaka 80 1.1 nonaka printf("Admin Command Set Attributes\n"); 81 1.1 nonaka printf("============================\n"); 82 1.1 nonaka printf("Security Send/Receive: %s\n", 83 1.1 nonaka (cdata->oacs & NVME_ID_CTRLR_OACS_SECURITY) ? 84 1.1 nonaka "Supported" : "Not Supported"); 85 1.1 nonaka printf("Format NVM: %s\n", 86 1.1 nonaka (cdata->oacs & NVME_ID_CTRLR_OACS_FORMAT) ? 87 1.1 nonaka "Supported" : "Not Supported"); 88 1.1 nonaka printf("Firmware Activate/Download: %s\n", 89 1.1 nonaka (cdata->oacs & NVME_ID_CTRLR_OACS_FW) ? 90 1.1 nonaka "Supported" : "Not Supported"); 91 1.9 andvar printf("Namespace Management: %s\n", 92 1.4 nonaka (cdata->oacs & NVME_ID_CTRLR_OACS_NS) ? 93 1.4 nonaka "Supported" : "Not Supported"); 94 1.1 nonaka printf("Abort Command Limit: %d\n", cdata->acl+1); 95 1.1 nonaka printf("Async Event Request Limit: %d\n", cdata->aerl+1); 96 1.1 nonaka printf("Number of Firmware Slots: "); 97 1.1 nonaka if (cdata->oacs & NVME_ID_CTRLR_OACS_FW) 98 1.1 nonaka printf("%d\n", 99 1.1 nonaka (uint8_t)__SHIFTOUT(cdata->frmw, NVME_ID_CTRLR_FRMW_NSLOT)); 100 1.1 nonaka else 101 1.1 nonaka printf("N/A\n"); 102 1.1 nonaka printf("Firmware Slot 1 Read-Only: "); 103 1.1 nonaka if (cdata->oacs & NVME_ID_CTRLR_OACS_FW) 104 1.1 nonaka printf("%s\n", (cdata->frmw & NVME_ID_CTRLR_FRMW_SLOT1_RO) ? 105 1.1 nonaka "Yes" : "No"); 106 1.1 nonaka else 107 1.1 nonaka printf("N/A\n"); 108 1.1 nonaka printf("Per-Namespace SMART Log: %s\n", 109 1.1 nonaka (cdata->lpa & NVME_ID_CTRLR_LPA_NS_SMART) ? "Yes" : "No"); 110 1.1 nonaka printf("Error Log Page Entries: %d\n", cdata->elpe+1); 111 1.1 nonaka printf("Number of Power States: %d\n", cdata->npss+1); 112 1.1 nonaka printf("\n"); 113 1.1 nonaka 114 1.1 nonaka printf("NVM Command Set Attributes\n"); 115 1.1 nonaka printf("==========================\n"); 116 1.1 nonaka printf("Submission Queue Entry Size\n"); 117 1.1 nonaka printf(" Max: %d\n", 118 1.1 nonaka 1 << __SHIFTOUT(cdata->sqes, NVME_ID_CTRLR_SQES_MAX)); 119 1.1 nonaka printf(" Min: %d\n", 120 1.1 nonaka 1 << __SHIFTOUT(cdata->sqes, NVME_ID_CTRLR_SQES_MIN)); 121 1.1 nonaka printf("Completion Queue Entry Size\n"); 122 1.1 nonaka printf(" Max: %d\n", 123 1.1 nonaka 1 << __SHIFTOUT(cdata->cqes, NVME_ID_CTRLR_CQES_MAX)); 124 1.1 nonaka printf(" Min: %d\n", 125 1.1 nonaka 1 << __SHIFTOUT(cdata->cqes, NVME_ID_CTRLR_CQES_MIN)); 126 1.1 nonaka printf("Number of Namespaces: %d\n", cdata->nn); 127 1.1 nonaka printf("Compare Command: %s\n", 128 1.1 nonaka (cdata->oncs & NVME_ID_CTRLR_ONCS_COMPARE) ? 129 1.1 nonaka "Supported" : "Not Supported"); 130 1.1 nonaka printf("Write Uncorrectable Command: %s\n", 131 1.1 nonaka (cdata->oncs & NVME_ID_CTRLR_ONCS_WRITE_UNC) ? 132 1.1 nonaka "Supported" : "Not Supported"); 133 1.1 nonaka printf("Dataset Management Command: %s\n", 134 1.1 nonaka (cdata->oncs & NVME_ID_CTRLR_ONCS_DSM) ? 135 1.1 nonaka "Supported" : "Not Supported"); 136 1.1 nonaka printf("Write Zeroes Command: %s\n", 137 1.1 nonaka (cdata->oncs & NVME_ID_CTRLR_ONCS_WRITE_ZERO) ? 138 1.1 nonaka "Supported" : "Not Supported"); 139 1.6 jdolecek printf("Features Save/Select Field: %s\n", 140 1.1 nonaka (cdata->oncs & NVME_ID_CTRLR_ONCS_SET_FEATURES) ? 141 1.1 nonaka "Supported" : "Not Supported"); 142 1.1 nonaka printf("Reservation: %s\n", 143 1.1 nonaka (cdata->oncs & NVME_ID_CTRLR_ONCS_RESERVATION) ? 144 1.1 nonaka "Supported" : "Not Supported"); 145 1.1 nonaka printf("Volatile Write Cache: %s\n", 146 1.1 nonaka (cdata->vwc & NVME_ID_CTRLR_VWC_PRESENT) ? 147 1.1 nonaka "Present" : "Not Present"); 148 1.7 jdolecek printf("Autonomous Power State Transitions: %s\n", 149 1.7 jdolecek (cdata->apsta & NVME_ID_CTRLR_APSTA_PRESENT) ? 150 1.7 jdolecek "Supported" : "Not Supported"); 151 1.4 nonaka 152 1.4 nonaka if (cdata->oacs & NVME_ID_CTRLR_OACS_NS) { 153 1.4 nonaka printf("\n"); 154 1.4 nonaka printf("Namespace Drive Attributes\n"); 155 1.4 nonaka printf("==========================\n"); 156 1.4 nonaka print_bignum("NVM total cap: ", 157 1.4 nonaka cdata->untncap.tnvmcap, ""); 158 1.4 nonaka print_bignum("NVM unallocated cap: ", 159 1.4 nonaka cdata->untncap.unvmcap, ""); 160 1.4 nonaka } 161 1.1 nonaka } 162 1.1 nonaka 163 1.1 nonaka static void 164 1.1 nonaka print_namespace(struct nvm_identify_namespace *nsdata) 165 1.1 nonaka { 166 1.1 nonaka uint32_t i; 167 1.1 nonaka 168 1.1 nonaka printf("Size (in LBAs): %lld (%lldM)\n", 169 1.1 nonaka (long long)nsdata->nsze, 170 1.1 nonaka (long long)nsdata->nsze / 1024 / 1024); 171 1.1 nonaka printf("Capacity (in LBAs): %lld (%lldM)\n", 172 1.1 nonaka (long long)nsdata->ncap, 173 1.1 nonaka (long long)nsdata->ncap / 1024 / 1024); 174 1.1 nonaka printf("Utilization (in LBAs): %lld (%lldM)\n", 175 1.1 nonaka (long long)nsdata->nuse, 176 1.1 nonaka (long long)nsdata->nuse / 1024 / 1024); 177 1.1 nonaka printf("Thin Provisioning: %s\n", 178 1.1 nonaka (nsdata->nsfeat & NVME_ID_NS_NSFEAT_THIN_PROV) ? 179 1.1 nonaka "Supported" : "Not Supported"); 180 1.1 nonaka printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 181 1.1 nonaka printf("Current LBA Format: LBA Format #%02d\n", 182 1.1 nonaka NVME_ID_NS_FLBAS(nsdata->flbas)); 183 1.1 nonaka for (i = 0; i <= nsdata->nlbaf; i++) 184 1.1 nonaka printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n", 185 1.1 nonaka i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms); 186 1.1 nonaka } 187 1.1 nonaka 188 1.2 joerg __dead static void 189 1.1 nonaka identify_usage(void) 190 1.1 nonaka { 191 1.1 nonaka fprintf(stderr, "usage:\n"); 192 1.3 jdolecek fprintf(stderr, "\t%s " IDENTIFY_USAGE, getprogname()); 193 1.1 nonaka exit(1); 194 1.1 nonaka } 195 1.1 nonaka 196 1.2 joerg __dead static void 197 1.1 nonaka identify_ctrlr(int argc, char *argv[]) 198 1.1 nonaka { 199 1.1 nonaka struct nvm_identify_controller cdata; 200 1.1 nonaka int ch, fd, hexflag = 0, hexlength; 201 1.1 nonaka int verboseflag = 0; 202 1.1 nonaka 203 1.1 nonaka while ((ch = getopt(argc, argv, "vx")) != -1) { 204 1.1 nonaka switch (ch) { 205 1.1 nonaka case 'v': 206 1.1 nonaka verboseflag = 1; 207 1.1 nonaka break; 208 1.1 nonaka case 'x': 209 1.1 nonaka hexflag = 1; 210 1.1 nonaka break; 211 1.1 nonaka default: 212 1.1 nonaka identify_usage(); 213 1.1 nonaka } 214 1.1 nonaka } 215 1.1 nonaka 216 1.1 nonaka /* Check that a controller was specified. */ 217 1.1 nonaka if (optind >= argc) 218 1.1 nonaka identify_usage(); 219 1.1 nonaka 220 1.1 nonaka open_dev(argv[optind], &fd, 1, 1); 221 1.1 nonaka read_controller_data(fd, &cdata); 222 1.1 nonaka close(fd); 223 1.1 nonaka 224 1.1 nonaka if (hexflag == 1) { 225 1.1 nonaka if (verboseflag == 1) 226 1.1 nonaka hexlength = sizeof(struct nvm_identify_controller); 227 1.1 nonaka else 228 1.1 nonaka hexlength = offsetof(struct nvm_identify_controller, 229 1.1 nonaka _reserved7); 230 1.1 nonaka print_hex(&cdata, hexlength); 231 1.1 nonaka exit(0); 232 1.1 nonaka } 233 1.1 nonaka 234 1.1 nonaka if (verboseflag == 1) { 235 1.1 nonaka fprintf(stderr, "-v not currently supported without -x\n"); 236 1.1 nonaka identify_usage(); 237 1.1 nonaka } 238 1.1 nonaka 239 1.1 nonaka print_controller(&cdata); 240 1.1 nonaka exit(0); 241 1.1 nonaka } 242 1.1 nonaka 243 1.2 joerg __dead static void 244 1.1 nonaka identify_ns(int argc, char *argv[]) 245 1.1 nonaka { 246 1.1 nonaka struct nvm_identify_namespace nsdata; 247 1.1 nonaka char path[64]; 248 1.1 nonaka int ch, fd, hexflag = 0, hexlength, nsid; 249 1.1 nonaka int verboseflag = 0; 250 1.1 nonaka 251 1.1 nonaka while ((ch = getopt(argc, argv, "vx")) != -1) { 252 1.1 nonaka switch (ch) { 253 1.1 nonaka case 'v': 254 1.1 nonaka verboseflag = 1; 255 1.1 nonaka break; 256 1.1 nonaka case 'x': 257 1.1 nonaka hexflag = 1; 258 1.1 nonaka break; 259 1.1 nonaka default: 260 1.1 nonaka identify_usage(); 261 1.1 nonaka } 262 1.1 nonaka } 263 1.1 nonaka 264 1.1 nonaka /* Check that a namespace was specified. */ 265 1.1 nonaka if (optind >= argc) 266 1.1 nonaka identify_usage(); 267 1.1 nonaka 268 1.1 nonaka /* 269 1.1 nonaka * Check if the specified device node exists before continuing. 270 1.1 nonaka * This is a cleaner check for cases where the correct controller 271 1.1 nonaka * is specified, but an invalid namespace on that controller. 272 1.1 nonaka */ 273 1.1 nonaka open_dev(argv[optind], &fd, 1, 1); 274 1.1 nonaka close(fd); 275 1.1 nonaka 276 1.1 nonaka /* 277 1.1 nonaka * We send IDENTIFY commands to the controller, not the namespace, 278 1.1 nonaka * since it is an admin cmd. The namespace ID will be specified in 279 1.1 nonaka * the IDENTIFY command itself. So parse the namespace's device node 280 1.1 nonaka * string to get the controller substring and namespace ID. 281 1.1 nonaka */ 282 1.1 nonaka parse_ns_str(argv[optind], path, &nsid); 283 1.1 nonaka open_dev(path, &fd, 1, 1); 284 1.1 nonaka read_namespace_data(fd, nsid, &nsdata); 285 1.1 nonaka close(fd); 286 1.1 nonaka 287 1.1 nonaka if (hexflag == 1) { 288 1.1 nonaka if (verboseflag == 1) 289 1.1 nonaka hexlength = sizeof(struct nvm_identify_namespace); 290 1.1 nonaka else 291 1.1 nonaka hexlength = offsetof(struct nvm_identify_namespace, 292 1.1 nonaka _reserved2); 293 1.1 nonaka print_hex(&nsdata, hexlength); 294 1.1 nonaka exit(0); 295 1.1 nonaka } 296 1.1 nonaka 297 1.1 nonaka if (verboseflag == 1) { 298 1.1 nonaka fprintf(stderr, "-v not currently supported without -x\n"); 299 1.1 nonaka identify_usage(); 300 1.1 nonaka } 301 1.1 nonaka 302 1.1 nonaka print_namespace(&nsdata); 303 1.1 nonaka exit(0); 304 1.1 nonaka } 305 1.1 nonaka 306 1.1 nonaka void 307 1.1 nonaka identify(int argc, char *argv[]) 308 1.1 nonaka { 309 1.1 nonaka char *target; 310 1.1 nonaka 311 1.1 nonaka if (argc < 2) 312 1.1 nonaka identify_usage(); 313 1.1 nonaka 314 1.1 nonaka while (getopt(argc, argv, "vx") != -1) ; 315 1.1 nonaka 316 1.1 nonaka /* Check that a controller or namespace was specified. */ 317 1.1 nonaka if (optind >= argc) 318 1.1 nonaka identify_usage(); 319 1.1 nonaka 320 1.1 nonaka target = argv[optind]; 321 1.1 nonaka 322 1.1 nonaka optreset = 1; 323 1.1 nonaka optind = 1; 324 1.1 nonaka 325 1.1 nonaka /* 326 1.1 nonaka * If device node contains "ns", we consider it a namespace, 327 1.1 nonaka * otherwise, consider it a controller. 328 1.1 nonaka */ 329 1.1 nonaka if (strstr(target, NVME_NS_PREFIX) == NULL) 330 1.1 nonaka identify_ctrlr(argc, argv); 331 1.1 nonaka else 332 1.1 nonaka identify_ns(argc, argv); 333 1.1 nonaka } 334