xref: /freebsd/sbin/nvmecontrol/discover.c (revision 1058c12197aba80d0777e3484f350436fca55fd7)
1*1058c121SJohn Baldwin /*-
2*1058c121SJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause
3*1058c121SJohn Baldwin  *
4*1058c121SJohn Baldwin  * Copyright (c) 2023-2024 Chelsio Communications, Inc.
5*1058c121SJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
6*1058c121SJohn Baldwin  */
7*1058c121SJohn Baldwin 
8*1058c121SJohn Baldwin #include <err.h>
9*1058c121SJohn Baldwin #include <libnvmf.h>
10*1058c121SJohn Baldwin #include <stdio.h>
11*1058c121SJohn Baldwin #include <stdlib.h>
12*1058c121SJohn Baldwin #include <string.h>
13*1058c121SJohn Baldwin #include <sysexits.h>
14*1058c121SJohn Baldwin 
15*1058c121SJohn Baldwin #include "comnd.h"
16*1058c121SJohn Baldwin #include "fabrics.h"
17*1058c121SJohn Baldwin #include "nvmecontrol_ext.h"
18*1058c121SJohn Baldwin 
19*1058c121SJohn Baldwin static struct options {
20*1058c121SJohn Baldwin 	const char	*transport;
21*1058c121SJohn Baldwin 	const char	*address;
22*1058c121SJohn Baldwin 	const char	*hostnqn;
23*1058c121SJohn Baldwin 	bool		verbose;
24*1058c121SJohn Baldwin } opt = {
25*1058c121SJohn Baldwin 	.transport = "tcp",
26*1058c121SJohn Baldwin 	.address = NULL,
27*1058c121SJohn Baldwin 	.hostnqn = NULL,
28*1058c121SJohn Baldwin 	.verbose = false,
29*1058c121SJohn Baldwin };
30*1058c121SJohn Baldwin 
31*1058c121SJohn Baldwin static void
32*1058c121SJohn Baldwin identify_controller(struct nvmf_qpair *qp)
33*1058c121SJohn Baldwin {
34*1058c121SJohn Baldwin 	struct nvme_controller_data cdata;
35*1058c121SJohn Baldwin 	int error;
36*1058c121SJohn Baldwin 
37*1058c121SJohn Baldwin 	error = nvmf_host_identify_controller(qp, &cdata);
38*1058c121SJohn Baldwin 	if (error != 0)
39*1058c121SJohn Baldwin 		errc(EX_IOERR, error, "Failed to fetch controller data");
40*1058c121SJohn Baldwin 	nvme_print_controller(&cdata);
41*1058c121SJohn Baldwin }
42*1058c121SJohn Baldwin 
43*1058c121SJohn Baldwin static const char *
44*1058c121SJohn Baldwin nvmf_address_family(uint8_t adrfam)
45*1058c121SJohn Baldwin {
46*1058c121SJohn Baldwin 	static char buf[8];
47*1058c121SJohn Baldwin 
48*1058c121SJohn Baldwin 	switch (adrfam) {
49*1058c121SJohn Baldwin 	case NVMF_ADRFAM_IPV4:
50*1058c121SJohn Baldwin 		return ("AF_INET");
51*1058c121SJohn Baldwin 	case NVMF_ADRFAM_IPV6:
52*1058c121SJohn Baldwin 		return ("AF_INET6");
53*1058c121SJohn Baldwin 	case NVMF_ADRFAM_IB:
54*1058c121SJohn Baldwin 		return ("InfiniBand");
55*1058c121SJohn Baldwin 	case NVMF_ADRFAM_FC:
56*1058c121SJohn Baldwin 		return ("Fibre Channel");
57*1058c121SJohn Baldwin 	case NVMF_ADRFAM_INTRA_HOST:
58*1058c121SJohn Baldwin 		return ("Intra-host");
59*1058c121SJohn Baldwin 	default:
60*1058c121SJohn Baldwin 		snprintf(buf, sizeof(buf), "0x%02x\n", adrfam);
61*1058c121SJohn Baldwin 		return (buf);
62*1058c121SJohn Baldwin 	}
63*1058c121SJohn Baldwin }
64*1058c121SJohn Baldwin 
65*1058c121SJohn Baldwin static const char *
66*1058c121SJohn Baldwin nvmf_subsystem_type(uint8_t subtype)
67*1058c121SJohn Baldwin {
68*1058c121SJohn Baldwin 	static char buf[8];
69*1058c121SJohn Baldwin 
70*1058c121SJohn Baldwin 	switch (subtype) {
71*1058c121SJohn Baldwin 	case NVMF_SUBTYPE_DISCOVERY:
72*1058c121SJohn Baldwin 		return ("Discovery");
73*1058c121SJohn Baldwin 	case NVMF_SUBTYPE_NVME:
74*1058c121SJohn Baldwin 		return ("NVMe");
75*1058c121SJohn Baldwin 	default:
76*1058c121SJohn Baldwin 		snprintf(buf, sizeof(buf), "0x%02x\n", subtype);
77*1058c121SJohn Baldwin 		return (buf);
78*1058c121SJohn Baldwin 	}
79*1058c121SJohn Baldwin }
80*1058c121SJohn Baldwin 
81*1058c121SJohn Baldwin static const char *
82*1058c121SJohn Baldwin nvmf_secure_channel(uint8_t treq)
83*1058c121SJohn Baldwin {
84*1058c121SJohn Baldwin 	switch (treq & 0x03) {
85*1058c121SJohn Baldwin 	case NVMF_TREQ_SECURE_CHANNEL_NOT_SPECIFIED:
86*1058c121SJohn Baldwin 		return ("Not specified");
87*1058c121SJohn Baldwin 	case NVMF_TREQ_SECURE_CHANNEL_REQUIRED:
88*1058c121SJohn Baldwin 		return ("Required");
89*1058c121SJohn Baldwin 	case NVMF_TREQ_SECURE_CHANNEL_NOT_REQUIRED:
90*1058c121SJohn Baldwin 		return ("Not required");
91*1058c121SJohn Baldwin 	default:
92*1058c121SJohn Baldwin 		return ("0x03");
93*1058c121SJohn Baldwin 	}
94*1058c121SJohn Baldwin }
95*1058c121SJohn Baldwin 
96*1058c121SJohn Baldwin static const char *
97*1058c121SJohn Baldwin nvmf_controller_id(uint16_t cntlid)
98*1058c121SJohn Baldwin {
99*1058c121SJohn Baldwin 	static char buf[8];
100*1058c121SJohn Baldwin 
101*1058c121SJohn Baldwin 	switch (cntlid) {
102*1058c121SJohn Baldwin 	case NVMF_CNTLID_DYNAMIC:
103*1058c121SJohn Baldwin 		return ("Dynamic");
104*1058c121SJohn Baldwin 	case NVMF_CNTLID_STATIC_ANY:
105*1058c121SJohn Baldwin 		return ("Static");
106*1058c121SJohn Baldwin 	default:
107*1058c121SJohn Baldwin 		snprintf(buf, sizeof(buf), "%u", cntlid);
108*1058c121SJohn Baldwin 		return (buf);
109*1058c121SJohn Baldwin 	}
110*1058c121SJohn Baldwin }
111*1058c121SJohn Baldwin 
112*1058c121SJohn Baldwin static const char *
113*1058c121SJohn Baldwin nvmf_rdma_service_type(uint8_t qptype)
114*1058c121SJohn Baldwin {
115*1058c121SJohn Baldwin 	static char buf[8];
116*1058c121SJohn Baldwin 
117*1058c121SJohn Baldwin 	switch (qptype) {
118*1058c121SJohn Baldwin 	case NVMF_RDMA_QPTYPE_RELIABLE_CONNECTED:
119*1058c121SJohn Baldwin 		return ("Reliable connected");
120*1058c121SJohn Baldwin 	case NVMF_RDMA_QPTYPE_RELIABLE_DATAGRAM:
121*1058c121SJohn Baldwin 		return ("Reliable datagram");
122*1058c121SJohn Baldwin 	default:
123*1058c121SJohn Baldwin 		snprintf(buf, sizeof(buf), "0x%02x\n", qptype);
124*1058c121SJohn Baldwin 		return (buf);
125*1058c121SJohn Baldwin 	}
126*1058c121SJohn Baldwin }
127*1058c121SJohn Baldwin 
128*1058c121SJohn Baldwin static const char *
129*1058c121SJohn Baldwin nvmf_rdma_provider_type(uint8_t prtype)
130*1058c121SJohn Baldwin {
131*1058c121SJohn Baldwin 	static char buf[8];
132*1058c121SJohn Baldwin 
133*1058c121SJohn Baldwin 	switch (prtype) {
134*1058c121SJohn Baldwin 	case NVMF_RDMA_PRTYPE_NONE:
135*1058c121SJohn Baldwin 		return ("None");
136*1058c121SJohn Baldwin 	case NVMF_RDMA_PRTYPE_IB:
137*1058c121SJohn Baldwin 		return ("InfiniBand");
138*1058c121SJohn Baldwin 	case NVMF_RDMA_PRTYPE_ROCE:
139*1058c121SJohn Baldwin 		return ("RoCE (v1)");
140*1058c121SJohn Baldwin 	case NVMF_RDMA_PRTYPE_ROCE2:
141*1058c121SJohn Baldwin 		return ("RoCE (v2)");
142*1058c121SJohn Baldwin 	case NVMF_RDMA_PRTYPE_IWARP:
143*1058c121SJohn Baldwin 		return ("iWARP");
144*1058c121SJohn Baldwin 	default:
145*1058c121SJohn Baldwin 		snprintf(buf, sizeof(buf), "0x%02x\n", prtype);
146*1058c121SJohn Baldwin 		return (buf);
147*1058c121SJohn Baldwin 	}
148*1058c121SJohn Baldwin }
149*1058c121SJohn Baldwin 
150*1058c121SJohn Baldwin static const char *
151*1058c121SJohn Baldwin nvmf_rdma_cms(uint8_t cms)
152*1058c121SJohn Baldwin {
153*1058c121SJohn Baldwin 	static char buf[8];
154*1058c121SJohn Baldwin 
155*1058c121SJohn Baldwin 	switch (cms) {
156*1058c121SJohn Baldwin 	case NVMF_RDMA_CMS_RDMA_CM:
157*1058c121SJohn Baldwin 		return ("RDMA_IP_CM");
158*1058c121SJohn Baldwin 	default:
159*1058c121SJohn Baldwin 		snprintf(buf, sizeof(buf), "0x%02x\n", cms);
160*1058c121SJohn Baldwin 		return (buf);
161*1058c121SJohn Baldwin 	}
162*1058c121SJohn Baldwin }
163*1058c121SJohn Baldwin 
164*1058c121SJohn Baldwin static const char *
165*1058c121SJohn Baldwin nvmf_tcp_security_type(uint8_t sectype)
166*1058c121SJohn Baldwin {
167*1058c121SJohn Baldwin 	static char buf[8];
168*1058c121SJohn Baldwin 
169*1058c121SJohn Baldwin 	switch (sectype) {
170*1058c121SJohn Baldwin 	case NVME_TCP_SECURITY_NONE:
171*1058c121SJohn Baldwin 		return ("None");
172*1058c121SJohn Baldwin 	case NVME_TCP_SECURITY_TLS_1_2:
173*1058c121SJohn Baldwin 		return ("TLS 1.2");
174*1058c121SJohn Baldwin 	case NVME_TCP_SECURITY_TLS_1_3:
175*1058c121SJohn Baldwin 		return ("TLS 1.3");
176*1058c121SJohn Baldwin 	default:
177*1058c121SJohn Baldwin 		snprintf(buf, sizeof(buf), "0x%02x\n", sectype);
178*1058c121SJohn Baldwin 		return (buf);
179*1058c121SJohn Baldwin 	}
180*1058c121SJohn Baldwin }
181*1058c121SJohn Baldwin 
182*1058c121SJohn Baldwin static void
183*1058c121SJohn Baldwin print_discovery_entry(u_int i, struct nvme_discovery_log_entry *entry)
184*1058c121SJohn Baldwin {
185*1058c121SJohn Baldwin 	printf("Entry %02d\n", i + 1);
186*1058c121SJohn Baldwin 	printf("========\n");
187*1058c121SJohn Baldwin 	printf(" Transport type:       %s\n",
188*1058c121SJohn Baldwin 	    nvmf_transport_type(entry->trtype));
189*1058c121SJohn Baldwin 	printf(" Address family:       %s\n",
190*1058c121SJohn Baldwin 	    nvmf_address_family(entry->adrfam));
191*1058c121SJohn Baldwin 	printf(" Subsystem type:       %s\n",
192*1058c121SJohn Baldwin 	    nvmf_subsystem_type(entry->subtype));
193*1058c121SJohn Baldwin 	printf(" SQ flow control:      %s\n",
194*1058c121SJohn Baldwin 	    (entry->treq & (1 << 2)) == 0 ? "required" : "optional");
195*1058c121SJohn Baldwin 	printf(" Secure Channel:       %s\n", nvmf_secure_channel(entry->treq));
196*1058c121SJohn Baldwin 	printf(" Port ID:              %u\n", entry->portid);
197*1058c121SJohn Baldwin 	printf(" Controller ID:        %s\n",
198*1058c121SJohn Baldwin 	    nvmf_controller_id(entry->cntlid));
199*1058c121SJohn Baldwin 	printf(" Max Admin SQ Size:    %u\n", entry->aqsz);
200*1058c121SJohn Baldwin 	printf(" Sub NQN:              %s\n", entry->subnqn);
201*1058c121SJohn Baldwin 	printf(" Transport address:    %s\n", entry->traddr);
202*1058c121SJohn Baldwin 	printf(" Service identifier:   %s\n", entry->trsvcid);
203*1058c121SJohn Baldwin 	switch (entry->trtype) {
204*1058c121SJohn Baldwin 	case NVMF_TRTYPE_RDMA:
205*1058c121SJohn Baldwin 		printf(" RDMA Service Type:    %s\n",
206*1058c121SJohn Baldwin 		    nvmf_rdma_service_type(entry->tsas.rdma.rdma_qptype));
207*1058c121SJohn Baldwin 		printf(" RDMA Provider Type:   %s\n",
208*1058c121SJohn Baldwin 		    nvmf_rdma_provider_type(entry->tsas.rdma.rdma_prtype));
209*1058c121SJohn Baldwin 		printf(" RDMA CMS:             %s\n",
210*1058c121SJohn Baldwin 		    nvmf_rdma_cms(entry->tsas.rdma.rdma_cms));
211*1058c121SJohn Baldwin 		printf(" Partition key:        %u\n",
212*1058c121SJohn Baldwin 		    entry->tsas.rdma.rdma_pkey);
213*1058c121SJohn Baldwin 		break;
214*1058c121SJohn Baldwin 	case NVMF_TRTYPE_TCP:
215*1058c121SJohn Baldwin 		printf(" Security Type:        %s\n",
216*1058c121SJohn Baldwin 		    nvmf_tcp_security_type(entry->tsas.tcp.sectype));
217*1058c121SJohn Baldwin 		break;
218*1058c121SJohn Baldwin 	}
219*1058c121SJohn Baldwin }
220*1058c121SJohn Baldwin 
221*1058c121SJohn Baldwin static void
222*1058c121SJohn Baldwin dump_discovery_log_page(struct nvmf_qpair *qp)
223*1058c121SJohn Baldwin {
224*1058c121SJohn Baldwin 	struct nvme_discovery_log *log;
225*1058c121SJohn Baldwin 	int error;
226*1058c121SJohn Baldwin 
227*1058c121SJohn Baldwin 	error = nvmf_host_fetch_discovery_log_page(qp, &log);
228*1058c121SJohn Baldwin 	if (error != 0)
229*1058c121SJohn Baldwin 		errc(EX_IOERR, error, "Failed to fetch discovery log page");
230*1058c121SJohn Baldwin 
231*1058c121SJohn Baldwin 	printf("Discovery\n");
232*1058c121SJohn Baldwin 	printf("=========\n");
233*1058c121SJohn Baldwin 	if (log->numrec == 0) {
234*1058c121SJohn Baldwin 		printf("No entries found\n");
235*1058c121SJohn Baldwin 	} else {
236*1058c121SJohn Baldwin 		for (u_int i = 0; i < log->numrec; i++)
237*1058c121SJohn Baldwin 			print_discovery_entry(i, &log->entries[i]);
238*1058c121SJohn Baldwin 	}
239*1058c121SJohn Baldwin 	free(log);
240*1058c121SJohn Baldwin }
241*1058c121SJohn Baldwin 
242*1058c121SJohn Baldwin static void
243*1058c121SJohn Baldwin discover(const struct cmd *f, int argc, char *argv[])
244*1058c121SJohn Baldwin {
245*1058c121SJohn Baldwin 	enum nvmf_trtype trtype;
246*1058c121SJohn Baldwin 	struct nvmf_qpair *qp;
247*1058c121SJohn Baldwin 	const char *address, *port;
248*1058c121SJohn Baldwin 	char *tofree;
249*1058c121SJohn Baldwin 
250*1058c121SJohn Baldwin 	if (arg_parse(argc, argv, f))
251*1058c121SJohn Baldwin 		return;
252*1058c121SJohn Baldwin 
253*1058c121SJohn Baldwin 	if (strcasecmp(opt.transport, "tcp") == 0) {
254*1058c121SJohn Baldwin 		trtype = NVMF_TRTYPE_TCP;
255*1058c121SJohn Baldwin 	} else
256*1058c121SJohn Baldwin 		errx(EX_USAGE, "Unsupported or invalid transport");
257*1058c121SJohn Baldwin 
258*1058c121SJohn Baldwin 	nvmf_parse_address(opt.address, &address, &port, &tofree);
259*1058c121SJohn Baldwin 	qp = connect_discovery_adminq(trtype, address, port, opt.hostnqn);
260*1058c121SJohn Baldwin 	free(tofree);
261*1058c121SJohn Baldwin 
262*1058c121SJohn Baldwin 	/* Use Identify to fetch controller data */
263*1058c121SJohn Baldwin 	if (opt.verbose) {
264*1058c121SJohn Baldwin 		identify_controller(qp);
265*1058c121SJohn Baldwin 		printf("\n");
266*1058c121SJohn Baldwin 	}
267*1058c121SJohn Baldwin 
268*1058c121SJohn Baldwin 	/* Fetch Log pages */
269*1058c121SJohn Baldwin 	dump_discovery_log_page(qp);
270*1058c121SJohn Baldwin 
271*1058c121SJohn Baldwin 	nvmf_free_qpair(qp);
272*1058c121SJohn Baldwin }
273*1058c121SJohn Baldwin 
274*1058c121SJohn Baldwin static const struct opts discover_opts[] = {
275*1058c121SJohn Baldwin #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
276*1058c121SJohn Baldwin 	OPT("transport", 't', arg_string, opt, transport,
277*1058c121SJohn Baldwin 	    "Transport type"),
278*1058c121SJohn Baldwin 	OPT("hostnqn", 'q', arg_string, opt, hostnqn,
279*1058c121SJohn Baldwin 	    "Host NQN"),
280*1058c121SJohn Baldwin 	OPT("verbose", 'v', arg_none, opt, verbose,
281*1058c121SJohn Baldwin 	    "Display the discovery controller's controller data"),
282*1058c121SJohn Baldwin 	{ NULL, 0, arg_none, NULL, NULL }
283*1058c121SJohn Baldwin };
284*1058c121SJohn Baldwin #undef OPT
285*1058c121SJohn Baldwin 
286*1058c121SJohn Baldwin static const struct args discover_args[] = {
287*1058c121SJohn Baldwin 	{ arg_string, &opt.address, "address" },
288*1058c121SJohn Baldwin 	{ arg_none, NULL, NULL },
289*1058c121SJohn Baldwin };
290*1058c121SJohn Baldwin 
291*1058c121SJohn Baldwin static struct cmd discover_cmd = {
292*1058c121SJohn Baldwin 	.name = "discover",
293*1058c121SJohn Baldwin 	.fn = discover,
294*1058c121SJohn Baldwin 	.descr = "List discovery log pages from a fabrics controller",
295*1058c121SJohn Baldwin 	.ctx_size = sizeof(opt),
296*1058c121SJohn Baldwin 	.opts = discover_opts,
297*1058c121SJohn Baldwin 	.args = discover_args,
298*1058c121SJohn Baldwin };
299*1058c121SJohn Baldwin 
300*1058c121SJohn Baldwin CMD_COMMAND(discover_cmd);
301