1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 8 #include "spdk/env.h" 9 #include "spdk/nvme.h" 10 #include "spdk/string.h" 11 #include "spdk/util.h" 12 #include "spdk/log.h" 13 #include "spdk/likely.h" 14 #include "spdk/sock.h" 15 16 static int g_time_in_sec; 17 18 static struct spdk_nvme_transport_id g_trid; 19 20 static void 21 usage(char *program_name) 22 { 23 printf("%s options", program_name); 24 printf("\n"); 25 printf("\t[-t, --time <sec> time in seconds]\n"); 26 printf("\t[-c, --core-mask <mask>]\n"); 27 printf("\t\t(default: 1)\n"); 28 printf("\t[-r, --transport <fmt> Transport ID for local PCIe NVMe or NVMeoF]\n"); 29 printf("\t Format: 'key:value [key:value] ...'\n"); 30 printf("\t Keys:\n"); 31 printf("\t trtype Transport type (e.g. PCIe, RDMA)\n"); 32 printf("\t adrfam Address family (e.g. IPv4, IPv6)\n"); 33 printf("\t traddr Transport address (e.g. 0000:04:00.0 for PCIe or 192.168.100.8 for RDMA)\n"); 34 printf("\t trsvcid Transport service identifier (e.g. 4420)\n"); 35 printf("\t subnqn Subsystem NQN\n"); 36 printf("\t Example: -r 'trtype:PCIe traddr:0000:04:00.0' for PCIe or\n"); 37 printf("\t -r 'trtype:RDMA adrfam:IPv4 traddr:192.168.100.8 trsvcid:4420' for NVMeoF\n"); 38 printf("\t[-s, --hugemem-size <MB> DPDK huge memory size in MB.]\n"); 39 printf("\t\t(default: 0 - unlimited)\n"); 40 printf("\t[-i, --shmem-grp-id <id> shared memory group ID]\n"); 41 printf("\t"); 42 spdk_log_usage(stdout, "-T"); 43 printf("\t[-S, --default-sock-impl <impl> set the default sock impl, e.g. \"posix\"]\n"); 44 #ifdef DEBUG 45 printf("\t[-G, --enable-debug enable debug logging]\n"); 46 #else 47 printf("\t[-G, --enable-debug enable debug logging (flag disabled, must reconfigure with --enable-debug)]\n"); 48 printf("\t[--iova-mode <mode> specify DPDK IOVA mode: va|pa]\n"); 49 #endif 50 } 51 52 static int 53 add_trid(const char *trid_str) 54 { 55 g_trid.trtype = SPDK_NVME_TRANSPORT_PCIE; 56 snprintf(g_trid.subnqn, sizeof(g_trid.subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN); 57 58 if (spdk_nvme_transport_id_parse(&g_trid, trid_str) != 0) { 59 fprintf(stderr, "Invalid transport ID format '%s'\n", trid_str); 60 return 1; 61 } 62 63 spdk_nvme_transport_id_populate_trstring(&g_trid, 64 spdk_nvme_transport_id_trtype_str(g_trid.trtype)); 65 66 return 0; 67 } 68 69 #define PERF_GETOPT_SHORT "c:i:r:s:t:GS:T:" 70 71 static const struct option g_cmdline_opts[] = { 72 #define PERF_CORE_MASK 'c' 73 {"core-mask", required_argument, NULL, PERF_CORE_MASK}, 74 #define PERF_SHMEM_GROUP_ID 'i' 75 {"shmem-grp-id", required_argument, NULL, PERF_SHMEM_GROUP_ID}, 76 #define PERF_TRANSPORT 'r' 77 {"transport", required_argument, NULL, PERF_TRANSPORT}, 78 #define PERF_HUGEMEM_SIZE 's' 79 {"hugemem-size", required_argument, NULL, PERF_HUGEMEM_SIZE}, 80 #define PERF_TIME 't' 81 {"time", required_argument, NULL, PERF_TIME}, 82 #define PERF_ENABLE_DEBUG 'G' 83 {"enable-debug", no_argument, NULL, PERF_ENABLE_DEBUG}, 84 #define PERF_DEFAULT_SOCK_IMPL 'S' 85 {"default-sock-impl", required_argument, NULL, PERF_DEFAULT_SOCK_IMPL}, 86 #define PERF_LOG_FLAG 'T' 87 {"logflag", required_argument, NULL, PERF_LOG_FLAG}, 88 #define PERF_IOVA_MODE 258 89 {"iova-mode", required_argument, NULL, PERF_IOVA_MODE}, 90 /* Should be the last element */ 91 {0, 0, 0, 0} 92 }; 93 94 static int 95 parse_args(int argc, char **argv, struct spdk_env_opts *env_opts) 96 { 97 bool trid_set = false; 98 int op, long_idx; 99 long int val; 100 int rc; 101 102 while ((op = getopt_long(argc, argv, PERF_GETOPT_SHORT, g_cmdline_opts, &long_idx)) != -1) { 103 switch (op) { 104 case PERF_SHMEM_GROUP_ID: 105 case PERF_HUGEMEM_SIZE: 106 case PERF_TIME: 107 val = spdk_strtol(optarg, 10); 108 if (val < 0) { 109 fprintf(stderr, "Converting a string to integer failed\n"); 110 return val; 111 } 112 switch (op) { 113 case PERF_SHMEM_GROUP_ID: 114 env_opts->shm_id = val; 115 break; 116 case PERF_HUGEMEM_SIZE: 117 env_opts->mem_size = val; 118 break; 119 case PERF_TIME: 120 g_time_in_sec = val; 121 break; 122 } 123 break; 124 case PERF_CORE_MASK: 125 env_opts->core_mask = optarg; 126 break; 127 case PERF_TRANSPORT: 128 if (trid_set) { 129 fprintf(stderr, "Only one trid can be specified\n"); 130 usage(argv[0]); 131 return 1; 132 } 133 trid_set = true; 134 if (add_trid(optarg)) { 135 usage(argv[0]); 136 return 1; 137 } 138 break; 139 case PERF_ENABLE_DEBUG: 140 #ifndef DEBUG 141 fprintf(stderr, "%s must be configured with --enable-debug for -G flag\n", 142 argv[0]); 143 usage(argv[0]); 144 return 1; 145 #else 146 spdk_log_set_flag("nvme"); 147 spdk_log_set_print_level(SPDK_LOG_DEBUG); 148 break; 149 #endif 150 case PERF_LOG_FLAG: 151 rc = spdk_log_set_flag(optarg); 152 if (rc < 0) { 153 fprintf(stderr, "unknown flag\n"); 154 usage(argv[0]); 155 exit(EXIT_FAILURE); 156 } 157 #ifdef DEBUG 158 spdk_log_set_print_level(SPDK_LOG_DEBUG); 159 #endif 160 break; 161 case PERF_DEFAULT_SOCK_IMPL: 162 rc = spdk_sock_set_default_impl(optarg); 163 if (rc) { 164 fprintf(stderr, "Failed to set sock impl %s, err %d (%s)\n", optarg, errno, strerror(errno)); 165 return 1; 166 } 167 break; 168 case PERF_IOVA_MODE: 169 env_opts->iova_mode = optarg; 170 break; 171 default: 172 usage(argv[0]); 173 return 1; 174 } 175 } 176 177 if (!g_time_in_sec) { 178 fprintf(stderr, "missing -t (--time) operand\n"); 179 usage(argv[0]); 180 return 1; 181 } 182 183 if (!trid_set) { 184 fprintf(stderr, "missing -r operand\n"); 185 usage(argv[0]); 186 return 1; 187 } 188 189 env_opts->no_pci = true; 190 if (g_trid.trtype == SPDK_NVME_TRANSPORT_PCIE) { 191 env_opts->no_pci = false; 192 } 193 194 return 0; 195 } 196 197 static int 198 test_controller(void) 199 { 200 const int LOOP_COUNT = 5; 201 struct spdk_nvme_qpair *qpair[LOOP_COUNT]; 202 union spdk_nvme_csts_register csts; 203 struct spdk_nvme_ctrlr *ctrlr; 204 205 ctrlr = spdk_nvme_connect(&g_trid, NULL, 0); 206 if (ctrlr == NULL) { 207 fprintf(stderr, "spdk_nvme_connect() failed for transport address '%s'\n", 208 g_trid.traddr); 209 return -1; 210 } 211 if (spdk_nvme_ctrlr_is_discovery(ctrlr)) { 212 fprintf(stderr, "discovery controller not allowed for this test\n"); 213 spdk_nvme_detach(ctrlr); 214 return -1; 215 } 216 217 for (int i = 0; i < LOOP_COUNT; i++) { 218 csts = spdk_nvme_ctrlr_get_regs_csts(ctrlr); 219 if (csts.raw == 0xFFFFFFFF) { 220 fprintf(stderr, "could not read csts\n"); 221 spdk_nvme_detach(ctrlr); 222 return -1; 223 } 224 qpair[i] = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0); 225 if (qpair[i] == NULL) { 226 fprintf(stderr, "could not allocate io qpair\n"); 227 spdk_nvme_detach(ctrlr); 228 return -1; 229 } 230 } 231 for (int i = 0; i < LOOP_COUNT; i++) { 232 spdk_nvme_ctrlr_free_io_qpair(qpair[i]); 233 } 234 235 spdk_nvme_detach(ctrlr); 236 237 return 0; 238 } 239 240 int 241 main(int argc, char **argv) 242 { 243 struct spdk_env_opts opts; 244 uint64_t tsc_end; 245 int rc; 246 247 spdk_env_opts_init(&opts); 248 opts.name = "connect_stress"; 249 rc = parse_args(argc, argv, &opts); 250 if (rc != 0) { 251 return rc; 252 } 253 if (spdk_env_init(&opts) < 0) { 254 fprintf(stderr, "Unable to initialize SPDK env\n"); 255 return -1; 256 } 257 258 if (g_trid.trtype != SPDK_NVME_TRANSPORT_PCIE) { 259 printf("Testing NVMe over Fabrics controller at %s:%s: %s\n", 260 g_trid.traddr, g_trid.trsvcid, 261 g_trid.subnqn); 262 } else { 263 printf("Testing NVMe PCI controller at %s\n", g_trid.traddr); 264 } 265 266 tsc_end = spdk_get_ticks() + g_time_in_sec * spdk_get_ticks_hz(); 267 while (spdk_get_ticks() < tsc_end && rc == 0) { 268 rc = test_controller(); 269 } 270 271 return 0; 272 } 273