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