1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2017 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 8 #include "spdk/event.h" 9 #include "spdk/nvme.h" 10 #include "spdk/string.h" 11 #include "spdk/thread.h" 12 13 static char g_path[256]; 14 static struct spdk_poller *g_poller; 15 /* default sleep time in ms */ 16 static uint32_t g_sleep_time = 1000; 17 18 struct ctrlr_entry { 19 struct spdk_nvme_ctrlr *ctrlr; 20 TAILQ_ENTRY(ctrlr_entry) link; 21 }; 22 23 static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers); 24 25 static void 26 cleanup(void) 27 { 28 struct ctrlr_entry *ctrlr_entry, *tmp; 29 struct spdk_nvme_detach_ctx *detach_ctx = NULL; 30 31 TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) { 32 TAILQ_REMOVE(&g_controllers, ctrlr_entry, link); 33 spdk_nvme_cuse_unregister(ctrlr_entry->ctrlr); 34 spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx); 35 free(ctrlr_entry); 36 } 37 38 if (detach_ctx) { 39 spdk_nvme_detach_poll(detach_ctx); 40 } 41 } 42 43 static void 44 usage(char *executable_name) 45 { 46 printf("%s [options]\n", executable_name); 47 printf("options:\n"); 48 printf(" -i shared memory ID [required]\n"); 49 printf(" -m mask core mask for DPDK\n"); 50 printf(" -n channel number of memory channels used for DPDK\n"); 51 printf(" -p core main (primary) core for DPDK\n"); 52 printf(" -s size memory size in MB for DPDK\n"); 53 printf(" -t msec sleep time (ms) between checking for admin completions\n"); 54 printf(" -H show this usage\n"); 55 } 56 57 static bool 58 probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 59 struct spdk_nvme_ctrlr_opts *opts) 60 { 61 /* 62 * Set the io_queue_size to UINT16_MAX to initialize 63 * the controller with the possible largest queue size. 64 */ 65 opts->io_queue_size = UINT16_MAX; 66 return true; 67 } 68 69 static void 70 attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 71 struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) 72 { 73 struct ctrlr_entry *entry; 74 75 entry = malloc(sizeof(struct ctrlr_entry)); 76 if (entry == NULL) { 77 fprintf(stderr, "Malloc error\n"); 78 exit(1); 79 } 80 81 entry->ctrlr = ctrlr; 82 TAILQ_INSERT_TAIL(&g_controllers, entry, link); 83 if (spdk_nvme_cuse_register(ctrlr) != 0) { 84 fprintf(stderr, "could not register ctrlr with cuse\n"); 85 } 86 } 87 88 static int 89 stub_sleep(void *arg) 90 { 91 struct ctrlr_entry *ctrlr_entry, *tmp; 92 93 usleep(g_sleep_time * 1000); 94 TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) { 95 spdk_nvme_ctrlr_process_admin_completions(ctrlr_entry->ctrlr); 96 } 97 return 0; 98 } 99 100 static void 101 stub_start(void *arg1) 102 { 103 int shm_id = (intptr_t)arg1; 104 105 spdk_unaffinitize_thread(); 106 107 if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { 108 fprintf(stderr, "spdk_nvme_probe() failed\n"); 109 exit(1); 110 } 111 112 snprintf(g_path, sizeof(g_path), "/var/run/spdk_stub%d", shm_id); 113 if (mknod(g_path, S_IFREG, 0) != 0) { 114 fprintf(stderr, "could not create sentinel file %s\n", g_path); 115 exit(1); 116 } 117 118 g_poller = SPDK_POLLER_REGISTER(stub_sleep, NULL, 0); 119 } 120 121 static void 122 stub_shutdown(void) 123 { 124 spdk_poller_unregister(&g_poller); 125 unlink(g_path); 126 spdk_app_stop(0); 127 } 128 129 int 130 main(int argc, char **argv) 131 { 132 int ch; 133 struct spdk_app_opts opts = {}; 134 long int val; 135 136 /* default value in opts structure */ 137 spdk_app_opts_init(&opts, sizeof(opts)); 138 139 opts.name = "stub"; 140 opts.rpc_addr = NULL; 141 142 while ((ch = getopt(argc, argv, "i:m:n:p:s:t:H")) != -1) { 143 if (ch == 'm') { 144 opts.reactor_mask = optarg; 145 } else if (ch == '?' || ch == 'H') { 146 usage(argv[0]); 147 exit(EXIT_SUCCESS); 148 } else { 149 val = spdk_strtol(optarg, 10); 150 if (val < 0) { 151 fprintf(stderr, "Converting a string to integer failed\n"); 152 exit(1); 153 } 154 switch (ch) { 155 case 'i': 156 opts.shm_id = val; 157 break; 158 case 'n': 159 opts.mem_channel = val; 160 break; 161 case 'p': 162 opts.main_core = val; 163 break; 164 case 's': 165 opts.mem_size = val; 166 break; 167 case 't': 168 g_sleep_time = val; 169 break; 170 default: 171 usage(argv[0]); 172 exit(EXIT_FAILURE); 173 } 174 } 175 } 176 177 if (opts.shm_id < 0) { 178 fprintf(stderr, "%s: -i shared memory ID must be specified\n", argv[0]); 179 usage(argv[0]); 180 exit(1); 181 } 182 183 opts.shutdown_cb = stub_shutdown; 184 185 ch = spdk_app_start(&opts, stub_start, (void *)(intptr_t)opts.shm_id); 186 187 cleanup(); 188 spdk_app_fini(); 189 190 return ch; 191 } 192