1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2017 Intel Corporation. 34b521e17SJim Harris * All rights reserved. 44b521e17SJim Harris */ 54b521e17SJim Harris 64b521e17SJim Harris #include "spdk/stdinc.h" 74b521e17SJim Harris 8fa3dd136SJim Harris #include "spdk/event.h" 94b521e17SJim Harris #include "spdk/nvme.h" 10f56de7b8SShuhei Matsumoto #include "spdk/string.h" 1105130f2dSJim Harris #include "spdk/thread.h" 124b521e17SJim Harris 13675dc02bSJim Harris static char g_path[256]; 1405130f2dSJim Harris static struct spdk_poller *g_poller; 15ad3634afSCurt Bruns /* default sleep time in ms */ 16ad3634afSCurt Bruns static uint32_t g_sleep_time = 1000; 1790b54d76SJim Harris static uint32_t g_io_queue_size; 18675dc02bSJim Harris 19bad2c8e8SChangpeng Liu struct ctrlr_entry { 20bad2c8e8SChangpeng Liu struct spdk_nvme_ctrlr *ctrlr; 21da08be0fSShuhei Matsumoto TAILQ_ENTRY(ctrlr_entry) link; 22bad2c8e8SChangpeng Liu }; 23bad2c8e8SChangpeng Liu 24da08be0fSShuhei Matsumoto static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers); 25bad2c8e8SChangpeng Liu 26bad2c8e8SChangpeng Liu static void 27bad2c8e8SChangpeng Liu cleanup(void) 28bad2c8e8SChangpeng Liu { 29da08be0fSShuhei Matsumoto struct ctrlr_entry *ctrlr_entry, *tmp; 307a85c283SShuhei Matsumoto struct spdk_nvme_detach_ctx *detach_ctx = NULL; 31bad2c8e8SChangpeng Liu 32da08be0fSShuhei Matsumoto TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) { 33da08be0fSShuhei Matsumoto TAILQ_REMOVE(&g_controllers, ctrlr_entry, link); 349fa44ca4SJim Harris spdk_nvme_cuse_unregister(ctrlr_entry->ctrlr); 357a85c283SShuhei Matsumoto spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx); 36bad2c8e8SChangpeng Liu free(ctrlr_entry); 37bad2c8e8SChangpeng Liu } 387a85c283SShuhei Matsumoto 394fe4040aSShuhei Matsumoto if (detach_ctx) { 404fe4040aSShuhei Matsumoto spdk_nvme_detach_poll(detach_ctx); 417a85c283SShuhei Matsumoto } 42bad2c8e8SChangpeng Liu } 43bad2c8e8SChangpeng Liu 444b521e17SJim Harris static void 454b521e17SJim Harris usage(char *executable_name) 464b521e17SJim Harris { 474b521e17SJim Harris printf("%s [options]\n", executable_name); 484b521e17SJim Harris printf("options:\n"); 491f5bbe02SDaniel Verkamp printf(" -i shared memory ID [required]\n"); 504b521e17SJim Harris printf(" -m mask core mask for DPDK\n"); 514b521e17SJim Harris printf(" -n channel number of memory channels used for DPDK\n"); 52*87696292SKonrad Sztyber printf(" -L flag enable log flag\n"); 533795c1cfSJim Harris printf(" -p core main (primary) core for DPDK\n"); 544b521e17SJim Harris printf(" -s size memory size in MB for DPDK\n"); 55ad3634afSCurt Bruns printf(" -t msec sleep time (ms) between checking for admin completions\n"); 5690b54d76SJim Harris printf(" -q size override default io_queue_size when attaching controllers\n"); 574b521e17SJim Harris printf(" -H show this usage\n"); 584b521e17SJim Harris } 594b521e17SJim Harris 604b521e17SJim Harris static bool 614b521e17SJim Harris probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 624b521e17SJim Harris struct spdk_nvme_ctrlr_opts *opts) 634b521e17SJim Harris { 6490b54d76SJim Harris if (g_io_queue_size > 0) { 6590b54d76SJim Harris opts->io_queue_size = g_io_queue_size; 6690b54d76SJim Harris } 674b521e17SJim Harris return true; 684b521e17SJim Harris } 694b521e17SJim Harris 704b521e17SJim Harris static void 714b521e17SJim Harris attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 724b521e17SJim Harris struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) 734b521e17SJim Harris { 74bad2c8e8SChangpeng Liu struct ctrlr_entry *entry; 75bad2c8e8SChangpeng Liu 76bad2c8e8SChangpeng Liu entry = malloc(sizeof(struct ctrlr_entry)); 77bad2c8e8SChangpeng Liu if (entry == NULL) { 78bad2c8e8SChangpeng Liu fprintf(stderr, "Malloc error\n"); 79bad2c8e8SChangpeng Liu exit(1); 80bad2c8e8SChangpeng Liu } 81bad2c8e8SChangpeng Liu 82bad2c8e8SChangpeng Liu entry->ctrlr = ctrlr; 83da08be0fSShuhei Matsumoto TAILQ_INSERT_TAIL(&g_controllers, entry, link); 849fa44ca4SJim Harris if (spdk_nvme_cuse_register(ctrlr) != 0) { 859fa44ca4SJim Harris fprintf(stderr, "could not register ctrlr with cuse\n"); 869fa44ca4SJim Harris } 874b521e17SJim Harris } 884b521e17SJim Harris 8905130f2dSJim Harris static int 9005130f2dSJim Harris stub_sleep(void *arg) 9105130f2dSJim Harris { 92ad3634afSCurt Bruns struct ctrlr_entry *ctrlr_entry, *tmp; 93ad3634afSCurt Bruns 94ad3634afSCurt Bruns usleep(g_sleep_time * 1000); 95ad3634afSCurt Bruns TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) { 96ad3634afSCurt Bruns spdk_nvme_ctrlr_process_admin_completions(ctrlr_entry->ctrlr); 97ad3634afSCurt Bruns } 9805130f2dSJim Harris return 0; 9905130f2dSJim Harris } 10005130f2dSJim Harris 101fa3dd136SJim Harris static void 102deb8ee5cSBen Walker stub_start(void *arg1) 103fa3dd136SJim Harris { 104fa3dd136SJim Harris int shm_id = (intptr_t)arg1; 105fa3dd136SJim Harris 106ef72f4c5SJim Harris snprintf(g_path, sizeof(g_path), "/var/run/spdk_stub%d", shm_id); 107ef72f4c5SJim Harris 108ef72f4c5SJim Harris /* If sentinel file already exists from earlier crashed stub, delete 109ef72f4c5SJim Harris * it now to avoid mknod() failure after spdk_nvme_probe() completes. 110ef72f4c5SJim Harris */ 111ef72f4c5SJim Harris unlink(g_path); 112ef72f4c5SJim Harris 113fa3dd136SJim Harris spdk_unaffinitize_thread(); 114fa3dd136SJim Harris 115fa3dd136SJim Harris if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { 116fa3dd136SJim Harris fprintf(stderr, "spdk_nvme_probe() failed\n"); 117fa3dd136SJim Harris exit(1); 118fa3dd136SJim Harris } 119fa3dd136SJim Harris 120fa3dd136SJim Harris if (mknod(g_path, S_IFREG, 0) != 0) { 121fa3dd136SJim Harris fprintf(stderr, "could not create sentinel file %s\n", g_path); 122fa3dd136SJim Harris exit(1); 123fa3dd136SJim Harris } 12405130f2dSJim Harris 125ab0bc5c2SShuhei Matsumoto g_poller = SPDK_POLLER_REGISTER(stub_sleep, NULL, 0); 126fa3dd136SJim Harris } 127fa3dd136SJim Harris 128fa3dd136SJim Harris static void 129fa3dd136SJim Harris stub_shutdown(void) 130fa3dd136SJim Harris { 13105130f2dSJim Harris spdk_poller_unregister(&g_poller); 132fa3dd136SJim Harris unlink(g_path); 133fa3dd136SJim Harris spdk_app_stop(0); 134fa3dd136SJim Harris } 135fa3dd136SJim Harris 1364b521e17SJim Harris int 1374b521e17SJim Harris main(int argc, char **argv) 1384b521e17SJim Harris { 1394b521e17SJim Harris int ch; 140fa3dd136SJim Harris struct spdk_app_opts opts = {}; 141f56de7b8SShuhei Matsumoto long int val; 1424b521e17SJim Harris 1434b521e17SJim Harris /* default value in opts structure */ 14448701bd9SZiye Yang spdk_app_opts_init(&opts, sizeof(opts)); 1454b521e17SJim Harris 1464b521e17SJim Harris opts.name = "stub"; 1476bef902cSJim Harris opts.rpc_addr = NULL; 148be619872SJim Harris opts.env_context = "--proc-type=primary"; 1494b521e17SJim Harris 150*87696292SKonrad Sztyber while ((ch = getopt(argc, argv, "i:m:n:p:q:s:t:HL:")) != -1) { 151f56de7b8SShuhei Matsumoto if (ch == 'm') { 152f56de7b8SShuhei Matsumoto opts.reactor_mask = optarg; 153*87696292SKonrad Sztyber } else if (ch == 'L') { 154*87696292SKonrad Sztyber if (spdk_log_set_flag(optarg) != 0) { 155*87696292SKonrad Sztyber SPDK_ERRLOG("unknown flag: %s\n", optarg); 156*87696292SKonrad Sztyber usage(argv[0]); 157*87696292SKonrad Sztyber exit(EXIT_FAILURE); 158*87696292SKonrad Sztyber } 159*87696292SKonrad Sztyber #ifdef DEBUG 160*87696292SKonrad Sztyber opts.print_level = SPDK_LOG_DEBUG; 161*87696292SKonrad Sztyber #endif 162cf3ed0e1Swanghailiangx } else if (ch == '?' || ch == 'H') { 163f56de7b8SShuhei Matsumoto usage(argv[0]); 164cf3ed0e1Swanghailiangx exit(EXIT_SUCCESS); 165f56de7b8SShuhei Matsumoto } else { 166f56de7b8SShuhei Matsumoto val = spdk_strtol(optarg, 10); 167f56de7b8SShuhei Matsumoto if (val < 0) { 168f56de7b8SShuhei Matsumoto fprintf(stderr, "Converting a string to integer failed\n"); 169f56de7b8SShuhei Matsumoto exit(1); 170f56de7b8SShuhei Matsumoto } 1714b521e17SJim Harris switch (ch) { 1724b521e17SJim Harris case 'i': 173f56de7b8SShuhei Matsumoto opts.shm_id = val; 1744b521e17SJim Harris break; 1754b521e17SJim Harris case 'n': 176f56de7b8SShuhei Matsumoto opts.mem_channel = val; 1774b521e17SJim Harris break; 1784b521e17SJim Harris case 'p': 1793795c1cfSJim Harris opts.main_core = val; 1804b521e17SJim Harris break; 1814b521e17SJim Harris case 's': 182f56de7b8SShuhei Matsumoto opts.mem_size = val; 1834b521e17SJim Harris break; 184ad3634afSCurt Bruns case 't': 185ad3634afSCurt Bruns g_sleep_time = val; 186ad3634afSCurt Bruns break; 18790b54d76SJim Harris case 'q': 18890b54d76SJim Harris g_io_queue_size = val; 18990b54d76SJim Harris break; 1904b521e17SJim Harris default: 1914b521e17SJim Harris usage(argv[0]); 192cf3ed0e1Swanghailiangx exit(EXIT_FAILURE); 1934b521e17SJim Harris } 1944b521e17SJim Harris } 195f56de7b8SShuhei Matsumoto } 1964b521e17SJim Harris 1971f5bbe02SDaniel Verkamp if (opts.shm_id < 0) { 1981f5bbe02SDaniel Verkamp fprintf(stderr, "%s: -i shared memory ID must be specified\n", argv[0]); 1991f5bbe02SDaniel Verkamp usage(argv[0]); 2001f5bbe02SDaniel Verkamp exit(1); 2011f5bbe02SDaniel Verkamp } 2021f5bbe02SDaniel Verkamp 203fa3dd136SJim Harris opts.shutdown_cb = stub_shutdown; 2044b521e17SJim Harris 20536287957SBen Walker ch = spdk_app_start(&opts, stub_start, (void *)(intptr_t)opts.shm_id); 206bad2c8e8SChangpeng Liu 207bad2c8e8SChangpeng Liu cleanup(); 20869a762caSPawel Wodkowski spdk_app_fini(); 2094b521e17SJim Harris 210b9be940aSLance Hartmann return ch; 2114b521e17SJim Harris } 212