16f0823e4SJim Harris /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 31de7b4b8SPedro F. Giffuni * 46f0823e4SJim Harris * Copyright (C) 2012-2013 Intel Corporation 56f0823e4SJim Harris * All rights reserved. 6a7bf63beSAlexander Motin * Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org> 76f0823e4SJim Harris * 86f0823e4SJim Harris * Redistribution and use in source and binary forms, with or without 96f0823e4SJim Harris * modification, are permitted provided that the following conditions 106f0823e4SJim Harris * are met: 116f0823e4SJim Harris * 1. Redistributions of source code must retain the above copyright 126f0823e4SJim Harris * notice, this list of conditions and the following disclaimer. 136f0823e4SJim Harris * 2. Redistributions in binary form must reproduce the above copyright 146f0823e4SJim Harris * notice, this list of conditions and the following disclaimer in the 156f0823e4SJim Harris * documentation and/or other materials provided with the distribution. 166f0823e4SJim Harris * 176f0823e4SJim Harris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 186f0823e4SJim Harris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 196f0823e4SJim Harris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 206f0823e4SJim Harris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 216f0823e4SJim Harris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 226f0823e4SJim Harris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 236f0823e4SJim Harris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 246f0823e4SJim Harris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 256f0823e4SJim Harris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 266f0823e4SJim Harris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 276f0823e4SJim Harris * SUCH DAMAGE. 286f0823e4SJim Harris */ 296f0823e4SJim Harris 306f0823e4SJim Harris #include <sys/cdefs.h> 316f0823e4SJim Harris __FBSDID("$FreeBSD$"); 326f0823e4SJim Harris 336f0823e4SJim Harris #include <sys/param.h> 346f0823e4SJim Harris 356f0823e4SJim Harris #include <ctype.h> 36821ef73cSJim Harris #include <err.h> 376f0823e4SJim Harris #include <fcntl.h> 38f634b4c1SWarner Losh #include <stdbool.h> 396f0823e4SJim Harris #include <stddef.h> 406f0823e4SJim Harris #include <stdio.h> 416f0823e4SJim Harris #include <stdlib.h> 426f0823e4SJim Harris #include <string.h> 436f0823e4SJim Harris #include <unistd.h> 446f0823e4SJim Harris 456f0823e4SJim Harris #include "nvmecontrol.h" 46e505b7ecSWarner Losh #include "nvmecontrol_ext.h" 476f0823e4SJim Harris 48a7bf63beSAlexander Motin #define NONE 0xfffffffeu 49a7bf63beSAlexander Motin 50f634b4c1SWarner Losh static struct options { 51f634b4c1SWarner Losh bool hex; 52f634b4c1SWarner Losh bool verbose; 53f634b4c1SWarner Losh const char *dev; 543b3dd3f7SAlexander Motin uint32_t nsid; 55f634b4c1SWarner Losh } opt = { 56f634b4c1SWarner Losh .hex = false, 57f634b4c1SWarner Losh .verbose = false, 58f634b4c1SWarner Losh .dev = NULL, 59a7bf63beSAlexander Motin .nsid = NONE, 60f634b4c1SWarner Losh }; 61a13a291aSWarner Losh 623b3dd3f7SAlexander Motin void 636f0823e4SJim Harris print_namespace(struct nvme_namespace_data *nsdata) 646f0823e4SJim Harris { 654035e778SAlexander Motin char cbuf[UINT128_DIG + 1]; 666f0823e4SJim Harris uint32_t i; 673fa5467aSAlexander Motin uint32_t lbaf, lbads, ms, rp; 683fa5467aSAlexander Motin uint8_t thin_prov, ptype; 691aed4995SAlexander Motin uint8_t flbas_fmt, t; 700d787e9bSWojciech Macek 710d787e9bSWojciech Macek thin_prov = (nsdata->nsfeat >> NVME_NS_DATA_NSFEAT_THIN_PROV_SHIFT) & 720d787e9bSWojciech Macek NVME_NS_DATA_NSFEAT_THIN_PROV_MASK; 730d787e9bSWojciech Macek 740d787e9bSWojciech Macek flbas_fmt = (nsdata->flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) & 750d787e9bSWojciech Macek NVME_NS_DATA_FLBAS_FORMAT_MASK; 766f0823e4SJim Harris 774035e778SAlexander Motin printf("Size: %lld blocks\n", 784035e778SAlexander Motin (long long)nsdata->nsze); 794035e778SAlexander Motin printf("Capacity: %lld blocks\n", 804035e778SAlexander Motin (long long)nsdata->ncap); 814035e778SAlexander Motin printf("Utilization: %lld blocks\n", 824035e778SAlexander Motin (long long)nsdata->nuse); 836f0823e4SJim Harris printf("Thin Provisioning: %s\n", 840d787e9bSWojciech Macek thin_prov ? "Supported" : "Not Supported"); 856f0823e4SJim Harris printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 860d787e9bSWojciech Macek printf("Current LBA Format: LBA Format #%02d\n", flbas_fmt); 873fa5467aSAlexander Motin printf("Data Protection Caps: %s%s%s%s%s%s\n", 883fa5467aSAlexander Motin (nsdata->dpc == 0) ? "Not Supported" : "", 893fa5467aSAlexander Motin ((nsdata->dpc >> NVME_NS_DATA_DPC_MD_END_SHIFT) & 903fa5467aSAlexander Motin NVME_NS_DATA_DPC_MD_END_MASK) ? "Last Bytes, " : "", 913fa5467aSAlexander Motin ((nsdata->dpc >> NVME_NS_DATA_DPC_MD_START_SHIFT) & 923fa5467aSAlexander Motin NVME_NS_DATA_DPC_MD_START_MASK) ? "First Bytes, " : "", 933fa5467aSAlexander Motin ((nsdata->dpc >> NVME_NS_DATA_DPC_PIT3_SHIFT) & 943fa5467aSAlexander Motin NVME_NS_DATA_DPC_PIT3_MASK) ? "Type 3, " : "", 953fa5467aSAlexander Motin ((nsdata->dpc >> NVME_NS_DATA_DPC_PIT2_SHIFT) & 963fa5467aSAlexander Motin NVME_NS_DATA_DPC_PIT2_MASK) ? "Type 2, " : "", 973fa5467aSAlexander Motin ((nsdata->dpc >> NVME_NS_DATA_DPC_PIT2_MASK) & 983fa5467aSAlexander Motin NVME_NS_DATA_DPC_PIT1_MASK) ? "Type 1" : ""); 993fa5467aSAlexander Motin printf("Data Protection Settings: "); 1003fa5467aSAlexander Motin ptype = (nsdata->dps >> NVME_NS_DATA_DPS_PIT_SHIFT) & 1013fa5467aSAlexander Motin NVME_NS_DATA_DPS_PIT_MASK; 1023fa5467aSAlexander Motin if (ptype) { 1033fa5467aSAlexander Motin printf("Type %d, %s Bytes\n", ptype, 1043fa5467aSAlexander Motin ((nsdata->dps >> NVME_NS_DATA_DPS_MD_START_SHIFT) & 1053fa5467aSAlexander Motin NVME_NS_DATA_DPS_MD_START_MASK) ? "First" : "Last"); 1063fa5467aSAlexander Motin } else { 1073fa5467aSAlexander Motin printf("Not Enabled\n"); 1083fa5467aSAlexander Motin } 1093fa5467aSAlexander Motin printf("Multi-Path I/O Capabilities: %s%s\n", 1103fa5467aSAlexander Motin (nsdata->nmic == 0) ? "Not Supported" : "", 1113fa5467aSAlexander Motin ((nsdata->nmic >> NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) & 1123fa5467aSAlexander Motin NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK) ? "May be shared" : ""); 1133fa5467aSAlexander Motin printf("Reservation Capabilities: %s%s%s%s%s%s%s%s%s\n", 1143fa5467aSAlexander Motin (nsdata->rescap == 0) ? "Not Supported" : "", 1153fa5467aSAlexander Motin ((nsdata->rescap >> NVME_NS_DATA_RESCAP_IEKEY13_SHIFT) & 1163fa5467aSAlexander Motin NVME_NS_DATA_RESCAP_IEKEY13_MASK) ? "IEKEY13, " : "", 1173fa5467aSAlexander Motin ((nsdata->rescap >> NVME_NS_DATA_RESCAP_EX_AC_AR_SHIFT) & 1183fa5467aSAlexander Motin NVME_NS_DATA_RESCAP_EX_AC_AR_MASK) ? "EX_AC_AR, " : "", 1193fa5467aSAlexander Motin ((nsdata->rescap >> NVME_NS_DATA_RESCAP_WR_EX_AR_SHIFT) & 1203fa5467aSAlexander Motin NVME_NS_DATA_RESCAP_WR_EX_AR_MASK) ? "WR_EX_AR, " : "", 1213fa5467aSAlexander Motin ((nsdata->rescap >> NVME_NS_DATA_RESCAP_EX_AC_RO_SHIFT) & 1223fa5467aSAlexander Motin NVME_NS_DATA_RESCAP_EX_AC_RO_MASK) ? "EX_AC_RO, " : "", 1233fa5467aSAlexander Motin ((nsdata->rescap >> NVME_NS_DATA_RESCAP_WR_EX_RO_SHIFT) & 1243fa5467aSAlexander Motin NVME_NS_DATA_RESCAP_WR_EX_RO_MASK) ? "WR_EX_RO, " : "", 1253fa5467aSAlexander Motin ((nsdata->rescap >> NVME_NS_DATA_RESCAP_EX_AC_SHIFT) & 1263fa5467aSAlexander Motin NVME_NS_DATA_RESCAP_EX_AC_MASK) ? "EX_AC, " : "", 1273fa5467aSAlexander Motin ((nsdata->rescap >> NVME_NS_DATA_RESCAP_WR_EX_SHIFT) & 1283fa5467aSAlexander Motin NVME_NS_DATA_RESCAP_WR_EX_MASK) ? "WR_EX, " : "", 1293fa5467aSAlexander Motin ((nsdata->rescap >> NVME_NS_DATA_RESCAP_PTPL_SHIFT) & 1303fa5467aSAlexander Motin NVME_NS_DATA_RESCAP_PTPL_MASK) ? "PTPL" : ""); 1313fa5467aSAlexander Motin printf("Format Progress Indicator: "); 1323fa5467aSAlexander Motin if ((nsdata->fpi >> NVME_NS_DATA_FPI_SUPP_SHIFT) & 1333fa5467aSAlexander Motin NVME_NS_DATA_FPI_SUPP_MASK) { 1343fa5467aSAlexander Motin printf("%u%% remains\n", 1353fa5467aSAlexander Motin (nsdata->fpi >> NVME_NS_DATA_FPI_PERC_SHIFT) & 1363fa5467aSAlexander Motin NVME_NS_DATA_FPI_PERC_MASK); 1373fa5467aSAlexander Motin } else 1383fa5467aSAlexander Motin printf("Not Supported\n"); 1391aed4995SAlexander Motin t = (nsdata->dlfeat >> NVME_NS_DATA_DLFEAT_READ_SHIFT) & 1401aed4995SAlexander Motin NVME_NS_DATA_DLFEAT_READ_MASK; 1411aed4995SAlexander Motin printf("Deallocate Logical Block: Read %s%s%s\n", 1421aed4995SAlexander Motin (t == NVME_NS_DATA_DLFEAT_READ_NR) ? "Not Reported" : 1431aed4995SAlexander Motin (t == NVME_NS_DATA_DLFEAT_READ_00) ? "00h" : 1441aed4995SAlexander Motin (t == NVME_NS_DATA_DLFEAT_READ_FF) ? "FFh" : "Unknown", 1451aed4995SAlexander Motin (nsdata->dlfeat >> NVME_NS_DATA_DLFEAT_DWZ_SHIFT) & 1461aed4995SAlexander Motin NVME_NS_DATA_DLFEAT_DWZ_MASK ? ", Write Zero" : "", 1471aed4995SAlexander Motin (nsdata->dlfeat >> NVME_NS_DATA_DLFEAT_GCRC_SHIFT) & 1481aed4995SAlexander Motin NVME_NS_DATA_DLFEAT_GCRC_MASK ? ", Guard CRC" : ""); 1494035e778SAlexander Motin printf("Optimal I/O Boundary: %u blocks\n", nsdata->noiob); 1504035e778SAlexander Motin printf("NVM Capacity: %s bytes\n", 1514035e778SAlexander Motin uint128_to_str(to128(nsdata->nvmcap), cbuf, sizeof(cbuf))); 1524035e778SAlexander Motin if ((nsdata->nsfeat >> NVME_NS_DATA_NSFEAT_NPVALID_SHIFT) & 1534035e778SAlexander Motin NVME_NS_DATA_NSFEAT_NPVALID_MASK) { 1544035e778SAlexander Motin printf("Preferred Write Granularity: %u blocks", 1554035e778SAlexander Motin nsdata->npwg + 1); 1564035e778SAlexander Motin printf("Preferred Write Alignment: %u blocks", 1574035e778SAlexander Motin nsdata->npwa + 1); 1584035e778SAlexander Motin printf("Preferred Deallocate Granul: %u blocks", 1594035e778SAlexander Motin nsdata->npdg + 1); 1604035e778SAlexander Motin printf("Preferred Deallocate Align: %u blocks", 1614035e778SAlexander Motin nsdata->npda + 1); 1624035e778SAlexander Motin printf("Optimal Write Size: %u blocks", 1634035e778SAlexander Motin nsdata->nows + 1); 1644035e778SAlexander Motin } 1653fa5467aSAlexander Motin printf("Globally Unique Identifier: "); 1663fa5467aSAlexander Motin for (i = 0; i < sizeof(nsdata->nguid); i++) 1673fa5467aSAlexander Motin printf("%02x", nsdata->nguid[i]); 1683fa5467aSAlexander Motin printf("\n"); 1693fa5467aSAlexander Motin printf("IEEE EUI64: "); 1703fa5467aSAlexander Motin for (i = 0; i < sizeof(nsdata->eui64); i++) 1713fa5467aSAlexander Motin printf("%02x", nsdata->eui64[i]); 1723fa5467aSAlexander Motin printf("\n"); 1730d787e9bSWojciech Macek for (i = 0; i <= nsdata->nlbaf; i++) { 1740d787e9bSWojciech Macek lbaf = nsdata->lbaf[i]; 1750d787e9bSWojciech Macek lbads = (lbaf >> NVME_NS_DATA_LBAF_LBADS_SHIFT) & 1760d787e9bSWojciech Macek NVME_NS_DATA_LBAF_LBADS_MASK; 1770d787e9bSWojciech Macek ms = (lbaf >> NVME_NS_DATA_LBAF_MS_SHIFT) & 1780d787e9bSWojciech Macek NVME_NS_DATA_LBAF_MS_MASK; 1793fa5467aSAlexander Motin rp = (lbaf >> NVME_NS_DATA_LBAF_RP_SHIFT) & 1803fa5467aSAlexander Motin NVME_NS_DATA_LBAF_RP_MASK; 1813fa5467aSAlexander Motin printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d" 1823fa5467aSAlexander Motin " Performance: %s\n", 1833fa5467aSAlexander Motin i, 1 << lbads, ms, (rp == 0) ? "Best" : 1843fa5467aSAlexander Motin (rp == 1) ? "Better" : (rp == 2) ? "Good" : "Degraded"); 1850d787e9bSWojciech Macek } 1866f0823e4SJim Harris } 1876f0823e4SJim Harris 1886f0823e4SJim Harris static void 189a7bf63beSAlexander Motin identify_ctrlr(int fd) 1906f0823e4SJim Harris { 1916f0823e4SJim Harris struct nvme_controller_data cdata; 192a7bf63beSAlexander Motin int hexlength; 1936f0823e4SJim Harris 1946f0823e4SJim Harris read_controller_data(fd, &cdata); 1956f0823e4SJim Harris close(fd); 1966f0823e4SJim Harris 197f634b4c1SWarner Losh if (opt.hex) { 198f634b4c1SWarner Losh if (opt.verbose) 1996f0823e4SJim Harris hexlength = sizeof(struct nvme_controller_data); 2006f0823e4SJim Harris else 2016f0823e4SJim Harris hexlength = offsetof(struct nvme_controller_data, 2023fa5467aSAlexander Motin reserved8); 203e83c9e35SJim Harris print_hex(&cdata, hexlength); 204821ef73cSJim Harris exit(0); 2056f0823e4SJim Harris } 2066f0823e4SJim Harris 207e505b7ecSWarner Losh nvme_print_controller(&cdata); 208821ef73cSJim Harris exit(0); 2096f0823e4SJim Harris } 2106f0823e4SJim Harris 2116f0823e4SJim Harris static void 212a7bf63beSAlexander Motin identify_ns(int fd, uint32_t nsid) 2136f0823e4SJim Harris { 2146f0823e4SJim Harris struct nvme_namespace_data nsdata; 215a7bf63beSAlexander Motin int hexlength; 2166f0823e4SJim Harris 2176f0823e4SJim Harris read_namespace_data(fd, nsid, &nsdata); 2186f0823e4SJim Harris close(fd); 2196f0823e4SJim Harris 220f634b4c1SWarner Losh if (opt.hex) { 221f634b4c1SWarner Losh if (opt.verbose) 2226f0823e4SJim Harris hexlength = sizeof(struct nvme_namespace_data); 2236f0823e4SJim Harris else 2246f0823e4SJim Harris hexlength = offsetof(struct nvme_namespace_data, 2256f0823e4SJim Harris reserved6); 226e83c9e35SJim Harris print_hex(&nsdata, hexlength); 227821ef73cSJim Harris exit(0); 2286f0823e4SJim Harris } 2296f0823e4SJim Harris 2306f0823e4SJim Harris print_namespace(&nsdata); 231821ef73cSJim Harris exit(0); 2326f0823e4SJim Harris } 2336f0823e4SJim Harris 234a13a291aSWarner Losh static void 235f634b4c1SWarner Losh identify(const struct cmd *f, int argc, char *argv[]) 2366f0823e4SJim Harris { 237a7bf63beSAlexander Motin char *path; 238a7bf63beSAlexander Motin int fd; 239a7bf63beSAlexander Motin uint32_t nsid; 240a7bf63beSAlexander Motin 241f634b4c1SWarner Losh arg_parse(argc, argv, f); 2426f0823e4SJim Harris 243a7bf63beSAlexander Motin open_dev(opt.dev, &fd, 1, 1); 244a7bf63beSAlexander Motin get_nsid(fd, &path, &nsid); 245a7bf63beSAlexander Motin if (nsid != 0) { 2466f0823e4SJim Harris /* 247a7bf63beSAlexander Motin * We got namespace device, but we need to send IDENTIFY 248a7bf63beSAlexander Motin * commands to the controller, not the namespace, since it 249a7bf63beSAlexander Motin * is an admin cmd. The namespace ID will be specified in 250a7bf63beSAlexander Motin * the IDENTIFY command itself. 2516f0823e4SJim Harris */ 252a7bf63beSAlexander Motin close(fd); 253a7bf63beSAlexander Motin open_dev(path, &fd, 1, 1); 254a7bf63beSAlexander Motin } 255a7bf63beSAlexander Motin free(path); 256a7bf63beSAlexander Motin if (opt.nsid != NONE) 257a7bf63beSAlexander Motin nsid = opt.nsid; 258a7bf63beSAlexander Motin 259a7bf63beSAlexander Motin if (nsid == 0) 260a7bf63beSAlexander Motin identify_ctrlr(fd); 2616f0823e4SJim Harris else 262a7bf63beSAlexander Motin identify_ns(fd, nsid); 2636f0823e4SJim Harris } 264a13a291aSWarner Losh 265f634b4c1SWarner Losh static const struct opts identify_opts[] = { 266f634b4c1SWarner Losh #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } 267f634b4c1SWarner Losh OPT("hex", 'x', arg_none, opt, hex, 268f634b4c1SWarner Losh "Print identiy information in hex"), 269f634b4c1SWarner Losh OPT("verbose", 'v', arg_none, opt, verbose, 270f634b4c1SWarner Losh "More verbosity: print entire identify table"), 2713b3dd3f7SAlexander Motin OPT("nsid", 'n', arg_uint32, opt, nsid, 2723b3dd3f7SAlexander Motin "Namespace ID to use if not in device name"), 273f634b4c1SWarner Losh { NULL, 0, arg_none, NULL, NULL } 274f634b4c1SWarner Losh }; 275f634b4c1SWarner Losh #undef OPT 276f634b4c1SWarner Losh 277f634b4c1SWarner Losh static const struct args identify_args[] = { 278f634b4c1SWarner Losh { arg_string, &opt.dev, "controller-id|namespace-id" }, 279f634b4c1SWarner Losh { arg_none, NULL, NULL }, 280f634b4c1SWarner Losh }; 281f634b4c1SWarner Losh 282f634b4c1SWarner Losh static struct cmd identify_cmd = { 283f634b4c1SWarner Losh .name = "identify", 284f634b4c1SWarner Losh .fn = identify, 2853b3dd3f7SAlexander Motin .descr = "Print summary of the IDENTIFY information", 286f634b4c1SWarner Losh .ctx_size = sizeof(opt), 287f634b4c1SWarner Losh .opts = identify_opts, 288f634b4c1SWarner Losh .args = identify_args, 289f634b4c1SWarner Losh }; 290f634b4c1SWarner Losh 291f634b4c1SWarner Losh CMD_COMMAND(identify_cmd); 292