1*1058c121SJohn Baldwin /*- 2*1058c121SJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 3*1058c121SJohn Baldwin * 4*1058c121SJohn Baldwin * Copyright (c) 2023-2024 Chelsio Communications, Inc. 5*1058c121SJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 6*1058c121SJohn Baldwin */ 7*1058c121SJohn Baldwin 8*1058c121SJohn Baldwin #include <sys/socket.h> 9*1058c121SJohn Baldwin #include <err.h> 10*1058c121SJohn Baldwin #include <libnvmf.h> 11*1058c121SJohn Baldwin #include <stdlib.h> 12*1058c121SJohn Baldwin #include <string.h> 13*1058c121SJohn Baldwin #include <sysexits.h> 14*1058c121SJohn Baldwin #include <unistd.h> 15*1058c121SJohn Baldwin 16*1058c121SJohn Baldwin #include "nvmecontrol.h" 17*1058c121SJohn Baldwin #include "fabrics.h" 18*1058c121SJohn Baldwin 19*1058c121SJohn Baldwin /* 20*1058c121SJohn Baldwin * See comment about other possible settings in connect.c. 21*1058c121SJohn Baldwin */ 22*1058c121SJohn Baldwin 23*1058c121SJohn Baldwin static struct options { 24*1058c121SJohn Baldwin const char *dev; 25*1058c121SJohn Baldwin const char *transport; 26*1058c121SJohn Baldwin const char *address; 27*1058c121SJohn Baldwin const char *hostnqn; 28*1058c121SJohn Baldwin uint32_t kato; 29*1058c121SJohn Baldwin uint16_t num_io_queues; 30*1058c121SJohn Baldwin uint16_t queue_size; 31*1058c121SJohn Baldwin bool data_digests; 32*1058c121SJohn Baldwin bool flow_control; 33*1058c121SJohn Baldwin bool header_digests; 34*1058c121SJohn Baldwin } opt = { 35*1058c121SJohn Baldwin .dev = NULL, 36*1058c121SJohn Baldwin .transport = "tcp", 37*1058c121SJohn Baldwin .address = NULL, 38*1058c121SJohn Baldwin .hostnqn = NULL, 39*1058c121SJohn Baldwin .kato = NVMF_KATO_DEFAULT / 1000, 40*1058c121SJohn Baldwin .num_io_queues = 1, 41*1058c121SJohn Baldwin .queue_size = 0, 42*1058c121SJohn Baldwin .data_digests = false, 43*1058c121SJohn Baldwin .flow_control = false, 44*1058c121SJohn Baldwin .header_digests = false, 45*1058c121SJohn Baldwin }; 46*1058c121SJohn Baldwin 47*1058c121SJohn Baldwin static void 48*1058c121SJohn Baldwin tcp_association_params(struct nvmf_association_params *params) 49*1058c121SJohn Baldwin { 50*1058c121SJohn Baldwin params->tcp.pda = 0; 51*1058c121SJohn Baldwin params->tcp.header_digests = opt.header_digests; 52*1058c121SJohn Baldwin params->tcp.data_digests = opt.data_digests; 53*1058c121SJohn Baldwin /* XXX */ 54*1058c121SJohn Baldwin params->tcp.maxr2t = 1; 55*1058c121SJohn Baldwin } 56*1058c121SJohn Baldwin 57*1058c121SJohn Baldwin static int 58*1058c121SJohn Baldwin reconnect_nvm_controller(int fd, enum nvmf_trtype trtype, int adrfam, 59*1058c121SJohn Baldwin const char *address, const char *port) 60*1058c121SJohn Baldwin { 61*1058c121SJohn Baldwin struct nvme_controller_data cdata; 62*1058c121SJohn Baldwin struct nvmf_association_params aparams; 63*1058c121SJohn Baldwin struct nvmf_reconnect_params rparams; 64*1058c121SJohn Baldwin struct nvmf_qpair *admin, **io; 65*1058c121SJohn Baldwin int error; 66*1058c121SJohn Baldwin 67*1058c121SJohn Baldwin error = nvmf_reconnect_params(fd, &rparams); 68*1058c121SJohn Baldwin if (error != 0) { 69*1058c121SJohn Baldwin warnc(error, "Failed to fetch reconnect parameters"); 70*1058c121SJohn Baldwin return (EX_IOERR); 71*1058c121SJohn Baldwin } 72*1058c121SJohn Baldwin 73*1058c121SJohn Baldwin memset(&aparams, 0, sizeof(aparams)); 74*1058c121SJohn Baldwin aparams.sq_flow_control = opt.flow_control; 75*1058c121SJohn Baldwin switch (trtype) { 76*1058c121SJohn Baldwin case NVMF_TRTYPE_TCP: 77*1058c121SJohn Baldwin tcp_association_params(&aparams); 78*1058c121SJohn Baldwin break; 79*1058c121SJohn Baldwin default: 80*1058c121SJohn Baldwin warnx("Unsupported transport %s", nvmf_transport_type(trtype)); 81*1058c121SJohn Baldwin return (EX_UNAVAILABLE); 82*1058c121SJohn Baldwin } 83*1058c121SJohn Baldwin 84*1058c121SJohn Baldwin io = calloc(opt.num_io_queues, sizeof(*io)); 85*1058c121SJohn Baldwin error = connect_nvm_queues(&aparams, trtype, adrfam, address, port, 86*1058c121SJohn Baldwin rparams.cntlid, rparams.subnqn, opt.hostnqn, opt.kato, &admin, io, 87*1058c121SJohn Baldwin opt.num_io_queues, opt.queue_size, &cdata); 88*1058c121SJohn Baldwin if (error != 0) 89*1058c121SJohn Baldwin return (error); 90*1058c121SJohn Baldwin 91*1058c121SJohn Baldwin error = nvmf_reconnect_host(fd, admin, opt.num_io_queues, io, &cdata); 92*1058c121SJohn Baldwin if (error != 0) { 93*1058c121SJohn Baldwin warnc(error, "Failed to handoff queues to kernel"); 94*1058c121SJohn Baldwin return (EX_IOERR); 95*1058c121SJohn Baldwin } 96*1058c121SJohn Baldwin free(io); 97*1058c121SJohn Baldwin return (0); 98*1058c121SJohn Baldwin } 99*1058c121SJohn Baldwin 100*1058c121SJohn Baldwin static void 101*1058c121SJohn Baldwin reconnect_fn(const struct cmd *f, int argc, char *argv[]) 102*1058c121SJohn Baldwin { 103*1058c121SJohn Baldwin enum nvmf_trtype trtype; 104*1058c121SJohn Baldwin const char *address, *port; 105*1058c121SJohn Baldwin char *tofree; 106*1058c121SJohn Baldwin int error, fd; 107*1058c121SJohn Baldwin 108*1058c121SJohn Baldwin if (arg_parse(argc, argv, f)) 109*1058c121SJohn Baldwin return; 110*1058c121SJohn Baldwin 111*1058c121SJohn Baldwin if (strcasecmp(opt.transport, "tcp") == 0) { 112*1058c121SJohn Baldwin trtype = NVMF_TRTYPE_TCP; 113*1058c121SJohn Baldwin } else 114*1058c121SJohn Baldwin errx(EX_USAGE, "Unsupported or invalid transport"); 115*1058c121SJohn Baldwin 116*1058c121SJohn Baldwin nvmf_parse_address(opt.address, &address, &port, &tofree); 117*1058c121SJohn Baldwin 118*1058c121SJohn Baldwin open_dev(opt.dev, &fd, 1, 1); 119*1058c121SJohn Baldwin if (port == NULL) 120*1058c121SJohn Baldwin errx(EX_USAGE, "Explicit port required"); 121*1058c121SJohn Baldwin 122*1058c121SJohn Baldwin error = reconnect_nvm_controller(fd, trtype, AF_UNSPEC, address, port); 123*1058c121SJohn Baldwin if (error != 0) 124*1058c121SJohn Baldwin exit(error); 125*1058c121SJohn Baldwin 126*1058c121SJohn Baldwin close(fd); 127*1058c121SJohn Baldwin free(tofree); 128*1058c121SJohn Baldwin } 129*1058c121SJohn Baldwin 130*1058c121SJohn Baldwin static const struct opts reconnect_opts[] = { 131*1058c121SJohn Baldwin #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } 132*1058c121SJohn Baldwin OPT("transport", 't', arg_string, opt, transport, 133*1058c121SJohn Baldwin "Transport type"), 134*1058c121SJohn Baldwin OPT("nr-io-queues", 'i', arg_uint16, opt, num_io_queues, 135*1058c121SJohn Baldwin "Number of I/O queues"), 136*1058c121SJohn Baldwin OPT("queue-size", 'Q', arg_uint16, opt, queue_size, 137*1058c121SJohn Baldwin "Number of entries in each I/O queue"), 138*1058c121SJohn Baldwin OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato, 139*1058c121SJohn Baldwin "Keep Alive timeout (in seconds)"), 140*1058c121SJohn Baldwin OPT("hostnqn", 'q', arg_string, opt, hostnqn, 141*1058c121SJohn Baldwin "Host NQN"), 142*1058c121SJohn Baldwin OPT("flow_control", 'F', arg_none, opt, flow_control, 143*1058c121SJohn Baldwin "Request SQ flow control"), 144*1058c121SJohn Baldwin OPT("hdr_digests", 'g', arg_none, opt, header_digests, 145*1058c121SJohn Baldwin "Enable TCP PDU header digests"), 146*1058c121SJohn Baldwin OPT("data_digests", 'G', arg_none, opt, data_digests, 147*1058c121SJohn Baldwin "Enable TCP PDU data digests"), 148*1058c121SJohn Baldwin { NULL, 0, arg_none, NULL, NULL } 149*1058c121SJohn Baldwin }; 150*1058c121SJohn Baldwin #undef OPT 151*1058c121SJohn Baldwin 152*1058c121SJohn Baldwin static const struct args reconnect_args[] = { 153*1058c121SJohn Baldwin { arg_string, &opt.dev, "controller-id" }, 154*1058c121SJohn Baldwin { arg_string, &opt.address, "address" }, 155*1058c121SJohn Baldwin { arg_none, NULL, NULL }, 156*1058c121SJohn Baldwin }; 157*1058c121SJohn Baldwin 158*1058c121SJohn Baldwin static struct cmd reconnect_cmd = { 159*1058c121SJohn Baldwin .name = "reconnect", 160*1058c121SJohn Baldwin .fn = reconnect_fn, 161*1058c121SJohn Baldwin .descr = "Reconnect to a fabrics controller", 162*1058c121SJohn Baldwin .ctx_size = sizeof(opt), 163*1058c121SJohn Baldwin .opts = reconnect_opts, 164*1058c121SJohn Baldwin .args = reconnect_args, 165*1058c121SJohn Baldwin }; 166*1058c121SJohn Baldwin 167*1058c121SJohn Baldwin CMD_COMMAND(reconnect_cmd); 168