16f0823e4SJim Harris /*- 26f0823e4SJim Harris * Copyright (C) 2012-2013 Intel Corporation 36f0823e4SJim Harris * All rights reserved. 46f0823e4SJim Harris * 56f0823e4SJim Harris * Redistribution and use in source and binary forms, with or without 66f0823e4SJim Harris * modification, are permitted provided that the following conditions 76f0823e4SJim Harris * are met: 86f0823e4SJim Harris * 1. Redistributions of source code must retain the above copyright 96f0823e4SJim Harris * notice, this list of conditions and the following disclaimer. 106f0823e4SJim Harris * 2. Redistributions in binary form must reproduce the above copyright 116f0823e4SJim Harris * notice, this list of conditions and the following disclaimer in the 126f0823e4SJim Harris * documentation and/or other materials provided with the distribution. 136f0823e4SJim Harris * 146f0823e4SJim Harris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 156f0823e4SJim Harris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 166f0823e4SJim Harris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 176f0823e4SJim Harris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 186f0823e4SJim Harris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 196f0823e4SJim Harris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 206f0823e4SJim Harris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 216f0823e4SJim Harris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 226f0823e4SJim Harris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 236f0823e4SJim Harris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 246f0823e4SJim Harris * SUCH DAMAGE. 256f0823e4SJim Harris */ 266f0823e4SJim Harris 276f0823e4SJim Harris #include <sys/cdefs.h> 286f0823e4SJim Harris __FBSDID("$FreeBSD$"); 296f0823e4SJim Harris 306f0823e4SJim Harris #include <sys/param.h> 316f0823e4SJim Harris 326f0823e4SJim Harris #include <ctype.h> 336f0823e4SJim Harris #include <errno.h> 346f0823e4SJim Harris #include <fcntl.h> 356f0823e4SJim Harris #include <stddef.h> 366f0823e4SJim Harris #include <stdio.h> 376f0823e4SJim Harris #include <stdlib.h> 386f0823e4SJim Harris #include <string.h> 396f0823e4SJim Harris #include <sysexits.h> 406f0823e4SJim Harris #include <unistd.h> 416f0823e4SJim Harris 426f0823e4SJim Harris #include "nvmecontrol.h" 436f0823e4SJim Harris 446f0823e4SJim Harris static void 456f0823e4SJim Harris print_controller_hex(struct nvme_controller_data *cdata, uint32_t length) 466f0823e4SJim Harris { 476f0823e4SJim Harris uint32_t *p; 486f0823e4SJim Harris uint32_t i, j; 496f0823e4SJim Harris 506f0823e4SJim Harris p = (uint32_t *)cdata; 516f0823e4SJim Harris length /= sizeof(uint32_t); 526f0823e4SJim Harris 536f0823e4SJim Harris for (i = 0; i < length; i+=8) { 546f0823e4SJim Harris printf("%03x: ", i*4); 556f0823e4SJim Harris for (j = 0; j < 8; j++) 566f0823e4SJim Harris printf("%08x ", p[i+j]); 576f0823e4SJim Harris printf("\n"); 586f0823e4SJim Harris } 596f0823e4SJim Harris 606f0823e4SJim Harris printf("\n"); 616f0823e4SJim Harris } 626f0823e4SJim Harris 636f0823e4SJim Harris static void 646f0823e4SJim Harris print_controller(struct nvme_controller_data *cdata) 656f0823e4SJim Harris { 666f0823e4SJim Harris printf("Controller Capabilities/Features\n"); 676f0823e4SJim Harris printf("================================\n"); 686f0823e4SJim Harris printf("Vendor ID: %04x\n", cdata->vid); 696f0823e4SJim Harris printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 706f0823e4SJim Harris printf("Serial Number: %s\n", cdata->sn); 716f0823e4SJim Harris printf("Model Number: %s\n", cdata->mn); 726f0823e4SJim Harris printf("Firmware Version: %s\n", cdata->fr); 736f0823e4SJim Harris printf("Recommended Arb Burst: %d\n", cdata->rab); 746f0823e4SJim Harris printf("IEEE OUI Identifier: %02x %02x %02x\n", 756f0823e4SJim Harris cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 766f0823e4SJim Harris printf("Multi-Interface Cap: %02x\n", cdata->mic); 776f0823e4SJim Harris /* TODO: Use CAP.MPSMIN to determine true memory page size. */ 786f0823e4SJim Harris printf("Max Data Transfer Size: "); 796f0823e4SJim Harris if (cdata->mdts == 0) 806f0823e4SJim Harris printf("Unlimited\n"); 816f0823e4SJim Harris else 826f0823e4SJim Harris printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); 836f0823e4SJim Harris printf("\n"); 846f0823e4SJim Harris 856f0823e4SJim Harris printf("Admin Command Set Attributes\n"); 866f0823e4SJim Harris printf("============================\n"); 876f0823e4SJim Harris printf("Security Send/Receive: %s\n", 886f0823e4SJim Harris cdata->oacs.security ? "Supported" : "Not Supported"); 896f0823e4SJim Harris printf("Format NVM: %s\n", 906f0823e4SJim Harris cdata->oacs.format ? "Supported" : "Not Supported"); 916f0823e4SJim Harris printf("Firmware Activate/Download: %s\n", 926f0823e4SJim Harris cdata->oacs.firmware ? "Supported" : "Not Supported"); 936f0823e4SJim Harris printf("Abort Command Limit: %d\n", cdata->acl+1); 946f0823e4SJim Harris printf("Async Event Request Limit: %d\n", cdata->aerl+1); 956f0823e4SJim Harris printf("Number of Firmware Slots: "); 966f0823e4SJim Harris if (cdata->oacs.firmware != 0) 976f0823e4SJim Harris printf("%d\n", cdata->frmw.num_slots); 986f0823e4SJim Harris else 996f0823e4SJim Harris printf("N/A\n"); 1006f0823e4SJim Harris printf("Firmware Slot 1 Read-Only: "); 1016f0823e4SJim Harris if (cdata->oacs.firmware != 0) 1026f0823e4SJim Harris printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); 1036f0823e4SJim Harris else 1046f0823e4SJim Harris printf("N/A\n"); 1056f0823e4SJim Harris printf("Per-Namespace SMART Log: %s\n", 1066f0823e4SJim Harris cdata->lpa.ns_smart ? "Yes" : "No"); 1076f0823e4SJim Harris printf("Error Log Page Entries: %d\n", cdata->elpe+1); 1086f0823e4SJim Harris printf("Number of Power States: %d\n", cdata->npss+1); 1096f0823e4SJim Harris printf("\n"); 1106f0823e4SJim Harris 1116f0823e4SJim Harris printf("NVM Command Set Attributes\n"); 1126f0823e4SJim Harris printf("==========================\n"); 1136f0823e4SJim Harris printf("Submission Queue Entry Size\n"); 1146f0823e4SJim Harris printf(" Max: %d\n", 1 << cdata->sqes.max); 1156f0823e4SJim Harris printf(" Min: %d\n", 1 << cdata->sqes.min); 1166f0823e4SJim Harris printf("Completion Queue Entry Size\n"); 1176f0823e4SJim Harris printf(" Max: %d\n", 1 << cdata->cqes.max); 1186f0823e4SJim Harris printf(" Min: %d\n", 1 << cdata->cqes.min); 1196f0823e4SJim Harris printf("Number of Namespaces: %d\n", cdata->nn); 1206f0823e4SJim Harris printf("Compare Command: %s\n", 1216f0823e4SJim Harris cdata->oncs.compare ? "Supported" : "Not Supported"); 1226f0823e4SJim Harris printf("Write Uncorrectable Command: %s\n", 1236f0823e4SJim Harris cdata->oncs.write_unc ? "Supported" : "Not Supported"); 1246f0823e4SJim Harris printf("Dataset Management Command: %s\n", 1256f0823e4SJim Harris cdata->oncs.dsm ? "Supported" : "Not Supported"); 1266f0823e4SJim Harris printf("Volatile Write Cache: %s\n", 1276f0823e4SJim Harris cdata->vwc.present ? "Present" : "Not Present"); 1286f0823e4SJim Harris } 1296f0823e4SJim Harris 1306f0823e4SJim Harris static void 1316f0823e4SJim Harris print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length) 1326f0823e4SJim Harris { 1336f0823e4SJim Harris uint32_t *p; 1346f0823e4SJim Harris uint32_t i, j; 1356f0823e4SJim Harris 1366f0823e4SJim Harris p = (uint32_t *)nsdata; 1376f0823e4SJim Harris length /= sizeof(uint32_t); 1386f0823e4SJim Harris 1396f0823e4SJim Harris for (i = 0; i < length; i+=8) { 1406f0823e4SJim Harris printf("%03x: ", i*4); 1416f0823e4SJim Harris for (j = 0; j < 8; j++) 1426f0823e4SJim Harris printf("%08x ", p[i+j]); 1436f0823e4SJim Harris printf("\n"); 1446f0823e4SJim Harris } 1456f0823e4SJim Harris 1466f0823e4SJim Harris printf("\n"); 1476f0823e4SJim Harris } 1486f0823e4SJim Harris 1496f0823e4SJim Harris static void 1506f0823e4SJim Harris print_namespace(struct nvme_namespace_data *nsdata) 1516f0823e4SJim Harris { 1526f0823e4SJim Harris uint32_t i; 1536f0823e4SJim Harris 1546f0823e4SJim Harris printf("Size (in LBAs): %lld (%lldM)\n", 1556f0823e4SJim Harris (long long)nsdata->nsze, 1566f0823e4SJim Harris (long long)nsdata->nsze / 1024 / 1024); 1576f0823e4SJim Harris printf("Capacity (in LBAs): %lld (%lldM)\n", 1586f0823e4SJim Harris (long long)nsdata->ncap, 1596f0823e4SJim Harris (long long)nsdata->ncap / 1024 / 1024); 1606f0823e4SJim Harris printf("Utilization (in LBAs): %lld (%lldM)\n", 1616f0823e4SJim Harris (long long)nsdata->nuse, 1626f0823e4SJim Harris (long long)nsdata->nuse / 1024 / 1024); 1636f0823e4SJim Harris printf("Thin Provisioning: %s\n", 1646f0823e4SJim Harris nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); 1656f0823e4SJim Harris printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); 1666f0823e4SJim Harris printf("Current LBA Format: LBA Format #%d\n", 1676f0823e4SJim Harris nsdata->flbas.format); 1686f0823e4SJim Harris for (i = 0; i <= nsdata->nlbaf; i++) { 1696f0823e4SJim Harris printf("LBA Format #%d:\n", i); 1706f0823e4SJim Harris printf(" LBA Data Size: %d\n", 1716f0823e4SJim Harris 1 << nsdata->lbaf[i].lbads); 1726f0823e4SJim Harris } 1736f0823e4SJim Harris } 1746f0823e4SJim Harris 1756f0823e4SJim Harris static void 1766f0823e4SJim Harris identify_usage(void) 1776f0823e4SJim Harris { 1786f0823e4SJim Harris fprintf(stderr, "usage:\n"); 1796f0823e4SJim Harris fprintf(stderr, IDENTIFY_USAGE); 1806f0823e4SJim Harris exit(EX_USAGE); 1816f0823e4SJim Harris } 1826f0823e4SJim Harris 1836f0823e4SJim Harris static void 1846f0823e4SJim Harris identify_ctrlr(int argc, char *argv[]) 1856f0823e4SJim Harris { 1866f0823e4SJim Harris struct nvme_controller_data cdata; 1876f0823e4SJim Harris int ch, fd, hexflag = 0, hexlength; 1886f0823e4SJim Harris int verboseflag = 0; 1896f0823e4SJim Harris 1906f0823e4SJim Harris while ((ch = getopt(argc, argv, "vx")) != -1) { 1916f0823e4SJim Harris switch ((char)ch) { 1926f0823e4SJim Harris case 'v': 1936f0823e4SJim Harris verboseflag = 1; 1946f0823e4SJim Harris break; 1956f0823e4SJim Harris case 'x': 1966f0823e4SJim Harris hexflag = 1; 1976f0823e4SJim Harris break; 1986f0823e4SJim Harris default: 1996f0823e4SJim Harris identify_usage(); 2006f0823e4SJim Harris } 2016f0823e4SJim Harris } 2026f0823e4SJim Harris 2036f0823e4SJim Harris open_dev(argv[optind], &fd, 1, 1); 2046f0823e4SJim Harris read_controller_data(fd, &cdata); 2056f0823e4SJim Harris close(fd); 2066f0823e4SJim Harris 2076f0823e4SJim Harris if (hexflag == 1) { 2086f0823e4SJim Harris if (verboseflag == 1) 2096f0823e4SJim Harris hexlength = sizeof(struct nvme_controller_data); 2106f0823e4SJim Harris else 2116f0823e4SJim Harris hexlength = offsetof(struct nvme_controller_data, 2126f0823e4SJim Harris reserved5); 2136f0823e4SJim Harris print_controller_hex(&cdata, hexlength); 2146f0823e4SJim Harris exit(EX_OK); 2156f0823e4SJim Harris } 2166f0823e4SJim Harris 2176f0823e4SJim Harris if (verboseflag == 1) { 2186f0823e4SJim Harris printf("-v not currently supported without -x.\n"); 2196f0823e4SJim Harris identify_usage(); 2206f0823e4SJim Harris } 2216f0823e4SJim Harris 2226f0823e4SJim Harris print_controller(&cdata); 2236f0823e4SJim Harris exit(EX_OK); 2246f0823e4SJim Harris } 2256f0823e4SJim Harris 2266f0823e4SJim Harris static void 2276f0823e4SJim Harris identify_ns(int argc, char *argv[]) 2286f0823e4SJim Harris { 2296f0823e4SJim Harris struct nvme_namespace_data nsdata; 2306f0823e4SJim Harris char path[64]; 2316f0823e4SJim Harris char *nsloc; 2326f0823e4SJim Harris int ch, fd, hexflag = 0, hexlength, nsid; 2336f0823e4SJim Harris int verboseflag = 0; 2346f0823e4SJim Harris 2356f0823e4SJim Harris while ((ch = getopt(argc, argv, "vx")) != -1) { 2366f0823e4SJim Harris switch ((char)ch) { 2376f0823e4SJim Harris case 'v': 2386f0823e4SJim Harris verboseflag = 1; 2396f0823e4SJim Harris break; 2406f0823e4SJim Harris case 'x': 2416f0823e4SJim Harris hexflag = 1; 2426f0823e4SJim Harris break; 2436f0823e4SJim Harris default: 2446f0823e4SJim Harris identify_usage(); 2456f0823e4SJim Harris } 2466f0823e4SJim Harris } 2476f0823e4SJim Harris 2486f0823e4SJim Harris /* 2496f0823e4SJim Harris * Check if the specified device node exists before continuing. 2506f0823e4SJim Harris * This is a cleaner check for cases where the correct controller 2516f0823e4SJim Harris * is specified, but an invalid namespace on that controller. 2526f0823e4SJim Harris */ 2536f0823e4SJim Harris open_dev(argv[optind], &fd, 1, 1); 2546f0823e4SJim Harris close(fd); 2556f0823e4SJim Harris 2566f0823e4SJim Harris /* 2576f0823e4SJim Harris * Pull the namespace id from the string. +2 skips past the "ns" part 2586f0823e4SJim Harris * of the string. Don't search past 10 characters into the string, 2596f0823e4SJim Harris * otherwise we know it is malformed. 2606f0823e4SJim Harris */ 2616420873cSJim Harris nsloc = strnstr(argv[optind], NVME_NS_PREFIX, 10); 2626f0823e4SJim Harris if (nsloc != NULL) 2636f0823e4SJim Harris nsid = strtol(nsloc + 2, NULL, 10); 2646f0823e4SJim Harris if (nsloc == NULL || (nsid == 0 && errno != 0)) { 2656f0823e4SJim Harris printf("Invalid namespace ID %s.\n", argv[optind]); 2666f0823e4SJim Harris exit(EX_IOERR); 2676f0823e4SJim Harris } 2686f0823e4SJim Harris 2696f0823e4SJim Harris /* 2706f0823e4SJim Harris * We send IDENTIFY commands to the controller, not the namespace, 2716f0823e4SJim Harris * since it is an admin cmd. So the path should only include the 2726f0823e4SJim Harris * nvmeX part of the nvmeXnsY string. 2736f0823e4SJim Harris */ 2746f0823e4SJim Harris snprintf(path, nsloc - argv[optind] + 1, "%s", argv[optind]); 2756f0823e4SJim Harris open_dev(path, &fd, 1, 1); 2766f0823e4SJim Harris read_namespace_data(fd, nsid, &nsdata); 2776f0823e4SJim Harris close(fd); 2786f0823e4SJim Harris 2796f0823e4SJim Harris if (hexflag == 1) { 2806f0823e4SJim Harris if (verboseflag == 1) 2816f0823e4SJim Harris hexlength = sizeof(struct nvme_namespace_data); 2826f0823e4SJim Harris else 2836f0823e4SJim Harris hexlength = offsetof(struct nvme_namespace_data, 2846f0823e4SJim Harris reserved6); 2856f0823e4SJim Harris print_namespace_hex(&nsdata, hexlength); 2866f0823e4SJim Harris exit(EX_OK); 2876f0823e4SJim Harris } 2886f0823e4SJim Harris 2896f0823e4SJim Harris if (verboseflag == 1) { 2906f0823e4SJim Harris printf("-v not currently supported without -x.\n"); 2916f0823e4SJim Harris identify_usage(); 2926f0823e4SJim Harris } 2936f0823e4SJim Harris 2946f0823e4SJim Harris print_namespace(&nsdata); 2956f0823e4SJim Harris exit(EX_OK); 2966f0823e4SJim Harris } 2976f0823e4SJim Harris 2986f0823e4SJim Harris void 2996f0823e4SJim Harris identify(int argc, char *argv[]) 3006f0823e4SJim Harris { 3016f0823e4SJim Harris char *target; 3026f0823e4SJim Harris 3036f0823e4SJim Harris if (argc < 2) 3046f0823e4SJim Harris identify_usage(); 3056f0823e4SJim Harris 3066f0823e4SJim Harris while (getopt(argc, argv, "vx") != -1) ; 3076f0823e4SJim Harris 3086f0823e4SJim Harris target = argv[optind]; 3096f0823e4SJim Harris 3106f0823e4SJim Harris optreset = 1; 3116f0823e4SJim Harris optind = 1; 3126f0823e4SJim Harris 3136f0823e4SJim Harris /* 3146f0823e4SJim Harris * If device node contains "ns", we consider it a namespace, 3156f0823e4SJim Harris * otherwise, consider it a controller. 3166f0823e4SJim Harris */ 3176420873cSJim Harris if (strstr(target, NVME_NS_PREFIX) == NULL) 3186f0823e4SJim Harris identify_ctrlr(argc, argv); 3196f0823e4SJim Harris else 3206f0823e4SJim Harris identify_ns(argc, argv); 3216f0823e4SJim Harris } 322