11058c121SJohn Baldwin /*- 21058c121SJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 31058c121SJohn Baldwin * 41058c121SJohn Baldwin * Copyright (c) 2023-2024 Chelsio Communications, Inc. 51058c121SJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 61058c121SJohn Baldwin */ 71058c121SJohn Baldwin 8*365b89e8SJohn Baldwin #include <sys/nv.h> 91058c121SJohn Baldwin #include <sys/socket.h> 101058c121SJohn Baldwin #include <err.h> 111058c121SJohn Baldwin #include <libnvmf.h> 121058c121SJohn Baldwin #include <stdlib.h> 131058c121SJohn Baldwin #include <string.h> 141058c121SJohn Baldwin #include <sysexits.h> 151058c121SJohn Baldwin #include <unistd.h> 161058c121SJohn Baldwin 171058c121SJohn Baldwin #include "nvmecontrol.h" 181058c121SJohn Baldwin #include "fabrics.h" 191058c121SJohn Baldwin 201058c121SJohn Baldwin /* 211058c121SJohn Baldwin * See comment about other possible settings in connect.c. 221058c121SJohn Baldwin */ 231058c121SJohn Baldwin 241058c121SJohn Baldwin static struct options { 251058c121SJohn Baldwin const char *dev; 261058c121SJohn Baldwin const char *transport; 271058c121SJohn Baldwin const char *address; 281058c121SJohn Baldwin const char *hostnqn; 291058c121SJohn Baldwin uint32_t kato; 301058c121SJohn Baldwin uint16_t num_io_queues; 311058c121SJohn Baldwin uint16_t queue_size; 321058c121SJohn Baldwin bool data_digests; 331058c121SJohn Baldwin bool flow_control; 341058c121SJohn Baldwin bool header_digests; 351058c121SJohn Baldwin } opt = { 361058c121SJohn Baldwin .dev = NULL, 371058c121SJohn Baldwin .transport = "tcp", 381058c121SJohn Baldwin .address = NULL, 391058c121SJohn Baldwin .hostnqn = NULL, 401058c121SJohn Baldwin .kato = NVMF_KATO_DEFAULT / 1000, 411058c121SJohn Baldwin .num_io_queues = 1, 421058c121SJohn Baldwin .queue_size = 0, 431058c121SJohn Baldwin .data_digests = false, 441058c121SJohn Baldwin .flow_control = false, 451058c121SJohn Baldwin .header_digests = false, 461058c121SJohn Baldwin }; 471058c121SJohn Baldwin 481058c121SJohn Baldwin static void 491058c121SJohn Baldwin tcp_association_params(struct nvmf_association_params *params) 501058c121SJohn Baldwin { 511058c121SJohn Baldwin params->tcp.pda = 0; 521058c121SJohn Baldwin params->tcp.header_digests = opt.header_digests; 531058c121SJohn Baldwin params->tcp.data_digests = opt.data_digests; 541058c121SJohn Baldwin /* XXX */ 551058c121SJohn Baldwin params->tcp.maxr2t = 1; 561058c121SJohn Baldwin } 571058c121SJohn Baldwin 581058c121SJohn Baldwin static int 591058c121SJohn Baldwin reconnect_nvm_controller(int fd, enum nvmf_trtype trtype, int adrfam, 601058c121SJohn Baldwin const char *address, const char *port) 611058c121SJohn Baldwin { 621058c121SJohn Baldwin struct nvme_controller_data cdata; 631058c121SJohn Baldwin struct nvmf_association_params aparams; 64*365b89e8SJohn Baldwin nvlist_t *rparams; 651058c121SJohn Baldwin struct nvmf_qpair *admin, **io; 661058c121SJohn Baldwin int error; 671058c121SJohn Baldwin 681058c121SJohn Baldwin error = nvmf_reconnect_params(fd, &rparams); 691058c121SJohn Baldwin if (error != 0) { 701058c121SJohn Baldwin warnc(error, "Failed to fetch reconnect parameters"); 711058c121SJohn Baldwin return (EX_IOERR); 721058c121SJohn Baldwin } 731058c121SJohn Baldwin 74*365b89e8SJohn Baldwin if (!nvlist_exists_number(rparams, "cntlid") || 75*365b89e8SJohn Baldwin !nvlist_exists_string(rparams, "subnqn")) { 76*365b89e8SJohn Baldwin nvlist_destroy(rparams); 77*365b89e8SJohn Baldwin warnx("Missing required reconnect parameters"); 78*365b89e8SJohn Baldwin return (EX_IOERR); 79*365b89e8SJohn Baldwin } 80*365b89e8SJohn Baldwin 811058c121SJohn Baldwin memset(&aparams, 0, sizeof(aparams)); 821058c121SJohn Baldwin aparams.sq_flow_control = opt.flow_control; 831058c121SJohn Baldwin switch (trtype) { 841058c121SJohn Baldwin case NVMF_TRTYPE_TCP: 851058c121SJohn Baldwin tcp_association_params(&aparams); 861058c121SJohn Baldwin break; 871058c121SJohn Baldwin default: 88*365b89e8SJohn Baldwin nvlist_destroy(rparams); 891058c121SJohn Baldwin warnx("Unsupported transport %s", nvmf_transport_type(trtype)); 901058c121SJohn Baldwin return (EX_UNAVAILABLE); 911058c121SJohn Baldwin } 921058c121SJohn Baldwin 931058c121SJohn Baldwin io = calloc(opt.num_io_queues, sizeof(*io)); 941058c121SJohn Baldwin error = connect_nvm_queues(&aparams, trtype, adrfam, address, port, 95*365b89e8SJohn Baldwin nvlist_get_number(rparams, "cntlid"), 96*365b89e8SJohn Baldwin nvlist_get_string(rparams, "subnqn"), opt.hostnqn, opt.kato, 97*365b89e8SJohn Baldwin &admin, io, opt.num_io_queues, opt.queue_size, &cdata); 980ac468c7SJohn Baldwin if (error != 0) { 990ac468c7SJohn Baldwin free(io); 100*365b89e8SJohn Baldwin nvlist_destroy(rparams); 1011058c121SJohn Baldwin return (error); 1020ac468c7SJohn Baldwin } 103*365b89e8SJohn Baldwin nvlist_destroy(rparams); 1041058c121SJohn Baldwin 1051058c121SJohn Baldwin error = nvmf_reconnect_host(fd, admin, opt.num_io_queues, io, &cdata); 1061058c121SJohn Baldwin if (error != 0) { 1071058c121SJohn Baldwin warnc(error, "Failed to handoff queues to kernel"); 1080ac468c7SJohn Baldwin free(io); 1091058c121SJohn Baldwin return (EX_IOERR); 1101058c121SJohn Baldwin } 1111058c121SJohn Baldwin free(io); 1121058c121SJohn Baldwin return (0); 1131058c121SJohn Baldwin } 1141058c121SJohn Baldwin 1151058c121SJohn Baldwin static void 1161058c121SJohn Baldwin reconnect_fn(const struct cmd *f, int argc, char *argv[]) 1171058c121SJohn Baldwin { 1181058c121SJohn Baldwin enum nvmf_trtype trtype; 1191058c121SJohn Baldwin const char *address, *port; 1201058c121SJohn Baldwin char *tofree; 1211058c121SJohn Baldwin int error, fd; 1221058c121SJohn Baldwin 1231058c121SJohn Baldwin if (arg_parse(argc, argv, f)) 1241058c121SJohn Baldwin return; 1251058c121SJohn Baldwin 1261058c121SJohn Baldwin if (strcasecmp(opt.transport, "tcp") == 0) { 1271058c121SJohn Baldwin trtype = NVMF_TRTYPE_TCP; 1281058c121SJohn Baldwin } else 1291058c121SJohn Baldwin errx(EX_USAGE, "Unsupported or invalid transport"); 1301058c121SJohn Baldwin 1311058c121SJohn Baldwin nvmf_parse_address(opt.address, &address, &port, &tofree); 1321058c121SJohn Baldwin 1331058c121SJohn Baldwin open_dev(opt.dev, &fd, 1, 1); 1341058c121SJohn Baldwin if (port == NULL) 1351058c121SJohn Baldwin errx(EX_USAGE, "Explicit port required"); 1361058c121SJohn Baldwin 1371058c121SJohn Baldwin error = reconnect_nvm_controller(fd, trtype, AF_UNSPEC, address, port); 1381058c121SJohn Baldwin if (error != 0) 1391058c121SJohn Baldwin exit(error); 1401058c121SJohn Baldwin 1411058c121SJohn Baldwin close(fd); 1421058c121SJohn Baldwin free(tofree); 1431058c121SJohn Baldwin } 1441058c121SJohn Baldwin 1451058c121SJohn Baldwin static const struct opts reconnect_opts[] = { 1461058c121SJohn Baldwin #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } 1471058c121SJohn Baldwin OPT("transport", 't', arg_string, opt, transport, 1481058c121SJohn Baldwin "Transport type"), 1491058c121SJohn Baldwin OPT("nr-io-queues", 'i', arg_uint16, opt, num_io_queues, 1501058c121SJohn Baldwin "Number of I/O queues"), 1511058c121SJohn Baldwin OPT("queue-size", 'Q', arg_uint16, opt, queue_size, 1521058c121SJohn Baldwin "Number of entries in each I/O queue"), 1531058c121SJohn Baldwin OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato, 1541058c121SJohn Baldwin "Keep Alive timeout (in seconds)"), 1551058c121SJohn Baldwin OPT("hostnqn", 'q', arg_string, opt, hostnqn, 1561058c121SJohn Baldwin "Host NQN"), 1571058c121SJohn Baldwin OPT("flow_control", 'F', arg_none, opt, flow_control, 1581058c121SJohn Baldwin "Request SQ flow control"), 1591058c121SJohn Baldwin OPT("hdr_digests", 'g', arg_none, opt, header_digests, 1601058c121SJohn Baldwin "Enable TCP PDU header digests"), 1611058c121SJohn Baldwin OPT("data_digests", 'G', arg_none, opt, data_digests, 1621058c121SJohn Baldwin "Enable TCP PDU data digests"), 1631058c121SJohn Baldwin { NULL, 0, arg_none, NULL, NULL } 1641058c121SJohn Baldwin }; 1651058c121SJohn Baldwin #undef OPT 1661058c121SJohn Baldwin 1671058c121SJohn Baldwin static const struct args reconnect_args[] = { 1681058c121SJohn Baldwin { arg_string, &opt.dev, "controller-id" }, 1691058c121SJohn Baldwin { arg_string, &opt.address, "address" }, 1701058c121SJohn Baldwin { arg_none, NULL, NULL }, 1711058c121SJohn Baldwin }; 1721058c121SJohn Baldwin 1731058c121SJohn Baldwin static struct cmd reconnect_cmd = { 1741058c121SJohn Baldwin .name = "reconnect", 1751058c121SJohn Baldwin .fn = reconnect_fn, 1761058c121SJohn Baldwin .descr = "Reconnect to a fabrics controller", 1771058c121SJohn Baldwin .ctx_size = sizeof(opt), 1781058c121SJohn Baldwin .opts = reconnect_opts, 1791058c121SJohn Baldwin .args = reconnect_args, 1801058c121SJohn Baldwin }; 1811058c121SJohn Baldwin 1821058c121SJohn Baldwin CMD_COMMAND(reconnect_cmd); 183