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