16660d5e4SJim Harris /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 46660d5e4SJim Harris * Copyright (C) 2012-2013 Intel Corporation 56660d5e4SJim Harris * All rights reserved. 66660d5e4SJim Harris * 76660d5e4SJim Harris * Redistribution and use in source and binary forms, with or without 86660d5e4SJim Harris * modification, are permitted provided that the following conditions 96660d5e4SJim Harris * are met: 106660d5e4SJim Harris * 1. Redistributions of source code must retain the above copyright 116660d5e4SJim Harris * notice, this list of conditions and the following disclaimer. 126660d5e4SJim Harris * 2. Redistributions in binary form must reproduce the above copyright 136660d5e4SJim Harris * notice, this list of conditions and the following disclaimer in the 146660d5e4SJim Harris * documentation and/or other materials provided with the distribution. 156660d5e4SJim Harris * 166660d5e4SJim Harris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 176660d5e4SJim Harris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 186660d5e4SJim Harris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 196660d5e4SJim Harris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 206660d5e4SJim Harris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 216660d5e4SJim Harris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 226660d5e4SJim Harris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 236660d5e4SJim Harris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 246660d5e4SJim Harris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 256660d5e4SJim Harris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 266660d5e4SJim Harris * SUCH DAMAGE. 276660d5e4SJim Harris */ 286660d5e4SJim Harris 296660d5e4SJim Harris #include <sys/param.h> 306660d5e4SJim Harris 31821ef73cSJim Harris #include <err.h> 32b378da27SJim Harris #include <errno.h> 336660d5e4SJim Harris #include <fcntl.h> 349c1bec9cSWanpeng Qian #include <stdbool.h> 359c1bec9cSWanpeng Qian #include <libutil.h> 36dddb618eSJim Harris #include <paths.h> 376660d5e4SJim Harris #include <stddef.h> 386660d5e4SJim Harris #include <stdio.h> 396660d5e4SJim Harris #include <stdlib.h> 406660d5e4SJim Harris #include <string.h> 415dc463f9SAlexander Motin #include <sysexits.h> 426660d5e4SJim Harris #include <unistd.h> 436660d5e4SJim Harris 446660d5e4SJim Harris #include "nvmecontrol.h" 45f634b4c1SWarner Losh #include "comnd.h" 466660d5e4SJim Harris 47f634b4c1SWarner Losh /* Tables for command line parsing */ 48a13a291aSWarner Losh 499d0e9f8eSWarner Losh #define NVME_MAX_UNIT 256 509d0e9f8eSWarner Losh 51f634b4c1SWarner Losh static cmd_fn_t devlist; 52f634b4c1SWarner Losh 539c1bec9cSWanpeng Qian static struct options { 549c1bec9cSWanpeng Qian bool human; 559c1bec9cSWanpeng Qian } opt = { 569c1bec9cSWanpeng Qian .human = false, 579c1bec9cSWanpeng Qian }; 589c1bec9cSWanpeng Qian 599c1bec9cSWanpeng Qian static const struct opts devlist_opts[] = { 609c1bec9cSWanpeng Qian #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } 619c1bec9cSWanpeng Qian OPT("human", 'h', arg_none, opt, human, 629c1bec9cSWanpeng Qian "Show human readable disk size"), 639c1bec9cSWanpeng Qian { NULL, 0, arg_none, NULL, NULL } 649c1bec9cSWanpeng Qian }; 659c1bec9cSWanpeng Qian #undef OPT 669c1bec9cSWanpeng Qian 67f634b4c1SWarner Losh static struct cmd devlist_cmd = { 68f634b4c1SWarner Losh .name = "devlist", 69f634b4c1SWarner Losh .fn = devlist, 709c1bec9cSWanpeng Qian .descr = "List NVMe controllers and namespaces", 719c1bec9cSWanpeng Qian .ctx_size = sizeof(opt), 729c1bec9cSWanpeng Qian .opts = devlist_opts, 739c1bec9cSWanpeng Qian .args = NULL, 74f634b4c1SWarner Losh }; 75f634b4c1SWarner Losh 76f634b4c1SWarner Losh CMD_COMMAND(devlist_cmd); 77f634b4c1SWarner Losh 78f634b4c1SWarner Losh /* End of tables for command line parsing */ 79f634b4c1SWarner Losh 806660d5e4SJim Harris static inline uint32_t 816660d5e4SJim Harris ns_get_sector_size(struct nvme_namespace_data *nsdata) 826660d5e4SJim Harris { 830d787e9bSWojciech Macek uint8_t flbas_fmt, lbads; 846660d5e4SJim Harris 85fba73a40SJohn Baldwin flbas_fmt = NVMEV(NVME_NS_DATA_FLBAS_FORMAT, nsdata->flbas); 86fba73a40SJohn Baldwin lbads = NVMEV(NVME_NS_DATA_LBAF_LBADS, nsdata->lbaf[flbas_fmt]); 870d787e9bSWojciech Macek 880d787e9bSWojciech Macek return (1 << lbads); 896660d5e4SJim Harris } 906660d5e4SJim Harris 91a13a291aSWarner Losh static void 92326e20fcSJohn Baldwin scan_namespace(int fd, int ctrlr, uint32_t nsid) 936660d5e4SJim Harris { 946660d5e4SJim Harris struct nvme_namespace_data nsdata; 956660d5e4SJim Harris char name[64]; 969c1bec9cSWanpeng Qian uint8_t buf[7]; 979c1bec9cSWanpeng Qian uint64_t size; 98326e20fcSJohn Baldwin 99326e20fcSJohn Baldwin if (read_namespace_data(fd, nsid, &nsdata) != 0) 100326e20fcSJohn Baldwin return; 101326e20fcSJohn Baldwin if (nsdata.nsze == 0) 102326e20fcSJohn Baldwin return; 103326e20fcSJohn Baldwin snprintf(name, sizeof(name), "%s%d%s%d", NVME_CTRLR_PREFIX, ctrlr, 104326e20fcSJohn Baldwin NVME_NS_PREFIX, nsid); 105326e20fcSJohn Baldwin size = nsdata.nsze * (uint64_t)ns_get_sector_size(&nsdata); 106326e20fcSJohn Baldwin if (opt.human) { 107326e20fcSJohn Baldwin humanize_number(buf, sizeof(buf), size, "B", 108326e20fcSJohn Baldwin HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 109326e20fcSJohn Baldwin printf(" %10s (%s)\n", name, buf); 110326e20fcSJohn Baldwin } else { 111326e20fcSJohn Baldwin printf(" %10s (%juMB)\n", name, (uintmax_t)size / 1024 / 1024); 112326e20fcSJohn Baldwin } 113326e20fcSJohn Baldwin } 114326e20fcSJohn Baldwin 115326e20fcSJohn Baldwin static bool 116326e20fcSJohn Baldwin scan_controller(int ctrlr) 117326e20fcSJohn Baldwin { 118326e20fcSJohn Baldwin struct nvme_controller_data cdata; 119*9e1db51dSJohn Baldwin struct nvme_ns_list nslist; 120326e20fcSJohn Baldwin char name[64]; 121326e20fcSJohn Baldwin uint8_t mn[64]; 122*9e1db51dSJohn Baldwin uint32_t nsid; 123326e20fcSJohn Baldwin int fd, ret; 124326e20fcSJohn Baldwin 125326e20fcSJohn Baldwin snprintf(name, sizeof(name), "%s%d", NVME_CTRLR_PREFIX, ctrlr); 126326e20fcSJohn Baldwin 127326e20fcSJohn Baldwin ret = open_dev(name, &fd, 0, 0); 128326e20fcSJohn Baldwin 129326e20fcSJohn Baldwin if (ret == EACCES) { 130326e20fcSJohn Baldwin warnx("could not open "_PATH_DEV"%s\n", name); 131326e20fcSJohn Baldwin return (false); 132326e20fcSJohn Baldwin } else if (ret != 0) 133326e20fcSJohn Baldwin return (false); 134326e20fcSJohn Baldwin 135326e20fcSJohn Baldwin if (read_controller_data(fd, &cdata) != 0) { 136326e20fcSJohn Baldwin close(fd); 137326e20fcSJohn Baldwin return (true); 138326e20fcSJohn Baldwin } 139326e20fcSJohn Baldwin 140326e20fcSJohn Baldwin nvme_strvis(mn, cdata.mn, sizeof(mn), NVME_MODEL_NUMBER_LENGTH); 141326e20fcSJohn Baldwin printf("%6s: %s\n", name, mn); 142326e20fcSJohn Baldwin 143*9e1db51dSJohn Baldwin nsid = 0; 144*9e1db51dSJohn Baldwin for (;;) { 145*9e1db51dSJohn Baldwin if (read_active_namespaces(fd, nsid, &nslist) != 0) 146*9e1db51dSJohn Baldwin break; 147*9e1db51dSJohn Baldwin for (u_int i = 0; i < nitems(nslist.ns); i++) { 148*9e1db51dSJohn Baldwin nsid = nslist.ns[i]; 149*9e1db51dSJohn Baldwin if (nsid == 0) { 150*9e1db51dSJohn Baldwin break; 151*9e1db51dSJohn Baldwin } 152*9e1db51dSJohn Baldwin 153*9e1db51dSJohn Baldwin scan_namespace(fd, ctrlr, nsid); 154*9e1db51dSJohn Baldwin } 155*9e1db51dSJohn Baldwin if (nsid == 0 || nsid >= NVME_GLOBAL_NAMESPACE_TAG - 1) 156*9e1db51dSJohn Baldwin break; 157326e20fcSJohn Baldwin } 158326e20fcSJohn Baldwin 159326e20fcSJohn Baldwin close(fd); 160326e20fcSJohn Baldwin return (true); 161326e20fcSJohn Baldwin } 162326e20fcSJohn Baldwin 163326e20fcSJohn Baldwin static void 164326e20fcSJohn Baldwin devlist(const struct cmd *f, int argc, char *argv[]) 165326e20fcSJohn Baldwin { 166326e20fcSJohn Baldwin int ctrlr, found; 1676660d5e4SJim Harris 168f634b4c1SWarner Losh if (arg_parse(argc, argv, f)) 169f634b4c1SWarner Losh return; 1706660d5e4SJim Harris 1716660d5e4SJim Harris ctrlr = -1; 1726660d5e4SJim Harris found = 0; 1736660d5e4SJim Harris 1749d0e9f8eSWarner Losh while (ctrlr < NVME_MAX_UNIT) { 1756660d5e4SJim Harris ctrlr++; 176326e20fcSJohn Baldwin if (scan_controller(ctrlr)) 1776660d5e4SJim Harris found++; 1786660d5e4SJim Harris } 1796660d5e4SJim Harris 1800e3e53d7SDavid Bright if (found == 0) { 1816660d5e4SJim Harris printf("No NVMe controllers found.\n"); 1825dc463f9SAlexander Motin exit(EX_UNAVAILABLE); 1836660d5e4SJim Harris } 1840e3e53d7SDavid Bright 1850e3e53d7SDavid Bright exit(0); 1860e3e53d7SDavid Bright } 187