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 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 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 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 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