xref: /freebsd-src/sbin/nvmecontrol/devlist.c (revision 9e1db51d4b5fce8a1ea7271018970760e396500c)
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