1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 34 #include <ctype.h> 35 #include <err.h> 36 #include <fcntl.h> 37 #include <stddef.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include "nvmecontrol.h" 44 #include "nvmecontrol_ext.h" 45 46 static void 47 print_namespace(struct nvme_namespace_data *nsdata) 48 { 49 uint32_t i; 50 uint32_t lbaf, lbads, ms, rp; 51 uint8_t thin_prov, ptype; 52 uint8_t flbas_fmt; 53 54 thin_prov = (nsdata->nsfeat >> NVME_NS_DATA_NSFEAT_THIN_PROV_SHIFT) & 55 NVME_NS_DATA_NSFEAT_THIN_PROV_MASK; 56 57 flbas_fmt = (nsdata->flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) & 58 NVME_NS_DATA_FLBAS_FORMAT_MASK; 59 60 printf("Size (in LBAs): %lld (%lldM)\n", 61 (long long)nsdata->nsze, 62 (long long)nsdata->nsze / 1024 / 1024); 63 printf("Capacity (in LBAs): %lld (%lldM)\n", 64 (long long)nsdata->ncap, 65 (long long)nsdata->ncap / 1024 / 1024); 66 printf("Utilization (in LBAs): %lld (%lldM)\n", 67 (long long)nsdata->nuse, 68 (long long)nsdata->nuse / 1024 / 1024); 69 printf("Thin Provisioning: %s\n", 70 thin_prov ? "Supported" : "Not Supported"); 71 printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 72 printf("Current LBA Format: LBA Format #%02d\n", flbas_fmt); 73 printf("Data Protection Caps: %s%s%s%s%s%s\n", 74 (nsdata->dpc == 0) ? "Not Supported" : "", 75 ((nsdata->dpc >> NVME_NS_DATA_DPC_MD_END_SHIFT) & 76 NVME_NS_DATA_DPC_MD_END_MASK) ? "Last Bytes, " : "", 77 ((nsdata->dpc >> NVME_NS_DATA_DPC_MD_START_SHIFT) & 78 NVME_NS_DATA_DPC_MD_START_MASK) ? "First Bytes, " : "", 79 ((nsdata->dpc >> NVME_NS_DATA_DPC_PIT3_SHIFT) & 80 NVME_NS_DATA_DPC_PIT3_MASK) ? "Type 3, " : "", 81 ((nsdata->dpc >> NVME_NS_DATA_DPC_PIT2_SHIFT) & 82 NVME_NS_DATA_DPC_PIT2_MASK) ? "Type 2, " : "", 83 ((nsdata->dpc >> NVME_NS_DATA_DPC_PIT2_MASK) & 84 NVME_NS_DATA_DPC_PIT1_MASK) ? "Type 1" : ""); 85 printf("Data Protection Settings: "); 86 ptype = (nsdata->dps >> NVME_NS_DATA_DPS_PIT_SHIFT) & 87 NVME_NS_DATA_DPS_PIT_MASK; 88 if (ptype) { 89 printf("Type %d, %s Bytes\n", ptype, 90 ((nsdata->dps >> NVME_NS_DATA_DPS_MD_START_SHIFT) & 91 NVME_NS_DATA_DPS_MD_START_MASK) ? "First" : "Last"); 92 } else { 93 printf("Not Enabled\n"); 94 } 95 printf("Multi-Path I/O Capabilities: %s%s\n", 96 (nsdata->nmic == 0) ? "Not Supported" : "", 97 ((nsdata->nmic >> NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) & 98 NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK) ? "May be shared" : ""); 99 printf("Reservation Capabilities: %s%s%s%s%s%s%s%s%s\n", 100 (nsdata->rescap == 0) ? "Not Supported" : "", 101 ((nsdata->rescap >> NVME_NS_DATA_RESCAP_IEKEY13_SHIFT) & 102 NVME_NS_DATA_RESCAP_IEKEY13_MASK) ? "IEKEY13, " : "", 103 ((nsdata->rescap >> NVME_NS_DATA_RESCAP_EX_AC_AR_SHIFT) & 104 NVME_NS_DATA_RESCAP_EX_AC_AR_MASK) ? "EX_AC_AR, " : "", 105 ((nsdata->rescap >> NVME_NS_DATA_RESCAP_WR_EX_AR_SHIFT) & 106 NVME_NS_DATA_RESCAP_WR_EX_AR_MASK) ? "WR_EX_AR, " : "", 107 ((nsdata->rescap >> NVME_NS_DATA_RESCAP_EX_AC_RO_SHIFT) & 108 NVME_NS_DATA_RESCAP_EX_AC_RO_MASK) ? "EX_AC_RO, " : "", 109 ((nsdata->rescap >> NVME_NS_DATA_RESCAP_WR_EX_RO_SHIFT) & 110 NVME_NS_DATA_RESCAP_WR_EX_RO_MASK) ? "WR_EX_RO, " : "", 111 ((nsdata->rescap >> NVME_NS_DATA_RESCAP_EX_AC_SHIFT) & 112 NVME_NS_DATA_RESCAP_EX_AC_MASK) ? "EX_AC, " : "", 113 ((nsdata->rescap >> NVME_NS_DATA_RESCAP_WR_EX_SHIFT) & 114 NVME_NS_DATA_RESCAP_WR_EX_MASK) ? "WR_EX, " : "", 115 ((nsdata->rescap >> NVME_NS_DATA_RESCAP_PTPL_SHIFT) & 116 NVME_NS_DATA_RESCAP_PTPL_MASK) ? "PTPL" : ""); 117 printf("Format Progress Indicator: "); 118 if ((nsdata->fpi >> NVME_NS_DATA_FPI_SUPP_SHIFT) & 119 NVME_NS_DATA_FPI_SUPP_MASK) { 120 printf("%u%% remains\n", 121 (nsdata->fpi >> NVME_NS_DATA_FPI_PERC_SHIFT) & 122 NVME_NS_DATA_FPI_PERC_MASK); 123 } else 124 printf("Not Supported\n"); 125 printf("Optimal I/O Boundary (LBAs): %u\n", nsdata->noiob); 126 printf("Globally Unique Identifier: "); 127 for (i = 0; i < sizeof(nsdata->nguid); i++) 128 printf("%02x", nsdata->nguid[i]); 129 printf("\n"); 130 printf("IEEE EUI64: "); 131 for (i = 0; i < sizeof(nsdata->eui64); i++) 132 printf("%02x", nsdata->eui64[i]); 133 printf("\n"); 134 for (i = 0; i <= nsdata->nlbaf; i++) { 135 lbaf = nsdata->lbaf[i]; 136 lbads = (lbaf >> NVME_NS_DATA_LBAF_LBADS_SHIFT) & 137 NVME_NS_DATA_LBAF_LBADS_MASK; 138 ms = (lbaf >> NVME_NS_DATA_LBAF_MS_SHIFT) & 139 NVME_NS_DATA_LBAF_MS_MASK; 140 rp = (lbaf >> NVME_NS_DATA_LBAF_RP_SHIFT) & 141 NVME_NS_DATA_LBAF_RP_MASK; 142 printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d" 143 " Performance: %s\n", 144 i, 1 << lbads, ms, (rp == 0) ? "Best" : 145 (rp == 1) ? "Better" : (rp == 2) ? "Good" : "Degraded"); 146 } 147 } 148 149 static void 150 identify_usage(void) 151 { 152 fprintf(stderr, "usage:\n"); 153 fprintf(stderr, IDENTIFY_USAGE); 154 exit(1); 155 } 156 157 static void 158 identify_ctrlr(int argc, char *argv[]) 159 { 160 struct nvme_controller_data cdata; 161 int ch, fd, hexflag = 0, hexlength; 162 int verboseflag = 0; 163 164 while ((ch = getopt(argc, argv, "vx")) != -1) { 165 switch ((char)ch) { 166 case 'v': 167 verboseflag = 1; 168 break; 169 case 'x': 170 hexflag = 1; 171 break; 172 default: 173 identify_usage(); 174 } 175 } 176 177 /* Check that a controller was specified. */ 178 if (optind >= argc) 179 identify_usage(); 180 181 open_dev(argv[optind], &fd, 1, 1); 182 read_controller_data(fd, &cdata); 183 close(fd); 184 185 if (hexflag == 1) { 186 if (verboseflag == 1) 187 hexlength = sizeof(struct nvme_controller_data); 188 else 189 hexlength = offsetof(struct nvme_controller_data, 190 reserved8); 191 print_hex(&cdata, hexlength); 192 exit(0); 193 } 194 195 if (verboseflag == 1) { 196 fprintf(stderr, "-v not currently supported without -x\n"); 197 identify_usage(); 198 } 199 200 nvme_print_controller(&cdata); 201 exit(0); 202 } 203 204 static void 205 identify_ns(int argc, char *argv[]) 206 { 207 struct nvme_namespace_data nsdata; 208 char path[64]; 209 int ch, fd, hexflag = 0, hexlength; 210 int verboseflag = 0; 211 uint32_t nsid; 212 213 while ((ch = getopt(argc, argv, "vx")) != -1) { 214 switch ((char)ch) { 215 case 'v': 216 verboseflag = 1; 217 break; 218 case 'x': 219 hexflag = 1; 220 break; 221 default: 222 identify_usage(); 223 } 224 } 225 226 /* Check that a namespace was specified. */ 227 if (optind >= argc) 228 identify_usage(); 229 230 /* 231 * Check if the specified device node exists before continuing. 232 * This is a cleaner check for cases where the correct controller 233 * is specified, but an invalid namespace on that controller. 234 */ 235 open_dev(argv[optind], &fd, 1, 1); 236 close(fd); 237 238 /* 239 * We send IDENTIFY commands to the controller, not the namespace, 240 * since it is an admin cmd. The namespace ID will be specified in 241 * the IDENTIFY command itself. So parse the namespace's device node 242 * string to get the controller substring and namespace ID. 243 */ 244 parse_ns_str(argv[optind], path, &nsid); 245 open_dev(path, &fd, 1, 1); 246 read_namespace_data(fd, nsid, &nsdata); 247 close(fd); 248 249 if (hexflag == 1) { 250 if (verboseflag == 1) 251 hexlength = sizeof(struct nvme_namespace_data); 252 else 253 hexlength = offsetof(struct nvme_namespace_data, 254 reserved6); 255 print_hex(&nsdata, hexlength); 256 exit(0); 257 } 258 259 if (verboseflag == 1) { 260 fprintf(stderr, "-v not currently supported without -x\n"); 261 identify_usage(); 262 } 263 264 print_namespace(&nsdata); 265 exit(0); 266 } 267 268 void 269 identify(int argc, char *argv[]) 270 { 271 char *target; 272 273 if (argc < 2) 274 identify_usage(); 275 276 while (getopt(argc, argv, "vx") != -1) ; 277 278 /* Check that a controller or namespace was specified. */ 279 if (optind >= argc) 280 identify_usage(); 281 282 target = argv[optind]; 283 284 optreset = 1; 285 optind = 1; 286 287 /* 288 * If device node contains "ns", we consider it a namespace, 289 * otherwise, consider it a controller. 290 */ 291 if (strstr(target, NVME_NS_PREFIX) == NULL) 292 identify_ctrlr(argc, argv); 293 else 294 identify_ns(argc, argv); 295 } 296