xref: /freebsd/usr.sbin/nvmfd/ctl.c (revision a8089ea5aee578e08acab2438e82fc9a9ae50ed8)
1*a8089ea5SJohn Baldwin /*-
2*a8089ea5SJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause
3*a8089ea5SJohn Baldwin  *
4*a8089ea5SJohn Baldwin  * Copyright (c) 2023 Chelsio Communications, Inc.
5*a8089ea5SJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
6*a8089ea5SJohn Baldwin  */
7*a8089ea5SJohn Baldwin 
8*a8089ea5SJohn Baldwin #include <sys/param.h>
9*a8089ea5SJohn Baldwin #include <sys/linker.h>
10*a8089ea5SJohn Baldwin #include <sys/nv.h>
11*a8089ea5SJohn Baldwin #include <sys/time.h>
12*a8089ea5SJohn Baldwin #include <err.h>
13*a8089ea5SJohn Baldwin #include <errno.h>
14*a8089ea5SJohn Baldwin #include <fcntl.h>
15*a8089ea5SJohn Baldwin #include <libnvmf.h>
16*a8089ea5SJohn Baldwin #include <string.h>
17*a8089ea5SJohn Baldwin 
18*a8089ea5SJohn Baldwin #include <cam/ctl/ctl.h>
19*a8089ea5SJohn Baldwin #include <cam/ctl/ctl_io.h>
20*a8089ea5SJohn Baldwin #include <cam/ctl/ctl_ioctl.h>
21*a8089ea5SJohn Baldwin 
22*a8089ea5SJohn Baldwin #include "internal.h"
23*a8089ea5SJohn Baldwin 
24*a8089ea5SJohn Baldwin static int ctl_fd = -1;
25*a8089ea5SJohn Baldwin static int ctl_port;
26*a8089ea5SJohn Baldwin 
27*a8089ea5SJohn Baldwin static void
28*a8089ea5SJohn Baldwin open_ctl(void)
29*a8089ea5SJohn Baldwin {
30*a8089ea5SJohn Baldwin 	if (ctl_fd > 0)
31*a8089ea5SJohn Baldwin 		return;
32*a8089ea5SJohn Baldwin 
33*a8089ea5SJohn Baldwin 	ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
34*a8089ea5SJohn Baldwin 	if (ctl_fd == -1 && errno == ENOENT) {
35*a8089ea5SJohn Baldwin 		if (kldload("ctl") == -1)
36*a8089ea5SJohn Baldwin 			err(1, "Failed to load ctl.ko");
37*a8089ea5SJohn Baldwin 		ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
38*a8089ea5SJohn Baldwin 	}
39*a8089ea5SJohn Baldwin 	if (ctl_fd == -1)
40*a8089ea5SJohn Baldwin 		err(1, "Failed to open %s", CTL_DEFAULT_DEV);
41*a8089ea5SJohn Baldwin }
42*a8089ea5SJohn Baldwin 
43*a8089ea5SJohn Baldwin void
44*a8089ea5SJohn Baldwin init_ctl_port(const char *subnqn, const struct nvmf_association_params *params)
45*a8089ea5SJohn Baldwin {
46*a8089ea5SJohn Baldwin 	char result_buf[256];
47*a8089ea5SJohn Baldwin 	struct ctl_port_entry entry;
48*a8089ea5SJohn Baldwin 	struct ctl_req req;
49*a8089ea5SJohn Baldwin 	nvlist_t *nvl;
50*a8089ea5SJohn Baldwin 
51*a8089ea5SJohn Baldwin 	open_ctl();
52*a8089ea5SJohn Baldwin 
53*a8089ea5SJohn Baldwin 	nvl = nvlist_create(0);
54*a8089ea5SJohn Baldwin 
55*a8089ea5SJohn Baldwin 	nvlist_add_string(nvl, "subnqn", subnqn);
56*a8089ea5SJohn Baldwin 
57*a8089ea5SJohn Baldwin 	/* XXX: Hardcoded in discovery.c */
58*a8089ea5SJohn Baldwin 	nvlist_add_stringf(nvl, "portid", "%u", 1);
59*a8089ea5SJohn Baldwin 
60*a8089ea5SJohn Baldwin 	nvlist_add_stringf(nvl, "max_io_qsize", "%u", params->max_io_qsize);
61*a8089ea5SJohn Baldwin 
62*a8089ea5SJohn Baldwin 	memset(&req, 0, sizeof(req));
63*a8089ea5SJohn Baldwin 	strlcpy(req.driver, "nvmf", sizeof(req.driver));
64*a8089ea5SJohn Baldwin 	req.reqtype = CTL_REQ_CREATE;
65*a8089ea5SJohn Baldwin 	req.args = nvlist_pack(nvl, &req.args_len);
66*a8089ea5SJohn Baldwin 	if (req.args == NULL)
67*a8089ea5SJohn Baldwin 		errx(1, "Failed to pack nvlist for CTL_PORT/CTL_REQ_CREATE");
68*a8089ea5SJohn Baldwin 	req.result = result_buf;
69*a8089ea5SJohn Baldwin 	req.result_len = sizeof(result_buf);
70*a8089ea5SJohn Baldwin 	if (ioctl(ctl_fd, CTL_PORT_REQ, &req) != 0)
71*a8089ea5SJohn Baldwin 		err(1, "ioctl(CTL_PORT/CTL_REQ_CREATE)");
72*a8089ea5SJohn Baldwin 	if (req.status == CTL_LUN_ERROR)
73*a8089ea5SJohn Baldwin 		errx(1, "Failed to create CTL port: %s", req.error_str);
74*a8089ea5SJohn Baldwin 	if (req.status != CTL_LUN_OK)
75*a8089ea5SJohn Baldwin 		errx(1, "Failed to create CTL port: %d", req.status);
76*a8089ea5SJohn Baldwin 
77*a8089ea5SJohn Baldwin 	nvlist_destroy(nvl);
78*a8089ea5SJohn Baldwin 	nvl = nvlist_unpack(result_buf, req.result_len, 0);
79*a8089ea5SJohn Baldwin 	if (nvl == NULL)
80*a8089ea5SJohn Baldwin 		errx(1, "Failed to unpack nvlist from CTL_PORT/CTL_REQ_CREATE");
81*a8089ea5SJohn Baldwin 
82*a8089ea5SJohn Baldwin 	ctl_port = nvlist_get_number(nvl, "port_id");
83*a8089ea5SJohn Baldwin 	nvlist_destroy(nvl);
84*a8089ea5SJohn Baldwin 
85*a8089ea5SJohn Baldwin 	memset(&entry, 0, sizeof(entry));
86*a8089ea5SJohn Baldwin 	entry.targ_port = ctl_port;
87*a8089ea5SJohn Baldwin 	if (ioctl(ctl_fd, CTL_ENABLE_PORT, &entry) != 0)
88*a8089ea5SJohn Baldwin 		errx(1, "ioctl(CTL_ENABLE_PORT)");
89*a8089ea5SJohn Baldwin }
90*a8089ea5SJohn Baldwin 
91*a8089ea5SJohn Baldwin void
92*a8089ea5SJohn Baldwin shutdown_ctl_port(const char *subnqn)
93*a8089ea5SJohn Baldwin {
94*a8089ea5SJohn Baldwin 	struct ctl_req req;
95*a8089ea5SJohn Baldwin 	nvlist_t *nvl;
96*a8089ea5SJohn Baldwin 
97*a8089ea5SJohn Baldwin 	open_ctl();
98*a8089ea5SJohn Baldwin 
99*a8089ea5SJohn Baldwin 	nvl = nvlist_create(0);
100*a8089ea5SJohn Baldwin 
101*a8089ea5SJohn Baldwin 	nvlist_add_string(nvl, "subnqn", subnqn);
102*a8089ea5SJohn Baldwin 
103*a8089ea5SJohn Baldwin 	memset(&req, 0, sizeof(req));
104*a8089ea5SJohn Baldwin 	strlcpy(req.driver, "nvmf", sizeof(req.driver));
105*a8089ea5SJohn Baldwin 	req.reqtype = CTL_REQ_REMOVE;
106*a8089ea5SJohn Baldwin 	req.args = nvlist_pack(nvl, &req.args_len);
107*a8089ea5SJohn Baldwin 	if (req.args == NULL)
108*a8089ea5SJohn Baldwin 		errx(1, "Failed to pack nvlist for CTL_PORT/CTL_REQ_REMOVE");
109*a8089ea5SJohn Baldwin 	if (ioctl(ctl_fd, CTL_PORT_REQ, &req) != 0)
110*a8089ea5SJohn Baldwin 		err(1, "ioctl(CTL_PORT/CTL_REQ_REMOVE)");
111*a8089ea5SJohn Baldwin 	if (req.status == CTL_LUN_ERROR)
112*a8089ea5SJohn Baldwin 		errx(1, "Failed to remove CTL port: %s", req.error_str);
113*a8089ea5SJohn Baldwin 	if (req.status != CTL_LUN_OK)
114*a8089ea5SJohn Baldwin 		errx(1, "Failed to remove CTL port: %d", req.status);
115*a8089ea5SJohn Baldwin 
116*a8089ea5SJohn Baldwin 	nvlist_destroy(nvl);
117*a8089ea5SJohn Baldwin }
118*a8089ea5SJohn Baldwin 
119*a8089ea5SJohn Baldwin void
120*a8089ea5SJohn Baldwin ctl_handoff_qpair(struct nvmf_qpair *qp,
121*a8089ea5SJohn Baldwin     const struct nvmf_fabric_connect_cmd *cmd,
122*a8089ea5SJohn Baldwin     const struct nvmf_fabric_connect_data *data)
123*a8089ea5SJohn Baldwin {
124*a8089ea5SJohn Baldwin 	struct ctl_nvmf req;
125*a8089ea5SJohn Baldwin 	int error;
126*a8089ea5SJohn Baldwin 
127*a8089ea5SJohn Baldwin 	memset(&req, 0, sizeof(req));
128*a8089ea5SJohn Baldwin 	req.type = CTL_NVMF_HANDOFF;
129*a8089ea5SJohn Baldwin 	error = nvmf_handoff_controller_qpair(qp, &req.data.handoff);
130*a8089ea5SJohn Baldwin 	if (error != 0) {
131*a8089ea5SJohn Baldwin 		warnc(error, "Failed to prepare qpair for handoff");
132*a8089ea5SJohn Baldwin 		return;
133*a8089ea5SJohn Baldwin 	}
134*a8089ea5SJohn Baldwin 
135*a8089ea5SJohn Baldwin 	req.data.handoff.cmd = cmd;
136*a8089ea5SJohn Baldwin 	req.data.handoff.data = data;
137*a8089ea5SJohn Baldwin 	if (ioctl(ctl_fd, CTL_NVMF, &req) != 0)
138*a8089ea5SJohn Baldwin 		warn("ioctl(CTL_NVMF/CTL_NVMF_HANDOFF)");
139*a8089ea5SJohn Baldwin }
140