xref: /freebsd/sbin/nvmecontrol/reconnect.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 <sys/socket.h>
9*1058c121SJohn Baldwin #include <err.h>
10*1058c121SJohn Baldwin #include <libnvmf.h>
11*1058c121SJohn Baldwin #include <stdlib.h>
12*1058c121SJohn Baldwin #include <string.h>
13*1058c121SJohn Baldwin #include <sysexits.h>
14*1058c121SJohn Baldwin #include <unistd.h>
15*1058c121SJohn Baldwin 
16*1058c121SJohn Baldwin #include "nvmecontrol.h"
17*1058c121SJohn Baldwin #include "fabrics.h"
18*1058c121SJohn Baldwin 
19*1058c121SJohn Baldwin /*
20*1058c121SJohn Baldwin  * See comment about other possible settings in connect.c.
21*1058c121SJohn Baldwin  */
22*1058c121SJohn Baldwin 
23*1058c121SJohn Baldwin static struct options {
24*1058c121SJohn Baldwin 	const char	*dev;
25*1058c121SJohn Baldwin 	const char	*transport;
26*1058c121SJohn Baldwin 	const char	*address;
27*1058c121SJohn Baldwin 	const char	*hostnqn;
28*1058c121SJohn Baldwin 	uint32_t	kato;
29*1058c121SJohn Baldwin 	uint16_t	num_io_queues;
30*1058c121SJohn Baldwin 	uint16_t	queue_size;
31*1058c121SJohn Baldwin 	bool		data_digests;
32*1058c121SJohn Baldwin 	bool		flow_control;
33*1058c121SJohn Baldwin 	bool		header_digests;
34*1058c121SJohn Baldwin } opt = {
35*1058c121SJohn Baldwin 	.dev = NULL,
36*1058c121SJohn Baldwin 	.transport = "tcp",
37*1058c121SJohn Baldwin 	.address = NULL,
38*1058c121SJohn Baldwin 	.hostnqn = NULL,
39*1058c121SJohn Baldwin 	.kato = NVMF_KATO_DEFAULT / 1000,
40*1058c121SJohn Baldwin 	.num_io_queues = 1,
41*1058c121SJohn Baldwin 	.queue_size = 0,
42*1058c121SJohn Baldwin 	.data_digests = false,
43*1058c121SJohn Baldwin 	.flow_control = false,
44*1058c121SJohn Baldwin 	.header_digests = false,
45*1058c121SJohn Baldwin };
46*1058c121SJohn Baldwin 
47*1058c121SJohn Baldwin static void
48*1058c121SJohn Baldwin tcp_association_params(struct nvmf_association_params *params)
49*1058c121SJohn Baldwin {
50*1058c121SJohn Baldwin 	params->tcp.pda = 0;
51*1058c121SJohn Baldwin 	params->tcp.header_digests = opt.header_digests;
52*1058c121SJohn Baldwin 	params->tcp.data_digests = opt.data_digests;
53*1058c121SJohn Baldwin 	/* XXX */
54*1058c121SJohn Baldwin 	params->tcp.maxr2t = 1;
55*1058c121SJohn Baldwin }
56*1058c121SJohn Baldwin 
57*1058c121SJohn Baldwin static int
58*1058c121SJohn Baldwin reconnect_nvm_controller(int fd, enum nvmf_trtype trtype, int adrfam,
59*1058c121SJohn Baldwin     const char *address, const char *port)
60*1058c121SJohn Baldwin {
61*1058c121SJohn Baldwin 	struct nvme_controller_data cdata;
62*1058c121SJohn Baldwin 	struct nvmf_association_params aparams;
63*1058c121SJohn Baldwin 	struct nvmf_reconnect_params rparams;
64*1058c121SJohn Baldwin 	struct nvmf_qpair *admin, **io;
65*1058c121SJohn Baldwin 	int error;
66*1058c121SJohn Baldwin 
67*1058c121SJohn Baldwin 	error = nvmf_reconnect_params(fd, &rparams);
68*1058c121SJohn Baldwin 	if (error != 0) {
69*1058c121SJohn Baldwin 		warnc(error, "Failed to fetch reconnect parameters");
70*1058c121SJohn Baldwin 		return (EX_IOERR);
71*1058c121SJohn Baldwin 	}
72*1058c121SJohn Baldwin 
73*1058c121SJohn Baldwin 	memset(&aparams, 0, sizeof(aparams));
74*1058c121SJohn Baldwin 	aparams.sq_flow_control = opt.flow_control;
75*1058c121SJohn Baldwin 	switch (trtype) {
76*1058c121SJohn Baldwin 	case NVMF_TRTYPE_TCP:
77*1058c121SJohn Baldwin 		tcp_association_params(&aparams);
78*1058c121SJohn Baldwin 		break;
79*1058c121SJohn Baldwin 	default:
80*1058c121SJohn Baldwin 		warnx("Unsupported transport %s", nvmf_transport_type(trtype));
81*1058c121SJohn Baldwin 		return (EX_UNAVAILABLE);
82*1058c121SJohn Baldwin 	}
83*1058c121SJohn Baldwin 
84*1058c121SJohn Baldwin 	io = calloc(opt.num_io_queues, sizeof(*io));
85*1058c121SJohn Baldwin 	error = connect_nvm_queues(&aparams, trtype, adrfam, address, port,
86*1058c121SJohn Baldwin 	    rparams.cntlid, rparams.subnqn, opt.hostnqn, opt.kato, &admin, io,
87*1058c121SJohn Baldwin 	    opt.num_io_queues, opt.queue_size, &cdata);
88*1058c121SJohn Baldwin 	if (error != 0)
89*1058c121SJohn Baldwin 		return (error);
90*1058c121SJohn Baldwin 
91*1058c121SJohn Baldwin 	error = nvmf_reconnect_host(fd, admin, opt.num_io_queues, io, &cdata);
92*1058c121SJohn Baldwin 	if (error != 0) {
93*1058c121SJohn Baldwin 		warnc(error, "Failed to handoff queues to kernel");
94*1058c121SJohn Baldwin 		return (EX_IOERR);
95*1058c121SJohn Baldwin 	}
96*1058c121SJohn Baldwin 	free(io);
97*1058c121SJohn Baldwin 	return (0);
98*1058c121SJohn Baldwin }
99*1058c121SJohn Baldwin 
100*1058c121SJohn Baldwin static void
101*1058c121SJohn Baldwin reconnect_fn(const struct cmd *f, int argc, char *argv[])
102*1058c121SJohn Baldwin {
103*1058c121SJohn Baldwin 	enum nvmf_trtype trtype;
104*1058c121SJohn Baldwin 	const char *address, *port;
105*1058c121SJohn Baldwin 	char *tofree;
106*1058c121SJohn Baldwin 	int error, fd;
107*1058c121SJohn Baldwin 
108*1058c121SJohn Baldwin 	if (arg_parse(argc, argv, f))
109*1058c121SJohn Baldwin 		return;
110*1058c121SJohn Baldwin 
111*1058c121SJohn Baldwin 	if (strcasecmp(opt.transport, "tcp") == 0) {
112*1058c121SJohn Baldwin 		trtype = NVMF_TRTYPE_TCP;
113*1058c121SJohn Baldwin 	} else
114*1058c121SJohn Baldwin 		errx(EX_USAGE, "Unsupported or invalid transport");
115*1058c121SJohn Baldwin 
116*1058c121SJohn Baldwin 	nvmf_parse_address(opt.address, &address, &port, &tofree);
117*1058c121SJohn Baldwin 
118*1058c121SJohn Baldwin 	open_dev(opt.dev, &fd, 1, 1);
119*1058c121SJohn Baldwin 	if (port == NULL)
120*1058c121SJohn Baldwin 		errx(EX_USAGE, "Explicit port required");
121*1058c121SJohn Baldwin 
122*1058c121SJohn Baldwin 	error = reconnect_nvm_controller(fd, trtype, AF_UNSPEC, address, port);
123*1058c121SJohn Baldwin 	if (error != 0)
124*1058c121SJohn Baldwin 		exit(error);
125*1058c121SJohn Baldwin 
126*1058c121SJohn Baldwin 	close(fd);
127*1058c121SJohn Baldwin 	free(tofree);
128*1058c121SJohn Baldwin }
129*1058c121SJohn Baldwin 
130*1058c121SJohn Baldwin static const struct opts reconnect_opts[] = {
131*1058c121SJohn Baldwin #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
132*1058c121SJohn Baldwin 	OPT("transport", 't', arg_string, opt, transport,
133*1058c121SJohn Baldwin 	    "Transport type"),
134*1058c121SJohn Baldwin 	OPT("nr-io-queues", 'i', arg_uint16, opt, num_io_queues,
135*1058c121SJohn Baldwin 	    "Number of I/O queues"),
136*1058c121SJohn Baldwin 	OPT("queue-size", 'Q', arg_uint16, opt, queue_size,
137*1058c121SJohn Baldwin 	    "Number of entries in each I/O queue"),
138*1058c121SJohn Baldwin 	OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato,
139*1058c121SJohn Baldwin 	    "Keep Alive timeout (in seconds)"),
140*1058c121SJohn Baldwin 	OPT("hostnqn", 'q', arg_string, opt, hostnqn,
141*1058c121SJohn Baldwin 	    "Host NQN"),
142*1058c121SJohn Baldwin 	OPT("flow_control", 'F', arg_none, opt, flow_control,
143*1058c121SJohn Baldwin 	    "Request SQ flow control"),
144*1058c121SJohn Baldwin 	OPT("hdr_digests", 'g', arg_none, opt, header_digests,
145*1058c121SJohn Baldwin 	    "Enable TCP PDU header digests"),
146*1058c121SJohn Baldwin 	OPT("data_digests", 'G', arg_none, opt, data_digests,
147*1058c121SJohn Baldwin 	    "Enable TCP PDU data digests"),
148*1058c121SJohn Baldwin 	{ NULL, 0, arg_none, NULL, NULL }
149*1058c121SJohn Baldwin };
150*1058c121SJohn Baldwin #undef OPT
151*1058c121SJohn Baldwin 
152*1058c121SJohn Baldwin static const struct args reconnect_args[] = {
153*1058c121SJohn Baldwin 	{ arg_string, &opt.dev, "controller-id" },
154*1058c121SJohn Baldwin 	{ arg_string, &opt.address, "address" },
155*1058c121SJohn Baldwin 	{ arg_none, NULL, NULL },
156*1058c121SJohn Baldwin };
157*1058c121SJohn Baldwin 
158*1058c121SJohn Baldwin static struct cmd reconnect_cmd = {
159*1058c121SJohn Baldwin 	.name = "reconnect",
160*1058c121SJohn Baldwin 	.fn = reconnect_fn,
161*1058c121SJohn Baldwin 	.descr = "Reconnect to a fabrics controller",
162*1058c121SJohn Baldwin 	.ctx_size = sizeof(opt),
163*1058c121SJohn Baldwin 	.opts = reconnect_opts,
164*1058c121SJohn Baldwin 	.args = reconnect_args,
165*1058c121SJohn Baldwin };
166*1058c121SJohn Baldwin 
167*1058c121SJohn Baldwin CMD_COMMAND(reconnect_cmd);
168