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(" -p core main (primary) core for DPDK\n"); 53 printf(" -s size memory size in MB for DPDK\n"); 54 printf(" -t msec sleep time (ms) between checking for admin completions\n"); 55 printf(" -q size override default io_queue_size when attaching controllers\n"); 56 printf(" -H show this usage\n"); 57 } 58 59 static bool 60 probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, 61 struct spdk_nvme_ctrlr_opts *opts) 62 { 63 if (g_io_queue_size > 0) { 64 opts->io_queue_size = g_io_queue_size; 65 } 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 snprintf(g_path, sizeof(g_path), "/var/run/spdk_stub%d", shm_id); 106 107 /* If sentinel file already exists from earlier crashed stub, delete 108 * it now to avoid mknod() failure after spdk_nvme_probe() completes. 109 */ 110 unlink(g_path); 111 112 spdk_unaffinitize_thread(); 113 114 if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { 115 fprintf(stderr, "spdk_nvme_probe() failed\n"); 116 exit(1); 117 } 118 119 if (mknod(g_path, S_IFREG, 0) != 0) { 120 fprintf(stderr, "could not create sentinel file %s\n", g_path); 121 exit(1); 122 } 123 124 g_poller = SPDK_POLLER_REGISTER(stub_sleep, NULL, 0); 125 } 126 127 static void 128 stub_shutdown(void) 129 { 130 spdk_poller_unregister(&g_poller); 131 unlink(g_path); 132 spdk_app_stop(0); 133 } 134 135 int 136 main(int argc, char **argv) 137 { 138 int ch; 139 struct spdk_app_opts opts = {}; 140 long int val; 141 142 /* default value in opts structure */ 143 spdk_app_opts_init(&opts, sizeof(opts)); 144 145 opts.name = "stub"; 146 opts.rpc_addr = NULL; 147 opts.env_context = "--proc-type=primary"; 148 149 while ((ch = getopt(argc, argv, "i:m:n:p:q:s:t:H")) != -1) { 150 if (ch == 'm') { 151 opts.reactor_mask = optarg; 152 } else if (ch == '?' || ch == 'H') { 153 usage(argv[0]); 154 exit(EXIT_SUCCESS); 155 } else { 156 val = spdk_strtol(optarg, 10); 157 if (val < 0) { 158 fprintf(stderr, "Converting a string to integer failed\n"); 159 exit(1); 160 } 161 switch (ch) { 162 case 'i': 163 opts.shm_id = val; 164 break; 165 case 'n': 166 opts.mem_channel = val; 167 break; 168 case 'p': 169 opts.main_core = val; 170 break; 171 case 's': 172 opts.mem_size = val; 173 break; 174 case 't': 175 g_sleep_time = val; 176 break; 177 case 'q': 178 g_io_queue_size = val; 179 break; 180 default: 181 usage(argv[0]); 182 exit(EXIT_FAILURE); 183 } 184 } 185 } 186 187 if (opts.shm_id < 0) { 188 fprintf(stderr, "%s: -i shared memory ID must be specified\n", argv[0]); 189 usage(argv[0]); 190 exit(1); 191 } 192 193 opts.shutdown_cb = stub_shutdown; 194 195 ch = spdk_app_start(&opts, stub_start, (void *)(intptr_t)opts.shm_id); 196 197 cleanup(); 198 spdk_app_fini(); 199 200 return ch; 201 } 202