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 81058c121SJohn Baldwin #include <sys/socket.h> 91058c121SJohn Baldwin #include <err.h> 101058c121SJohn Baldwin #include <libnvmf.h> 111058c121SJohn Baldwin #include <stdlib.h> 121058c121SJohn Baldwin #include <string.h> 131058c121SJohn Baldwin #include <sysexits.h> 141058c121SJohn Baldwin #include <unistd.h> 151058c121SJohn Baldwin 161058c121SJohn Baldwin #include "nvmecontrol.h" 171058c121SJohn Baldwin #include "fabrics.h" 181058c121SJohn Baldwin 191058c121SJohn Baldwin /* 201058c121SJohn Baldwin * See comment about other possible settings in connect.c. 211058c121SJohn Baldwin */ 221058c121SJohn Baldwin 231058c121SJohn Baldwin static struct options { 241058c121SJohn Baldwin const char *dev; 251058c121SJohn Baldwin const char *transport; 261058c121SJohn Baldwin const char *address; 271058c121SJohn Baldwin const char *hostnqn; 281058c121SJohn Baldwin uint32_t kato; 291058c121SJohn Baldwin uint16_t num_io_queues; 301058c121SJohn Baldwin uint16_t queue_size; 311058c121SJohn Baldwin bool data_digests; 321058c121SJohn Baldwin bool flow_control; 331058c121SJohn Baldwin bool header_digests; 341058c121SJohn Baldwin } opt = { 351058c121SJohn Baldwin .dev = NULL, 361058c121SJohn Baldwin .transport = "tcp", 371058c121SJohn Baldwin .address = NULL, 381058c121SJohn Baldwin .hostnqn = NULL, 391058c121SJohn Baldwin .kato = NVMF_KATO_DEFAULT / 1000, 401058c121SJohn Baldwin .num_io_queues = 1, 411058c121SJohn Baldwin .queue_size = 0, 421058c121SJohn Baldwin .data_digests = false, 431058c121SJohn Baldwin .flow_control = false, 441058c121SJohn Baldwin .header_digests = false, 451058c121SJohn Baldwin }; 461058c121SJohn Baldwin 471058c121SJohn Baldwin static void 481058c121SJohn Baldwin tcp_association_params(struct nvmf_association_params *params) 491058c121SJohn Baldwin { 501058c121SJohn Baldwin params->tcp.pda = 0; 511058c121SJohn Baldwin params->tcp.header_digests = opt.header_digests; 521058c121SJohn Baldwin params->tcp.data_digests = opt.data_digests; 531058c121SJohn Baldwin /* XXX */ 541058c121SJohn Baldwin params->tcp.maxr2t = 1; 551058c121SJohn Baldwin } 561058c121SJohn Baldwin 571058c121SJohn Baldwin static int 581058c121SJohn Baldwin reconnect_nvm_controller(int fd, enum nvmf_trtype trtype, int adrfam, 591058c121SJohn Baldwin const char *address, const char *port) 601058c121SJohn Baldwin { 611058c121SJohn Baldwin struct nvme_controller_data cdata; 621058c121SJohn Baldwin struct nvmf_association_params aparams; 631058c121SJohn Baldwin struct nvmf_reconnect_params rparams; 641058c121SJohn Baldwin struct nvmf_qpair *admin, **io; 651058c121SJohn Baldwin int error; 661058c121SJohn Baldwin 671058c121SJohn Baldwin error = nvmf_reconnect_params(fd, &rparams); 681058c121SJohn Baldwin if (error != 0) { 691058c121SJohn Baldwin warnc(error, "Failed to fetch reconnect parameters"); 701058c121SJohn Baldwin return (EX_IOERR); 711058c121SJohn Baldwin } 721058c121SJohn Baldwin 731058c121SJohn Baldwin memset(&aparams, 0, sizeof(aparams)); 741058c121SJohn Baldwin aparams.sq_flow_control = opt.flow_control; 751058c121SJohn Baldwin switch (trtype) { 761058c121SJohn Baldwin case NVMF_TRTYPE_TCP: 771058c121SJohn Baldwin tcp_association_params(&aparams); 781058c121SJohn Baldwin break; 791058c121SJohn Baldwin default: 801058c121SJohn Baldwin warnx("Unsupported transport %s", nvmf_transport_type(trtype)); 811058c121SJohn Baldwin return (EX_UNAVAILABLE); 821058c121SJohn Baldwin } 831058c121SJohn Baldwin 841058c121SJohn Baldwin io = calloc(opt.num_io_queues, sizeof(*io)); 851058c121SJohn Baldwin error = connect_nvm_queues(&aparams, trtype, adrfam, address, port, 861058c121SJohn Baldwin rparams.cntlid, rparams.subnqn, opt.hostnqn, opt.kato, &admin, io, 871058c121SJohn Baldwin opt.num_io_queues, opt.queue_size, &cdata); 88*0ac468c7SJohn Baldwin if (error != 0) { 89*0ac468c7SJohn Baldwin free(io); 901058c121SJohn Baldwin return (error); 91*0ac468c7SJohn Baldwin } 921058c121SJohn Baldwin 931058c121SJohn Baldwin error = nvmf_reconnect_host(fd, admin, opt.num_io_queues, io, &cdata); 941058c121SJohn Baldwin if (error != 0) { 951058c121SJohn Baldwin warnc(error, "Failed to handoff queues to kernel"); 96*0ac468c7SJohn Baldwin free(io); 971058c121SJohn Baldwin return (EX_IOERR); 981058c121SJohn Baldwin } 991058c121SJohn Baldwin free(io); 1001058c121SJohn Baldwin return (0); 1011058c121SJohn Baldwin } 1021058c121SJohn Baldwin 1031058c121SJohn Baldwin static void 1041058c121SJohn Baldwin reconnect_fn(const struct cmd *f, int argc, char *argv[]) 1051058c121SJohn Baldwin { 1061058c121SJohn Baldwin enum nvmf_trtype trtype; 1071058c121SJohn Baldwin const char *address, *port; 1081058c121SJohn Baldwin char *tofree; 1091058c121SJohn Baldwin int error, fd; 1101058c121SJohn Baldwin 1111058c121SJohn Baldwin if (arg_parse(argc, argv, f)) 1121058c121SJohn Baldwin return; 1131058c121SJohn Baldwin 1141058c121SJohn Baldwin if (strcasecmp(opt.transport, "tcp") == 0) { 1151058c121SJohn Baldwin trtype = NVMF_TRTYPE_TCP; 1161058c121SJohn Baldwin } else 1171058c121SJohn Baldwin errx(EX_USAGE, "Unsupported or invalid transport"); 1181058c121SJohn Baldwin 1191058c121SJohn Baldwin nvmf_parse_address(opt.address, &address, &port, &tofree); 1201058c121SJohn Baldwin 1211058c121SJohn Baldwin open_dev(opt.dev, &fd, 1, 1); 1221058c121SJohn Baldwin if (port == NULL) 1231058c121SJohn Baldwin errx(EX_USAGE, "Explicit port required"); 1241058c121SJohn Baldwin 1251058c121SJohn Baldwin error = reconnect_nvm_controller(fd, trtype, AF_UNSPEC, address, port); 1261058c121SJohn Baldwin if (error != 0) 1271058c121SJohn Baldwin exit(error); 1281058c121SJohn Baldwin 1291058c121SJohn Baldwin close(fd); 1301058c121SJohn Baldwin free(tofree); 1311058c121SJohn Baldwin } 1321058c121SJohn Baldwin 1331058c121SJohn Baldwin static const struct opts reconnect_opts[] = { 1341058c121SJohn Baldwin #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } 1351058c121SJohn Baldwin OPT("transport", 't', arg_string, opt, transport, 1361058c121SJohn Baldwin "Transport type"), 1371058c121SJohn Baldwin OPT("nr-io-queues", 'i', arg_uint16, opt, num_io_queues, 1381058c121SJohn Baldwin "Number of I/O queues"), 1391058c121SJohn Baldwin OPT("queue-size", 'Q', arg_uint16, opt, queue_size, 1401058c121SJohn Baldwin "Number of entries in each I/O queue"), 1411058c121SJohn Baldwin OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato, 1421058c121SJohn Baldwin "Keep Alive timeout (in seconds)"), 1431058c121SJohn Baldwin OPT("hostnqn", 'q', arg_string, opt, hostnqn, 1441058c121SJohn Baldwin "Host NQN"), 1451058c121SJohn Baldwin OPT("flow_control", 'F', arg_none, opt, flow_control, 1461058c121SJohn Baldwin "Request SQ flow control"), 1471058c121SJohn Baldwin OPT("hdr_digests", 'g', arg_none, opt, header_digests, 1481058c121SJohn Baldwin "Enable TCP PDU header digests"), 1491058c121SJohn Baldwin OPT("data_digests", 'G', arg_none, opt, data_digests, 1501058c121SJohn Baldwin "Enable TCP PDU data digests"), 1511058c121SJohn Baldwin { NULL, 0, arg_none, NULL, NULL } 1521058c121SJohn Baldwin }; 1531058c121SJohn Baldwin #undef OPT 1541058c121SJohn Baldwin 1551058c121SJohn Baldwin static const struct args reconnect_args[] = { 1561058c121SJohn Baldwin { arg_string, &opt.dev, "controller-id" }, 1571058c121SJohn Baldwin { arg_string, &opt.address, "address" }, 1581058c121SJohn Baldwin { arg_none, NULL, NULL }, 1591058c121SJohn Baldwin }; 1601058c121SJohn Baldwin 1611058c121SJohn Baldwin static struct cmd reconnect_cmd = { 1621058c121SJohn Baldwin .name = "reconnect", 1631058c121SJohn Baldwin .fn = reconnect_fn, 1641058c121SJohn Baldwin .descr = "Reconnect to a fabrics controller", 1651058c121SJohn Baldwin .ctx_size = sizeof(opt), 1661058c121SJohn Baldwin .opts = reconnect_opts, 1671058c121SJohn Baldwin .args = reconnect_args, 1681058c121SJohn Baldwin }; 1691058c121SJohn Baldwin 1701058c121SJohn Baldwin CMD_COMMAND(reconnect_cmd); 171