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