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 static uint32_t g_io_queue_size; 18 19 struct ctrlr_entry { 20 struct spdk_nvme_ctrlr *ctrlr; 21 TAILQ_ENTRY(ctrlr_entry) link; 22 }; 23 24 static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers); 25 26 static void 27 cleanup(void) 28 { 29 struct ctrlr_entry *ctrlr_entry, *tmp; 30 struct spdk_nvme_detach_ctx *detach_ctx = NULL; 31 32 TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) { 33 TAILQ_REMOVE(&g_controllers, ctrlr_entry, link); 34 spdk_nvme_cuse_unregister(ctrlr_entry->ctrlr); 35 spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx); 36 free(ctrlr_entry); 37 } 38 39 if (detach_ctx) { 40 spdk_nvme_detach_poll(detach_ctx); 41 } 42 } 43 44 static void 45 usage(char *executable_name) 46 { 47 printf("%s [options]\n", executable_name); 48 printf("options:\n"); 49 printf(" -i shared memory ID [required]\n"); 50 printf(" -m mask core mask for DPDK\n"); 51 printf(" -n channel number of memory channels used for DPDK\n"); 52 printf(" -L flag enable log flag\n"); 53 printf(" -p core main (primary) core for DPDK\n"); 54 printf(" -s size memory size in MB for DPDK\n"); 55 printf(" -t msec sleep time (ms) between checking for admin completions\n"); 56 printf(" -q size override default io_queue_size when attaching controllers\n"); 57 printf(" -H show this usage\n"); 58 } 59 60 static bool 61 probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 62 struct spdk_nvme_ctrlr_opts *opts) 63 { 64 if (g_io_queue_size > 0) { 65 opts->io_queue_size = g_io_queue_size; 66 } 67 return true; 68 } 69 70 static void 71 attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 72 struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) 73 { 74 struct ctrlr_entry *entry; 75 76 entry = malloc(sizeof(struct ctrlr_entry)); 77 if (entry == NULL) { 78 fprintf(stderr, "Malloc error\n"); 79 exit(1); 80 } 81 82 entry->ctrlr = ctrlr; 83 TAILQ_INSERT_TAIL(&g_controllers, entry, link); 84 if (spdk_nvme_cuse_register(ctrlr) != 0) { 85 fprintf(stderr, "could not register ctrlr with cuse\n"); 86 } 87 } 88 89 static int 90 stub_sleep(void *arg) 91 { 92 struct ctrlr_entry *ctrlr_entry, *tmp; 93 94 usleep(g_sleep_time * 1000); 95 TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) { 96 spdk_nvme_ctrlr_process_admin_completions(ctrlr_entry->ctrlr); 97 } 98 return 0; 99 } 100 101 static void 102 stub_start(void *arg1) 103 { 104 int shm_id = (intptr_t)arg1; 105 106 snprintf(g_path, sizeof(g_path), "/var/run/spdk_stub%d", shm_id); 107 108 /* If sentinel file already exists from earlier crashed stub, delete 109 * it now to avoid mknod() failure after spdk_nvme_probe() completes. 110 */ 111 unlink(g_path); 112 113 spdk_unaffinitize_thread(); 114 115 if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { 116 fprintf(stderr, "spdk_nvme_probe() failed\n"); 117 exit(1); 118 } 119 120 if (mknod(g_path, S_IFREG, 0) != 0) { 121 fprintf(stderr, "could not create sentinel file %s\n", g_path); 122 exit(1); 123 } 124 125 g_poller = SPDK_POLLER_REGISTER(stub_sleep, NULL, 0); 126 } 127 128 static void 129 stub_shutdown(void) 130 { 131 spdk_poller_unregister(&g_poller); 132 unlink(g_path); 133 spdk_app_stop(0); 134 } 135 136 int 137 main(int argc, char **argv) 138 { 139 int ch; 140 struct spdk_app_opts opts = {}; 141 long int val; 142 143 /* default value in opts structure */ 144 spdk_app_opts_init(&opts, sizeof(opts)); 145 146 opts.name = "stub"; 147 opts.rpc_addr = NULL; 148 opts.env_context = "--proc-type=primary"; 149 150 while ((ch = getopt(argc, argv, "i:m:n:p:q:s:t:HL:")) != -1) { 151 if (ch == 'm') { 152 opts.reactor_mask = optarg; 153 } else if (ch == 'L') { 154 if (spdk_log_set_flag(optarg) != 0) { 155 SPDK_ERRLOG("unknown flag: %s\n", optarg); 156 usage(argv[0]); 157 exit(EXIT_FAILURE); 158 } 159 #ifdef DEBUG 160 opts.print_level = SPDK_LOG_DEBUG; 161 #endif 162 } else if (ch == '?' || ch == 'H') { 163 usage(argv[0]); 164 exit(EXIT_SUCCESS); 165 } else { 166 val = spdk_strtol(optarg, 10); 167 if (val < 0) { 168 fprintf(stderr, "Converting a string to integer failed\n"); 169 exit(1); 170 } 171 switch (ch) { 172 case 'i': 173 opts.shm_id = val; 174 break; 175 case 'n': 176 opts.mem_channel = val; 177 break; 178 case 'p': 179 opts.main_core = val; 180 break; 181 case 's': 182 opts.mem_size = val; 183 break; 184 case 't': 185 g_sleep_time = val; 186 break; 187 case 'q': 188 g_io_queue_size = val; 189 break; 190 default: 191 usage(argv[0]); 192 exit(EXIT_FAILURE); 193 } 194 } 195 } 196 197 if (opts.shm_id < 0) { 198 fprintf(stderr, "%s: -i shared memory ID must be specified\n", argv[0]); 199 usage(argv[0]); 200 exit(1); 201 } 202 203 opts.shutdown_cb = stub_shutdown; 204 205 ch = spdk_app_start(&opts, stub_start, (void *)(intptr_t)opts.shm_id); 206 207 cleanup(); 208 spdk_app_fini(); 209 210 return ch; 211 } 212