xref: /freebsd/sbin/nvmecontrol/reconnect.c (revision 365b89e8ea4af34a05f68aa28e77573e89fa00b2)
11058c121SJohn Baldwin /*-
21058c121SJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause
31058c121SJohn Baldwin  *
41058c121SJohn Baldwin  * Copyright (c) 2023-2024 Chelsio Communications, Inc.
51058c121SJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
61058c121SJohn Baldwin  */
71058c121SJohn Baldwin 
8*365b89e8SJohn Baldwin #include <sys/nv.h>
91058c121SJohn Baldwin #include <sys/socket.h>
101058c121SJohn Baldwin #include <err.h>
111058c121SJohn Baldwin #include <libnvmf.h>
121058c121SJohn Baldwin #include <stdlib.h>
131058c121SJohn Baldwin #include <string.h>
141058c121SJohn Baldwin #include <sysexits.h>
151058c121SJohn Baldwin #include <unistd.h>
161058c121SJohn Baldwin 
171058c121SJohn Baldwin #include "nvmecontrol.h"
181058c121SJohn Baldwin #include "fabrics.h"
191058c121SJohn Baldwin 
201058c121SJohn Baldwin /*
211058c121SJohn Baldwin  * See comment about other possible settings in connect.c.
221058c121SJohn Baldwin  */
231058c121SJohn Baldwin 
241058c121SJohn Baldwin static struct options {
251058c121SJohn Baldwin 	const char	*dev;
261058c121SJohn Baldwin 	const char	*transport;
271058c121SJohn Baldwin 	const char	*address;
281058c121SJohn Baldwin 	const char	*hostnqn;
291058c121SJohn Baldwin 	uint32_t	kato;
301058c121SJohn Baldwin 	uint16_t	num_io_queues;
311058c121SJohn Baldwin 	uint16_t	queue_size;
321058c121SJohn Baldwin 	bool		data_digests;
331058c121SJohn Baldwin 	bool		flow_control;
341058c121SJohn Baldwin 	bool		header_digests;
351058c121SJohn Baldwin } opt = {
361058c121SJohn Baldwin 	.dev = NULL,
371058c121SJohn Baldwin 	.transport = "tcp",
381058c121SJohn Baldwin 	.address = NULL,
391058c121SJohn Baldwin 	.hostnqn = NULL,
401058c121SJohn Baldwin 	.kato = NVMF_KATO_DEFAULT / 1000,
411058c121SJohn Baldwin 	.num_io_queues = 1,
421058c121SJohn Baldwin 	.queue_size = 0,
431058c121SJohn Baldwin 	.data_digests = false,
441058c121SJohn Baldwin 	.flow_control = false,
451058c121SJohn Baldwin 	.header_digests = false,
461058c121SJohn Baldwin };
471058c121SJohn Baldwin 
481058c121SJohn Baldwin static void
491058c121SJohn Baldwin tcp_association_params(struct nvmf_association_params *params)
501058c121SJohn Baldwin {
511058c121SJohn Baldwin 	params->tcp.pda = 0;
521058c121SJohn Baldwin 	params->tcp.header_digests = opt.header_digests;
531058c121SJohn Baldwin 	params->tcp.data_digests = opt.data_digests;
541058c121SJohn Baldwin 	/* XXX */
551058c121SJohn Baldwin 	params->tcp.maxr2t = 1;
561058c121SJohn Baldwin }
571058c121SJohn Baldwin 
581058c121SJohn Baldwin static int
591058c121SJohn Baldwin reconnect_nvm_controller(int fd, enum nvmf_trtype trtype, int adrfam,
601058c121SJohn Baldwin     const char *address, const char *port)
611058c121SJohn Baldwin {
621058c121SJohn Baldwin 	struct nvme_controller_data cdata;
631058c121SJohn Baldwin 	struct nvmf_association_params aparams;
64*365b89e8SJohn Baldwin 	nvlist_t *rparams;
651058c121SJohn Baldwin 	struct nvmf_qpair *admin, **io;
661058c121SJohn Baldwin 	int error;
671058c121SJohn Baldwin 
681058c121SJohn Baldwin 	error = nvmf_reconnect_params(fd, &rparams);
691058c121SJohn Baldwin 	if (error != 0) {
701058c121SJohn Baldwin 		warnc(error, "Failed to fetch reconnect parameters");
711058c121SJohn Baldwin 		return (EX_IOERR);
721058c121SJohn Baldwin 	}
731058c121SJohn Baldwin 
74*365b89e8SJohn Baldwin 	if (!nvlist_exists_number(rparams, "cntlid") ||
75*365b89e8SJohn Baldwin 	    !nvlist_exists_string(rparams, "subnqn")) {
76*365b89e8SJohn Baldwin 		nvlist_destroy(rparams);
77*365b89e8SJohn Baldwin 		warnx("Missing required reconnect parameters");
78*365b89e8SJohn Baldwin 		return (EX_IOERR);
79*365b89e8SJohn Baldwin 	}
80*365b89e8SJohn Baldwin 
811058c121SJohn Baldwin 	memset(&aparams, 0, sizeof(aparams));
821058c121SJohn Baldwin 	aparams.sq_flow_control = opt.flow_control;
831058c121SJohn Baldwin 	switch (trtype) {
841058c121SJohn Baldwin 	case NVMF_TRTYPE_TCP:
851058c121SJohn Baldwin 		tcp_association_params(&aparams);
861058c121SJohn Baldwin 		break;
871058c121SJohn Baldwin 	default:
88*365b89e8SJohn Baldwin 		nvlist_destroy(rparams);
891058c121SJohn Baldwin 		warnx("Unsupported transport %s", nvmf_transport_type(trtype));
901058c121SJohn Baldwin 		return (EX_UNAVAILABLE);
911058c121SJohn Baldwin 	}
921058c121SJohn Baldwin 
931058c121SJohn Baldwin 	io = calloc(opt.num_io_queues, sizeof(*io));
941058c121SJohn Baldwin 	error = connect_nvm_queues(&aparams, trtype, adrfam, address, port,
95*365b89e8SJohn Baldwin 	    nvlist_get_number(rparams, "cntlid"),
96*365b89e8SJohn Baldwin 	    nvlist_get_string(rparams, "subnqn"), opt.hostnqn, opt.kato,
97*365b89e8SJohn Baldwin 	    &admin, io, opt.num_io_queues, opt.queue_size, &cdata);
980ac468c7SJohn Baldwin 	if (error != 0) {
990ac468c7SJohn Baldwin 		free(io);
100*365b89e8SJohn Baldwin 		nvlist_destroy(rparams);
1011058c121SJohn Baldwin 		return (error);
1020ac468c7SJohn Baldwin 	}
103*365b89e8SJohn Baldwin 	nvlist_destroy(rparams);
1041058c121SJohn Baldwin 
1051058c121SJohn Baldwin 	error = nvmf_reconnect_host(fd, admin, opt.num_io_queues, io, &cdata);
1061058c121SJohn Baldwin 	if (error != 0) {
1071058c121SJohn Baldwin 		warnc(error, "Failed to handoff queues to kernel");
1080ac468c7SJohn Baldwin 		free(io);
1091058c121SJohn Baldwin 		return (EX_IOERR);
1101058c121SJohn Baldwin 	}
1111058c121SJohn Baldwin 	free(io);
1121058c121SJohn Baldwin 	return (0);
1131058c121SJohn Baldwin }
1141058c121SJohn Baldwin 
1151058c121SJohn Baldwin static void
1161058c121SJohn Baldwin reconnect_fn(const struct cmd *f, int argc, char *argv[])
1171058c121SJohn Baldwin {
1181058c121SJohn Baldwin 	enum nvmf_trtype trtype;
1191058c121SJohn Baldwin 	const char *address, *port;
1201058c121SJohn Baldwin 	char *tofree;
1211058c121SJohn Baldwin 	int error, fd;
1221058c121SJohn Baldwin 
1231058c121SJohn Baldwin 	if (arg_parse(argc, argv, f))
1241058c121SJohn Baldwin 		return;
1251058c121SJohn Baldwin 
1261058c121SJohn Baldwin 	if (strcasecmp(opt.transport, "tcp") == 0) {
1271058c121SJohn Baldwin 		trtype = NVMF_TRTYPE_TCP;
1281058c121SJohn Baldwin 	} else
1291058c121SJohn Baldwin 		errx(EX_USAGE, "Unsupported or invalid transport");
1301058c121SJohn Baldwin 
1311058c121SJohn Baldwin 	nvmf_parse_address(opt.address, &address, &port, &tofree);
1321058c121SJohn Baldwin 
1331058c121SJohn Baldwin 	open_dev(opt.dev, &fd, 1, 1);
1341058c121SJohn Baldwin 	if (port == NULL)
1351058c121SJohn Baldwin 		errx(EX_USAGE, "Explicit port required");
1361058c121SJohn Baldwin 
1371058c121SJohn Baldwin 	error = reconnect_nvm_controller(fd, trtype, AF_UNSPEC, address, port);
1381058c121SJohn Baldwin 	if (error != 0)
1391058c121SJohn Baldwin 		exit(error);
1401058c121SJohn Baldwin 
1411058c121SJohn Baldwin 	close(fd);
1421058c121SJohn Baldwin 	free(tofree);
1431058c121SJohn Baldwin }
1441058c121SJohn Baldwin 
1451058c121SJohn Baldwin static const struct opts reconnect_opts[] = {
1461058c121SJohn Baldwin #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
1471058c121SJohn Baldwin 	OPT("transport", 't', arg_string, opt, transport,
1481058c121SJohn Baldwin 	    "Transport type"),
1491058c121SJohn Baldwin 	OPT("nr-io-queues", 'i', arg_uint16, opt, num_io_queues,
1501058c121SJohn Baldwin 	    "Number of I/O queues"),
1511058c121SJohn Baldwin 	OPT("queue-size", 'Q', arg_uint16, opt, queue_size,
1521058c121SJohn Baldwin 	    "Number of entries in each I/O queue"),
1531058c121SJohn Baldwin 	OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato,
1541058c121SJohn Baldwin 	    "Keep Alive timeout (in seconds)"),
1551058c121SJohn Baldwin 	OPT("hostnqn", 'q', arg_string, opt, hostnqn,
1561058c121SJohn Baldwin 	    "Host NQN"),
1571058c121SJohn Baldwin 	OPT("flow_control", 'F', arg_none, opt, flow_control,
1581058c121SJohn Baldwin 	    "Request SQ flow control"),
1591058c121SJohn Baldwin 	OPT("hdr_digests", 'g', arg_none, opt, header_digests,
1601058c121SJohn Baldwin 	    "Enable TCP PDU header digests"),
1611058c121SJohn Baldwin 	OPT("data_digests", 'G', arg_none, opt, data_digests,
1621058c121SJohn Baldwin 	    "Enable TCP PDU data digests"),
1631058c121SJohn Baldwin 	{ NULL, 0, arg_none, NULL, NULL }
1641058c121SJohn Baldwin };
1651058c121SJohn Baldwin #undef OPT
1661058c121SJohn Baldwin 
1671058c121SJohn Baldwin static const struct args reconnect_args[] = {
1681058c121SJohn Baldwin 	{ arg_string, &opt.dev, "controller-id" },
1691058c121SJohn Baldwin 	{ arg_string, &opt.address, "address" },
1701058c121SJohn Baldwin 	{ arg_none, NULL, NULL },
1711058c121SJohn Baldwin };
1721058c121SJohn Baldwin 
1731058c121SJohn Baldwin static struct cmd reconnect_cmd = {
1741058c121SJohn Baldwin 	.name = "reconnect",
1751058c121SJohn Baldwin 	.fn = reconnect_fn,
1761058c121SJohn Baldwin 	.descr = "Reconnect to a fabrics controller",
1771058c121SJohn Baldwin 	.ctx_size = sizeof(opt),
1781058c121SJohn Baldwin 	.opts = reconnect_opts,
1791058c121SJohn Baldwin 	.args = reconnect_args,
1801058c121SJohn Baldwin };
1811058c121SJohn Baldwin 
1821058c121SJohn Baldwin CMD_COMMAND(reconnect_cmd);
183