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 <err.h> 9*1058c121SJohn Baldwin #include <libnvmf.h> 10*1058c121SJohn Baldwin #include <stdio.h> 11*1058c121SJohn Baldwin #include <stdlib.h> 12*1058c121SJohn Baldwin #include <string.h> 13*1058c121SJohn Baldwin #include <sysexits.h> 14*1058c121SJohn Baldwin 15*1058c121SJohn Baldwin #include "comnd.h" 16*1058c121SJohn Baldwin #include "fabrics.h" 17*1058c121SJohn Baldwin #include "nvmecontrol_ext.h" 18*1058c121SJohn Baldwin 19*1058c121SJohn Baldwin static struct options { 20*1058c121SJohn Baldwin const char *transport; 21*1058c121SJohn Baldwin const char *address; 22*1058c121SJohn Baldwin const char *hostnqn; 23*1058c121SJohn Baldwin bool verbose; 24*1058c121SJohn Baldwin } opt = { 25*1058c121SJohn Baldwin .transport = "tcp", 26*1058c121SJohn Baldwin .address = NULL, 27*1058c121SJohn Baldwin .hostnqn = NULL, 28*1058c121SJohn Baldwin .verbose = false, 29*1058c121SJohn Baldwin }; 30*1058c121SJohn Baldwin 31*1058c121SJohn Baldwin static void 32*1058c121SJohn Baldwin identify_controller(struct nvmf_qpair *qp) 33*1058c121SJohn Baldwin { 34*1058c121SJohn Baldwin struct nvme_controller_data cdata; 35*1058c121SJohn Baldwin int error; 36*1058c121SJohn Baldwin 37*1058c121SJohn Baldwin error = nvmf_host_identify_controller(qp, &cdata); 38*1058c121SJohn Baldwin if (error != 0) 39*1058c121SJohn Baldwin errc(EX_IOERR, error, "Failed to fetch controller data"); 40*1058c121SJohn Baldwin nvme_print_controller(&cdata); 41*1058c121SJohn Baldwin } 42*1058c121SJohn Baldwin 43*1058c121SJohn Baldwin static const char * 44*1058c121SJohn Baldwin nvmf_address_family(uint8_t adrfam) 45*1058c121SJohn Baldwin { 46*1058c121SJohn Baldwin static char buf[8]; 47*1058c121SJohn Baldwin 48*1058c121SJohn Baldwin switch (adrfam) { 49*1058c121SJohn Baldwin case NVMF_ADRFAM_IPV4: 50*1058c121SJohn Baldwin return ("AF_INET"); 51*1058c121SJohn Baldwin case NVMF_ADRFAM_IPV6: 52*1058c121SJohn Baldwin return ("AF_INET6"); 53*1058c121SJohn Baldwin case NVMF_ADRFAM_IB: 54*1058c121SJohn Baldwin return ("InfiniBand"); 55*1058c121SJohn Baldwin case NVMF_ADRFAM_FC: 56*1058c121SJohn Baldwin return ("Fibre Channel"); 57*1058c121SJohn Baldwin case NVMF_ADRFAM_INTRA_HOST: 58*1058c121SJohn Baldwin return ("Intra-host"); 59*1058c121SJohn Baldwin default: 60*1058c121SJohn Baldwin snprintf(buf, sizeof(buf), "0x%02x\n", adrfam); 61*1058c121SJohn Baldwin return (buf); 62*1058c121SJohn Baldwin } 63*1058c121SJohn Baldwin } 64*1058c121SJohn Baldwin 65*1058c121SJohn Baldwin static const char * 66*1058c121SJohn Baldwin nvmf_subsystem_type(uint8_t subtype) 67*1058c121SJohn Baldwin { 68*1058c121SJohn Baldwin static char buf[8]; 69*1058c121SJohn Baldwin 70*1058c121SJohn Baldwin switch (subtype) { 71*1058c121SJohn Baldwin case NVMF_SUBTYPE_DISCOVERY: 72*1058c121SJohn Baldwin return ("Discovery"); 73*1058c121SJohn Baldwin case NVMF_SUBTYPE_NVME: 74*1058c121SJohn Baldwin return ("NVMe"); 75*1058c121SJohn Baldwin default: 76*1058c121SJohn Baldwin snprintf(buf, sizeof(buf), "0x%02x\n", subtype); 77*1058c121SJohn Baldwin return (buf); 78*1058c121SJohn Baldwin } 79*1058c121SJohn Baldwin } 80*1058c121SJohn Baldwin 81*1058c121SJohn Baldwin static const char * 82*1058c121SJohn Baldwin nvmf_secure_channel(uint8_t treq) 83*1058c121SJohn Baldwin { 84*1058c121SJohn Baldwin switch (treq & 0x03) { 85*1058c121SJohn Baldwin case NVMF_TREQ_SECURE_CHANNEL_NOT_SPECIFIED: 86*1058c121SJohn Baldwin return ("Not specified"); 87*1058c121SJohn Baldwin case NVMF_TREQ_SECURE_CHANNEL_REQUIRED: 88*1058c121SJohn Baldwin return ("Required"); 89*1058c121SJohn Baldwin case NVMF_TREQ_SECURE_CHANNEL_NOT_REQUIRED: 90*1058c121SJohn Baldwin return ("Not required"); 91*1058c121SJohn Baldwin default: 92*1058c121SJohn Baldwin return ("0x03"); 93*1058c121SJohn Baldwin } 94*1058c121SJohn Baldwin } 95*1058c121SJohn Baldwin 96*1058c121SJohn Baldwin static const char * 97*1058c121SJohn Baldwin nvmf_controller_id(uint16_t cntlid) 98*1058c121SJohn Baldwin { 99*1058c121SJohn Baldwin static char buf[8]; 100*1058c121SJohn Baldwin 101*1058c121SJohn Baldwin switch (cntlid) { 102*1058c121SJohn Baldwin case NVMF_CNTLID_DYNAMIC: 103*1058c121SJohn Baldwin return ("Dynamic"); 104*1058c121SJohn Baldwin case NVMF_CNTLID_STATIC_ANY: 105*1058c121SJohn Baldwin return ("Static"); 106*1058c121SJohn Baldwin default: 107*1058c121SJohn Baldwin snprintf(buf, sizeof(buf), "%u", cntlid); 108*1058c121SJohn Baldwin return (buf); 109*1058c121SJohn Baldwin } 110*1058c121SJohn Baldwin } 111*1058c121SJohn Baldwin 112*1058c121SJohn Baldwin static const char * 113*1058c121SJohn Baldwin nvmf_rdma_service_type(uint8_t qptype) 114*1058c121SJohn Baldwin { 115*1058c121SJohn Baldwin static char buf[8]; 116*1058c121SJohn Baldwin 117*1058c121SJohn Baldwin switch (qptype) { 118*1058c121SJohn Baldwin case NVMF_RDMA_QPTYPE_RELIABLE_CONNECTED: 119*1058c121SJohn Baldwin return ("Reliable connected"); 120*1058c121SJohn Baldwin case NVMF_RDMA_QPTYPE_RELIABLE_DATAGRAM: 121*1058c121SJohn Baldwin return ("Reliable datagram"); 122*1058c121SJohn Baldwin default: 123*1058c121SJohn Baldwin snprintf(buf, sizeof(buf), "0x%02x\n", qptype); 124*1058c121SJohn Baldwin return (buf); 125*1058c121SJohn Baldwin } 126*1058c121SJohn Baldwin } 127*1058c121SJohn Baldwin 128*1058c121SJohn Baldwin static const char * 129*1058c121SJohn Baldwin nvmf_rdma_provider_type(uint8_t prtype) 130*1058c121SJohn Baldwin { 131*1058c121SJohn Baldwin static char buf[8]; 132*1058c121SJohn Baldwin 133*1058c121SJohn Baldwin switch (prtype) { 134*1058c121SJohn Baldwin case NVMF_RDMA_PRTYPE_NONE: 135*1058c121SJohn Baldwin return ("None"); 136*1058c121SJohn Baldwin case NVMF_RDMA_PRTYPE_IB: 137*1058c121SJohn Baldwin return ("InfiniBand"); 138*1058c121SJohn Baldwin case NVMF_RDMA_PRTYPE_ROCE: 139*1058c121SJohn Baldwin return ("RoCE (v1)"); 140*1058c121SJohn Baldwin case NVMF_RDMA_PRTYPE_ROCE2: 141*1058c121SJohn Baldwin return ("RoCE (v2)"); 142*1058c121SJohn Baldwin case NVMF_RDMA_PRTYPE_IWARP: 143*1058c121SJohn Baldwin return ("iWARP"); 144*1058c121SJohn Baldwin default: 145*1058c121SJohn Baldwin snprintf(buf, sizeof(buf), "0x%02x\n", prtype); 146*1058c121SJohn Baldwin return (buf); 147*1058c121SJohn Baldwin } 148*1058c121SJohn Baldwin } 149*1058c121SJohn Baldwin 150*1058c121SJohn Baldwin static const char * 151*1058c121SJohn Baldwin nvmf_rdma_cms(uint8_t cms) 152*1058c121SJohn Baldwin { 153*1058c121SJohn Baldwin static char buf[8]; 154*1058c121SJohn Baldwin 155*1058c121SJohn Baldwin switch (cms) { 156*1058c121SJohn Baldwin case NVMF_RDMA_CMS_RDMA_CM: 157*1058c121SJohn Baldwin return ("RDMA_IP_CM"); 158*1058c121SJohn Baldwin default: 159*1058c121SJohn Baldwin snprintf(buf, sizeof(buf), "0x%02x\n", cms); 160*1058c121SJohn Baldwin return (buf); 161*1058c121SJohn Baldwin } 162*1058c121SJohn Baldwin } 163*1058c121SJohn Baldwin 164*1058c121SJohn Baldwin static const char * 165*1058c121SJohn Baldwin nvmf_tcp_security_type(uint8_t sectype) 166*1058c121SJohn Baldwin { 167*1058c121SJohn Baldwin static char buf[8]; 168*1058c121SJohn Baldwin 169*1058c121SJohn Baldwin switch (sectype) { 170*1058c121SJohn Baldwin case NVME_TCP_SECURITY_NONE: 171*1058c121SJohn Baldwin return ("None"); 172*1058c121SJohn Baldwin case NVME_TCP_SECURITY_TLS_1_2: 173*1058c121SJohn Baldwin return ("TLS 1.2"); 174*1058c121SJohn Baldwin case NVME_TCP_SECURITY_TLS_1_3: 175*1058c121SJohn Baldwin return ("TLS 1.3"); 176*1058c121SJohn Baldwin default: 177*1058c121SJohn Baldwin snprintf(buf, sizeof(buf), "0x%02x\n", sectype); 178*1058c121SJohn Baldwin return (buf); 179*1058c121SJohn Baldwin } 180*1058c121SJohn Baldwin } 181*1058c121SJohn Baldwin 182*1058c121SJohn Baldwin static void 183*1058c121SJohn Baldwin print_discovery_entry(u_int i, struct nvme_discovery_log_entry *entry) 184*1058c121SJohn Baldwin { 185*1058c121SJohn Baldwin printf("Entry %02d\n", i + 1); 186*1058c121SJohn Baldwin printf("========\n"); 187*1058c121SJohn Baldwin printf(" Transport type: %s\n", 188*1058c121SJohn Baldwin nvmf_transport_type(entry->trtype)); 189*1058c121SJohn Baldwin printf(" Address family: %s\n", 190*1058c121SJohn Baldwin nvmf_address_family(entry->adrfam)); 191*1058c121SJohn Baldwin printf(" Subsystem type: %s\n", 192*1058c121SJohn Baldwin nvmf_subsystem_type(entry->subtype)); 193*1058c121SJohn Baldwin printf(" SQ flow control: %s\n", 194*1058c121SJohn Baldwin (entry->treq & (1 << 2)) == 0 ? "required" : "optional"); 195*1058c121SJohn Baldwin printf(" Secure Channel: %s\n", nvmf_secure_channel(entry->treq)); 196*1058c121SJohn Baldwin printf(" Port ID: %u\n", entry->portid); 197*1058c121SJohn Baldwin printf(" Controller ID: %s\n", 198*1058c121SJohn Baldwin nvmf_controller_id(entry->cntlid)); 199*1058c121SJohn Baldwin printf(" Max Admin SQ Size: %u\n", entry->aqsz); 200*1058c121SJohn Baldwin printf(" Sub NQN: %s\n", entry->subnqn); 201*1058c121SJohn Baldwin printf(" Transport address: %s\n", entry->traddr); 202*1058c121SJohn Baldwin printf(" Service identifier: %s\n", entry->trsvcid); 203*1058c121SJohn Baldwin switch (entry->trtype) { 204*1058c121SJohn Baldwin case NVMF_TRTYPE_RDMA: 205*1058c121SJohn Baldwin printf(" RDMA Service Type: %s\n", 206*1058c121SJohn Baldwin nvmf_rdma_service_type(entry->tsas.rdma.rdma_qptype)); 207*1058c121SJohn Baldwin printf(" RDMA Provider Type: %s\n", 208*1058c121SJohn Baldwin nvmf_rdma_provider_type(entry->tsas.rdma.rdma_prtype)); 209*1058c121SJohn Baldwin printf(" RDMA CMS: %s\n", 210*1058c121SJohn Baldwin nvmf_rdma_cms(entry->tsas.rdma.rdma_cms)); 211*1058c121SJohn Baldwin printf(" Partition key: %u\n", 212*1058c121SJohn Baldwin entry->tsas.rdma.rdma_pkey); 213*1058c121SJohn Baldwin break; 214*1058c121SJohn Baldwin case NVMF_TRTYPE_TCP: 215*1058c121SJohn Baldwin printf(" Security Type: %s\n", 216*1058c121SJohn Baldwin nvmf_tcp_security_type(entry->tsas.tcp.sectype)); 217*1058c121SJohn Baldwin break; 218*1058c121SJohn Baldwin } 219*1058c121SJohn Baldwin } 220*1058c121SJohn Baldwin 221*1058c121SJohn Baldwin static void 222*1058c121SJohn Baldwin dump_discovery_log_page(struct nvmf_qpair *qp) 223*1058c121SJohn Baldwin { 224*1058c121SJohn Baldwin struct nvme_discovery_log *log; 225*1058c121SJohn Baldwin int error; 226*1058c121SJohn Baldwin 227*1058c121SJohn Baldwin error = nvmf_host_fetch_discovery_log_page(qp, &log); 228*1058c121SJohn Baldwin if (error != 0) 229*1058c121SJohn Baldwin errc(EX_IOERR, error, "Failed to fetch discovery log page"); 230*1058c121SJohn Baldwin 231*1058c121SJohn Baldwin printf("Discovery\n"); 232*1058c121SJohn Baldwin printf("=========\n"); 233*1058c121SJohn Baldwin if (log->numrec == 0) { 234*1058c121SJohn Baldwin printf("No entries found\n"); 235*1058c121SJohn Baldwin } else { 236*1058c121SJohn Baldwin for (u_int i = 0; i < log->numrec; i++) 237*1058c121SJohn Baldwin print_discovery_entry(i, &log->entries[i]); 238*1058c121SJohn Baldwin } 239*1058c121SJohn Baldwin free(log); 240*1058c121SJohn Baldwin } 241*1058c121SJohn Baldwin 242*1058c121SJohn Baldwin static void 243*1058c121SJohn Baldwin discover(const struct cmd *f, int argc, char *argv[]) 244*1058c121SJohn Baldwin { 245*1058c121SJohn Baldwin enum nvmf_trtype trtype; 246*1058c121SJohn Baldwin struct nvmf_qpair *qp; 247*1058c121SJohn Baldwin const char *address, *port; 248*1058c121SJohn Baldwin char *tofree; 249*1058c121SJohn Baldwin 250*1058c121SJohn Baldwin if (arg_parse(argc, argv, f)) 251*1058c121SJohn Baldwin return; 252*1058c121SJohn Baldwin 253*1058c121SJohn Baldwin if (strcasecmp(opt.transport, "tcp") == 0) { 254*1058c121SJohn Baldwin trtype = NVMF_TRTYPE_TCP; 255*1058c121SJohn Baldwin } else 256*1058c121SJohn Baldwin errx(EX_USAGE, "Unsupported or invalid transport"); 257*1058c121SJohn Baldwin 258*1058c121SJohn Baldwin nvmf_parse_address(opt.address, &address, &port, &tofree); 259*1058c121SJohn Baldwin qp = connect_discovery_adminq(trtype, address, port, opt.hostnqn); 260*1058c121SJohn Baldwin free(tofree); 261*1058c121SJohn Baldwin 262*1058c121SJohn Baldwin /* Use Identify to fetch controller data */ 263*1058c121SJohn Baldwin if (opt.verbose) { 264*1058c121SJohn Baldwin identify_controller(qp); 265*1058c121SJohn Baldwin printf("\n"); 266*1058c121SJohn Baldwin } 267*1058c121SJohn Baldwin 268*1058c121SJohn Baldwin /* Fetch Log pages */ 269*1058c121SJohn Baldwin dump_discovery_log_page(qp); 270*1058c121SJohn Baldwin 271*1058c121SJohn Baldwin nvmf_free_qpair(qp); 272*1058c121SJohn Baldwin } 273*1058c121SJohn Baldwin 274*1058c121SJohn Baldwin static const struct opts discover_opts[] = { 275*1058c121SJohn Baldwin #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } 276*1058c121SJohn Baldwin OPT("transport", 't', arg_string, opt, transport, 277*1058c121SJohn Baldwin "Transport type"), 278*1058c121SJohn Baldwin OPT("hostnqn", 'q', arg_string, opt, hostnqn, 279*1058c121SJohn Baldwin "Host NQN"), 280*1058c121SJohn Baldwin OPT("verbose", 'v', arg_none, opt, verbose, 281*1058c121SJohn Baldwin "Display the discovery controller's controller data"), 282*1058c121SJohn Baldwin { NULL, 0, arg_none, NULL, NULL } 283*1058c121SJohn Baldwin }; 284*1058c121SJohn Baldwin #undef OPT 285*1058c121SJohn Baldwin 286*1058c121SJohn Baldwin static const struct args discover_args[] = { 287*1058c121SJohn Baldwin { arg_string, &opt.address, "address" }, 288*1058c121SJohn Baldwin { arg_none, NULL, NULL }, 289*1058c121SJohn Baldwin }; 290*1058c121SJohn Baldwin 291*1058c121SJohn Baldwin static struct cmd discover_cmd = { 292*1058c121SJohn Baldwin .name = "discover", 293*1058c121SJohn Baldwin .fn = discover, 294*1058c121SJohn Baldwin .descr = "List discovery log pages from a fabrics controller", 295*1058c121SJohn Baldwin .ctx_size = sizeof(opt), 296*1058c121SJohn Baldwin .opts = discover_opts, 297*1058c121SJohn Baldwin .args = discover_args, 298*1058c121SJohn Baldwin }; 299*1058c121SJohn Baldwin 300*1058c121SJohn Baldwin CMD_COMMAND(discover_cmd); 301