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/nvme.h" 9 #include "spdk/vmd.h" 10 #include "spdk/nvme_zns.h" 11 #include "spdk/env.h" 12 #include "spdk/string.h" 13 #include "spdk/log.h" 14 15 struct ctrlr_entry { 16 struct spdk_nvme_ctrlr *ctrlr; 17 TAILQ_ENTRY(ctrlr_entry) link; 18 char name[1024]; 19 }; 20 21 struct ns_entry { 22 struct spdk_nvme_ctrlr *ctrlr; 23 struct spdk_nvme_ns *ns; 24 TAILQ_ENTRY(ns_entry) link; 25 struct spdk_nvme_qpair *qpair; 26 }; 27 28 static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers); 29 static TAILQ_HEAD(, ns_entry) g_namespaces = TAILQ_HEAD_INITIALIZER(g_namespaces); 30 static struct spdk_nvme_transport_id g_trid = {}; 31 32 static bool g_vmd = false; 33 34 static void 35 register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns) 36 { 37 struct ns_entry *entry; 38 39 if (!spdk_nvme_ns_is_active(ns)) { 40 return; 41 } 42 43 entry = malloc(sizeof(struct ns_entry)); 44 if (entry == NULL) { 45 perror("ns_entry malloc"); 46 exit(1); 47 } 48 49 entry->ctrlr = ctrlr; 50 entry->ns = ns; 51 TAILQ_INSERT_TAIL(&g_namespaces, entry, link); 52 53 printf(" Namespace ID: %d size: %juGB\n", spdk_nvme_ns_get_id(ns), 54 spdk_nvme_ns_get_size(ns) / 1000000000); 55 } 56 57 struct hello_world_sequence { 58 struct ns_entry *ns_entry; 59 char *buf; 60 unsigned using_cmb_io; 61 int is_completed; 62 }; 63 64 static void 65 read_complete(void *arg, const struct spdk_nvme_cpl *completion) 66 { 67 struct hello_world_sequence *sequence = arg; 68 69 /* Assume the I/O was successful */ 70 sequence->is_completed = 1; 71 /* See if an error occurred. If so, display information 72 * about it, and set completion value so that I/O 73 * caller is aware that an error occurred. 74 */ 75 if (spdk_nvme_cpl_is_error(completion)) { 76 spdk_nvme_qpair_print_completion(sequence->ns_entry->qpair, (struct spdk_nvme_cpl *)completion); 77 fprintf(stderr, "I/O error status: %s\n", spdk_nvme_cpl_get_status_string(&completion->status)); 78 fprintf(stderr, "Read I/O failed, aborting run\n"); 79 sequence->is_completed = 2; 80 exit(1); 81 } 82 83 /* 84 * The read I/O has completed. Print the contents of the 85 * buffer, free the buffer, then mark the sequence as 86 * completed. This will trigger the hello_world() function 87 * to exit its polling loop. 88 */ 89 printf("%s", sequence->buf); 90 spdk_free(sequence->buf); 91 } 92 93 static void 94 write_complete(void *arg, const struct spdk_nvme_cpl *completion) 95 { 96 struct hello_world_sequence *sequence = arg; 97 struct ns_entry *ns_entry = sequence->ns_entry; 98 int rc; 99 100 /* See if an error occurred. If so, display information 101 * about it, and set completion value so that I/O 102 * caller is aware that an error occurred. 103 */ 104 if (spdk_nvme_cpl_is_error(completion)) { 105 spdk_nvme_qpair_print_completion(sequence->ns_entry->qpair, (struct spdk_nvme_cpl *)completion); 106 fprintf(stderr, "I/O error status: %s\n", spdk_nvme_cpl_get_status_string(&completion->status)); 107 fprintf(stderr, "Write I/O failed, aborting run\n"); 108 sequence->is_completed = 2; 109 exit(1); 110 } 111 /* 112 * The write I/O has completed. Free the buffer associated with 113 * the write I/O and allocate a new zeroed buffer for reading 114 * the data back from the NVMe namespace. 115 */ 116 if (sequence->using_cmb_io) { 117 spdk_nvme_ctrlr_unmap_cmb(ns_entry->ctrlr); 118 } else { 119 spdk_free(sequence->buf); 120 } 121 sequence->buf = spdk_zmalloc(0x1000, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA); 122 123 rc = spdk_nvme_ns_cmd_read(ns_entry->ns, ns_entry->qpair, sequence->buf, 124 0, /* LBA start */ 125 1, /* number of LBAs */ 126 read_complete, (void *)sequence, 0); 127 if (rc != 0) { 128 fprintf(stderr, "starting read I/O failed\n"); 129 exit(1); 130 } 131 } 132 133 static void 134 reset_zone_complete(void *arg, const struct spdk_nvme_cpl *completion) 135 { 136 struct hello_world_sequence *sequence = arg; 137 138 /* Assume the I/O was successful */ 139 sequence->is_completed = 1; 140 /* See if an error occurred. If so, display information 141 * about it, and set completion value so that I/O 142 * caller is aware that an error occurred. 143 */ 144 if (spdk_nvme_cpl_is_error(completion)) { 145 spdk_nvme_qpair_print_completion(sequence->ns_entry->qpair, (struct spdk_nvme_cpl *)completion); 146 fprintf(stderr, "I/O error status: %s\n", spdk_nvme_cpl_get_status_string(&completion->status)); 147 fprintf(stderr, "Reset zone I/O failed, aborting run\n"); 148 sequence->is_completed = 2; 149 exit(1); 150 } 151 } 152 153 static void 154 reset_zone_and_wait_for_completion(struct hello_world_sequence *sequence) 155 { 156 if (spdk_nvme_zns_reset_zone(sequence->ns_entry->ns, sequence->ns_entry->qpair, 157 0, /* starting LBA of the zone to reset */ 158 false, /* don't reset all zones */ 159 reset_zone_complete, 160 sequence)) { 161 fprintf(stderr, "starting reset zone I/O failed\n"); 162 exit(1); 163 } 164 while (!sequence->is_completed) { 165 spdk_nvme_qpair_process_completions(sequence->ns_entry->qpair, 0); 166 } 167 sequence->is_completed = 0; 168 } 169 170 static void 171 hello_world(void) 172 { 173 struct ns_entry *ns_entry; 174 struct hello_world_sequence sequence; 175 int rc; 176 size_t sz; 177 178 TAILQ_FOREACH(ns_entry, &g_namespaces, link) { 179 /* 180 * Allocate an I/O qpair that we can use to submit read/write requests 181 * to namespaces on the controller. NVMe controllers typically support 182 * many qpairs per controller. Any I/O qpair allocated for a controller 183 * can submit I/O to any namespace on that controller. 184 * 185 * The SPDK NVMe driver provides no synchronization for qpair accesses - 186 * the application must ensure only a single thread submits I/O to a 187 * qpair, and that same thread must also check for completions on that 188 * qpair. This enables extremely efficient I/O processing by making all 189 * I/O operations completely lockless. 190 */ 191 ns_entry->qpair = spdk_nvme_ctrlr_alloc_io_qpair(ns_entry->ctrlr, NULL, 0); 192 if (ns_entry->qpair == NULL) { 193 printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n"); 194 return; 195 } 196 197 /* 198 * Use spdk_dma_zmalloc to allocate a 4KB zeroed buffer. This memory 199 * will be pinned, which is required for data buffers used for SPDK NVMe 200 * I/O operations. 201 */ 202 sequence.using_cmb_io = 1; 203 sequence.buf = spdk_nvme_ctrlr_map_cmb(ns_entry->ctrlr, &sz); 204 if (sequence.buf == NULL || sz < 0x1000) { 205 sequence.using_cmb_io = 0; 206 sequence.buf = spdk_zmalloc(0x1000, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA); 207 } 208 if (sequence.buf == NULL) { 209 printf("ERROR: write buffer allocation failed\n"); 210 return; 211 } 212 if (sequence.using_cmb_io) { 213 printf("INFO: using controller memory buffer for IO\n"); 214 } else { 215 printf("INFO: using host memory buffer for IO\n"); 216 } 217 sequence.is_completed = 0; 218 sequence.ns_entry = ns_entry; 219 220 /* 221 * If the namespace is a Zoned Namespace, rather than a regular 222 * NVM namespace, we need to reset the first zone, before we 223 * write to it. This not needed for regular NVM namespaces. 224 */ 225 if (spdk_nvme_ns_get_csi(ns_entry->ns) == SPDK_NVME_CSI_ZNS) { 226 reset_zone_and_wait_for_completion(&sequence); 227 } 228 229 /* 230 * Print "Hello world!" to sequence.buf. We will write this data to LBA 231 * 0 on the namespace, and then later read it back into a separate buffer 232 * to demonstrate the full I/O path. 233 */ 234 snprintf(sequence.buf, 0x1000, "%s", "Hello world!\n"); 235 236 /* 237 * Write the data buffer to LBA 0 of this namespace. "write_complete" and 238 * "&sequence" are specified as the completion callback function and 239 * argument respectively. write_complete() will be called with the 240 * value of &sequence as a parameter when the write I/O is completed. 241 * This allows users to potentially specify different completion 242 * callback routines for each I/O, as well as pass a unique handle 243 * as an argument so the application knows which I/O has completed. 244 * 245 * Note that the SPDK NVMe driver will only check for completions 246 * when the application calls spdk_nvme_qpair_process_completions(). 247 * It is the responsibility of the application to trigger the polling 248 * process. 249 */ 250 rc = spdk_nvme_ns_cmd_write(ns_entry->ns, ns_entry->qpair, sequence.buf, 251 0, /* LBA start */ 252 1, /* number of LBAs */ 253 write_complete, &sequence, 0); 254 if (rc != 0) { 255 fprintf(stderr, "starting write I/O failed\n"); 256 exit(1); 257 } 258 259 /* 260 * Poll for completions. 0 here means process all available completions. 261 * In certain usage models, the caller may specify a positive integer 262 * instead of 0 to signify the maximum number of completions it should 263 * process. This function will never block - if there are no 264 * completions pending on the specified qpair, it will return immediately. 265 * 266 * When the write I/O completes, write_complete() will submit a new I/O 267 * to read LBA 0 into a separate buffer, specifying read_complete() as its 268 * completion routine. When the read I/O completes, read_complete() will 269 * print the buffer contents and set sequence.is_completed = 1. That will 270 * break this loop and then exit the program. 271 */ 272 while (!sequence.is_completed) { 273 spdk_nvme_qpair_process_completions(ns_entry->qpair, 0); 274 } 275 276 /* 277 * Free the I/O qpair. This typically is done when an application exits. 278 * But SPDK does support freeing and then reallocating qpairs during 279 * operation. It is the responsibility of the caller to ensure all 280 * pending I/O are completed before trying to free the qpair. 281 */ 282 spdk_nvme_ctrlr_free_io_qpair(ns_entry->qpair); 283 } 284 } 285 286 static bool 287 probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 288 struct spdk_nvme_ctrlr_opts *opts) 289 { 290 printf("Attaching to %s\n", trid->traddr); 291 292 return true; 293 } 294 295 static void 296 attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 297 struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) 298 { 299 int nsid; 300 struct ctrlr_entry *entry; 301 struct spdk_nvme_ns *ns; 302 const struct spdk_nvme_ctrlr_data *cdata; 303 304 entry = malloc(sizeof(struct ctrlr_entry)); 305 if (entry == NULL) { 306 perror("ctrlr_entry malloc"); 307 exit(1); 308 } 309 310 printf("Attached to %s\n", trid->traddr); 311 312 /* 313 * spdk_nvme_ctrlr is the logical abstraction in SPDK for an NVMe 314 * controller. During initialization, the IDENTIFY data for the 315 * controller is read using an NVMe admin command, and that data 316 * can be retrieved using spdk_nvme_ctrlr_get_data() to get 317 * detailed information on the controller. Refer to the NVMe 318 * specification for more details on IDENTIFY for NVMe controllers. 319 */ 320 cdata = spdk_nvme_ctrlr_get_data(ctrlr); 321 322 snprintf(entry->name, sizeof(entry->name), "%-20.20s (%-20.20s)", cdata->mn, cdata->sn); 323 324 entry->ctrlr = ctrlr; 325 TAILQ_INSERT_TAIL(&g_controllers, entry, link); 326 327 /* 328 * Each controller has one or more namespaces. An NVMe namespace is basically 329 * equivalent to a SCSI LUN. The controller's IDENTIFY data tells us how 330 * many namespaces exist on the controller. For Intel(R) P3X00 controllers, 331 * it will just be one namespace. 332 * 333 * Note that in NVMe, namespace IDs start at 1, not 0. 334 */ 335 for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr); nsid != 0; 336 nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid)) { 337 ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid); 338 if (ns == NULL) { 339 continue; 340 } 341 register_ns(ctrlr, ns); 342 } 343 } 344 345 static void 346 cleanup(void) 347 { 348 struct ns_entry *ns_entry, *tmp_ns_entry; 349 struct ctrlr_entry *ctrlr_entry, *tmp_ctrlr_entry; 350 struct spdk_nvme_detach_ctx *detach_ctx = NULL; 351 352 TAILQ_FOREACH_SAFE(ns_entry, &g_namespaces, link, tmp_ns_entry) { 353 TAILQ_REMOVE(&g_namespaces, ns_entry, link); 354 free(ns_entry); 355 } 356 357 TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp_ctrlr_entry) { 358 TAILQ_REMOVE(&g_controllers, ctrlr_entry, link); 359 spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx); 360 free(ctrlr_entry); 361 } 362 363 if (detach_ctx) { 364 spdk_nvme_detach_poll(detach_ctx); 365 } 366 } 367 368 static void 369 usage(const char *program_name) 370 { 371 printf("%s [options]", program_name); 372 printf("\t\n"); 373 printf("options:\n"); 374 printf("\t[-d DPDK huge memory size in MB]\n"); 375 printf("\t[-g use single file descriptor for DPDK memory segments]\n"); 376 printf("\t[-i shared memory group ID]\n"); 377 printf("\t[-r remote NVMe over Fabrics target address]\n"); 378 printf("\t[-V enumerate VMD]\n"); 379 #ifdef DEBUG 380 printf("\t[-L enable debug logging]\n"); 381 #else 382 printf("\t[-L enable debug logging (flag disabled, must reconfigure with --enable-debug)]\n"); 383 #endif 384 } 385 386 static int 387 parse_args(int argc, char **argv, struct spdk_env_opts *env_opts) 388 { 389 int op, rc; 390 391 spdk_nvme_trid_populate_transport(&g_trid, SPDK_NVME_TRANSPORT_PCIE); 392 snprintf(g_trid.subnqn, sizeof(g_trid.subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN); 393 394 while ((op = getopt(argc, argv, "d:gi:r:L:V")) != -1) { 395 switch (op) { 396 case 'V': 397 g_vmd = true; 398 break; 399 case 'i': 400 env_opts->shm_id = spdk_strtol(optarg, 10); 401 if (env_opts->shm_id < 0) { 402 fprintf(stderr, "Invalid shared memory ID\n"); 403 return env_opts->shm_id; 404 } 405 break; 406 case 'g': 407 env_opts->hugepage_single_segments = true; 408 break; 409 case 'r': 410 if (spdk_nvme_transport_id_parse(&g_trid, optarg) != 0) { 411 fprintf(stderr, "Error parsing transport address\n"); 412 return 1; 413 } 414 break; 415 case 'd': 416 env_opts->mem_size = spdk_strtol(optarg, 10); 417 if (env_opts->mem_size < 0) { 418 fprintf(stderr, "Invalid DPDK memory size\n"); 419 return env_opts->mem_size; 420 } 421 break; 422 case 'L': 423 rc = spdk_log_set_flag(optarg); 424 if (rc < 0) { 425 fprintf(stderr, "unknown flag\n"); 426 usage(argv[0]); 427 exit(EXIT_FAILURE); 428 } 429 #ifdef DEBUG 430 spdk_log_set_print_level(SPDK_LOG_DEBUG); 431 #endif 432 break; 433 default: 434 usage(argv[0]); 435 return 1; 436 } 437 } 438 439 return 0; 440 } 441 442 int 443 main(int argc, char **argv) 444 { 445 int rc; 446 struct spdk_env_opts opts; 447 448 /* 449 * SPDK relies on an abstraction around the local environment 450 * named env that handles memory allocation and PCI device operations. 451 * This library must be initialized first. 452 * 453 */ 454 spdk_env_opts_init(&opts); 455 rc = parse_args(argc, argv, &opts); 456 if (rc != 0) { 457 return rc; 458 } 459 460 opts.name = "hello_world"; 461 if (spdk_env_init(&opts) < 0) { 462 fprintf(stderr, "Unable to initialize SPDK env\n"); 463 return 1; 464 } 465 466 printf("Initializing NVMe Controllers\n"); 467 468 if (g_vmd && spdk_vmd_init()) { 469 fprintf(stderr, "Failed to initialize VMD." 470 " Some NVMe devices can be unavailable.\n"); 471 } 472 473 /* 474 * Start the SPDK NVMe enumeration process. probe_cb will be called 475 * for each NVMe controller found, giving our application a choice on 476 * whether to attach to each controller. attach_cb will then be 477 * called for each controller after the SPDK NVMe driver has completed 478 * initializing the controller we chose to attach. 479 */ 480 rc = spdk_nvme_probe(&g_trid, NULL, probe_cb, attach_cb, NULL); 481 if (rc != 0) { 482 fprintf(stderr, "spdk_nvme_probe() failed\n"); 483 rc = 1; 484 goto exit; 485 } 486 487 if (TAILQ_EMPTY(&g_controllers)) { 488 fprintf(stderr, "no NVMe controllers found\n"); 489 rc = 1; 490 goto exit; 491 } 492 493 printf("Initialization complete.\n"); 494 hello_world(); 495 cleanup(); 496 if (g_vmd) { 497 spdk_vmd_fini(); 498 } 499 500 exit: 501 cleanup(); 502 spdk_env_fini(); 503 return rc; 504 } 505