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