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