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 48 printf("Controller Capabilities/Features\n"); 49 printf("================================\n"); 50 printf("Vendor ID: %04x\n", cdata->vid); 51 printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 52 nvme_strvis(str, cdata->sn, sizeof(str), NVME_SERIAL_NUMBER_LENGTH); 53 printf("Serial Number: %s\n", str); 54 nvme_strvis(str, cdata->mn, sizeof(str), NVME_MODEL_NUMBER_LENGTH); 55 printf("Model Number: %s\n", str); 56 nvme_strvis(str, cdata->fr, sizeof(str), NVME_FIRMWARE_REVISION_LENGTH); 57 printf("Firmware Version: %s\n", str); 58 printf("Recommended Arb Burst: %d\n", cdata->rab); 59 printf("IEEE OUI Identifier: %02x %02x %02x\n", 60 cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 61 printf("Multi-Interface Cap: %02x\n", cdata->mic); 62 /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 63 printf("Max Data Transfer Size: "); 64 if (cdata->mdts == 0) 65 printf("Unlimited\n"); 66 else 67 printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); 68 printf("\n"); 69 70 printf("Admin Command Set Attributes\n"); 71 printf("============================\n"); 72 printf("Security Send/Receive: %s\n", 73 cdata->oacs.security ? "Supported" : "Not Supported"); 74 printf("Format NVM: %s\n", 75 cdata->oacs.format ? "Supported" : "Not Supported"); 76 printf("Firmware Activate/Download: %s\n", 77 cdata->oacs.firmware ? "Supported" : "Not Supported"); 78 printf("Abort Command Limit: %d\n", cdata->acl+1); 79 printf("Async Event Request Limit: %d\n", cdata->aerl+1); 80 printf("Number of Firmware Slots: "); 81 if (cdata->oacs.firmware != 0) 82 printf("%d\n", cdata->frmw.num_slots); 83 else 84 printf("N/A\n"); 85 printf("Firmware Slot 1 Read-Only: "); 86 if (cdata->oacs.firmware != 0) 87 printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); 88 else 89 printf("N/A\n"); 90 printf("Per-Namespace SMART Log: %s\n", 91 cdata->lpa.ns_smart ? "Yes" : "No"); 92 printf("Error Log Page Entries: %d\n", cdata->elpe+1); 93 printf("Number of Power States: %d\n", cdata->npss+1); 94 printf("\n"); 95 96 printf("NVM Command Set Attributes\n"); 97 printf("==========================\n"); 98 printf("Submission Queue Entry Size\n"); 99 printf(" Max: %d\n", 1 << cdata->sqes.max); 100 printf(" Min: %d\n", 1 << cdata->sqes.min); 101 printf("Completion Queue Entry Size\n"); 102 printf(" Max: %d\n", 1 << cdata->cqes.max); 103 printf(" Min: %d\n", 1 << cdata->cqes.min); 104 printf("Number of Namespaces: %d\n", cdata->nn); 105 printf("Compare Command: %s\n", 106 cdata->oncs.compare ? "Supported" : "Not Supported"); 107 printf("Write Uncorrectable Command: %s\n", 108 cdata->oncs.write_unc ? "Supported" : "Not Supported"); 109 printf("Dataset Management Command: %s\n", 110 cdata->oncs.dsm ? "Supported" : "Not Supported"); 111 printf("Volatile Write Cache: %s\n", 112 cdata->vwc.present ? "Present" : "Not Present"); 113 } 114 115 static void 116 print_namespace(struct nvme_namespace_data *nsdata) 117 { 118 uint32_t i; 119 120 printf("Size (in LBAs): %lld (%lldM)\n", 121 (long long)nsdata->nsze, 122 (long long)nsdata->nsze / 1024 / 1024); 123 printf("Capacity (in LBAs): %lld (%lldM)\n", 124 (long long)nsdata->ncap, 125 (long long)nsdata->ncap / 1024 / 1024); 126 printf("Utilization (in LBAs): %lld (%lldM)\n", 127 (long long)nsdata->nuse, 128 (long long)nsdata->nuse / 1024 / 1024); 129 printf("Thin Provisioning: %s\n", 130 nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); 131 printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 132 printf("Current LBA Format: LBA Format #%02d\n", 133 nsdata->flbas.format); 134 for (i = 0; i <= nsdata->nlbaf; i++) 135 printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n", 136 i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms); 137 } 138 139 static void 140 identify_usage(void) 141 { 142 fprintf(stderr, "usage:\n"); 143 fprintf(stderr, IDENTIFY_USAGE); 144 exit(1); 145 } 146 147 static void 148 identify_ctrlr(int argc, char *argv[]) 149 { 150 struct nvme_controller_data cdata; 151 int ch, fd, hexflag = 0, hexlength; 152 int verboseflag = 0; 153 154 while ((ch = getopt(argc, argv, "vx")) != -1) { 155 switch ((char)ch) { 156 case 'v': 157 verboseflag = 1; 158 break; 159 case 'x': 160 hexflag = 1; 161 break; 162 default: 163 identify_usage(); 164 } 165 } 166 167 /* Check that a controller was specified. */ 168 if (optind >= argc) 169 identify_usage(); 170 171 open_dev(argv[optind], &fd, 1, 1); 172 read_controller_data(fd, &cdata); 173 close(fd); 174 175 if (hexflag == 1) { 176 if (verboseflag == 1) 177 hexlength = sizeof(struct nvme_controller_data); 178 else 179 hexlength = offsetof(struct nvme_controller_data, 180 reserved5); 181 print_hex(&cdata, hexlength); 182 exit(0); 183 } 184 185 if (verboseflag == 1) { 186 fprintf(stderr, "-v not currently supported without -x\n"); 187 identify_usage(); 188 } 189 190 print_controller(&cdata); 191 exit(0); 192 } 193 194 static void 195 identify_ns(int argc, char *argv[]) 196 { 197 struct nvme_namespace_data nsdata; 198 char path[64]; 199 int ch, fd, hexflag = 0, hexlength, nsid; 200 int verboseflag = 0; 201 202 while ((ch = getopt(argc, argv, "vx")) != -1) { 203 switch ((char)ch) { 204 case 'v': 205 verboseflag = 1; 206 break; 207 case 'x': 208 hexflag = 1; 209 break; 210 default: 211 identify_usage(); 212 } 213 } 214 215 /* Check that a namespace was specified. */ 216 if (optind >= argc) 217 identify_usage(); 218 219 /* 220 * Check if the specified device node exists before continuing. 221 * This is a cleaner check for cases where the correct controller 222 * is specified, but an invalid namespace on that controller. 223 */ 224 open_dev(argv[optind], &fd, 1, 1); 225 close(fd); 226 227 /* 228 * We send IDENTIFY commands to the controller, not the namespace, 229 * since it is an admin cmd. The namespace ID will be specified in 230 * the IDENTIFY command itself. So parse the namespace's device node 231 * string to get the controller substring and namespace ID. 232 */ 233 parse_ns_str(argv[optind], path, &nsid); 234 open_dev(path, &fd, 1, 1); 235 read_namespace_data(fd, nsid, &nsdata); 236 close(fd); 237 238 if (hexflag == 1) { 239 if (verboseflag == 1) 240 hexlength = sizeof(struct nvme_namespace_data); 241 else 242 hexlength = offsetof(struct nvme_namespace_data, 243 reserved6); 244 print_hex(&nsdata, hexlength); 245 exit(0); 246 } 247 248 if (verboseflag == 1) { 249 fprintf(stderr, "-v not currently supported without -x\n"); 250 identify_usage(); 251 } 252 253 print_namespace(&nsdata); 254 exit(0); 255 } 256 257 void 258 identify(int argc, char *argv[]) 259 { 260 char *target; 261 262 if (argc < 2) 263 identify_usage(); 264 265 while (getopt(argc, argv, "vx") != -1) ; 266 267 /* Check that a controller or namespace was specified. */ 268 if (optind >= argc) 269 identify_usage(); 270 271 target = argv[optind]; 272 273 optreset = 1; 274 optind = 1; 275 276 /* 277 * If device node contains "ns", we consider it a namespace, 278 * otherwise, consider it a controller. 279 */ 280 if (strstr(target, NVME_NS_PREFIX) == NULL) 281 identify_ctrlr(argc, argv); 282 else 283 identify_ns(argc, argv); 284 } 285