Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2021 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/env.h"
9 : : #include "spdk/nvme.h"
10 : : #include "spdk/queue.h"
11 : : #include "spdk/string.h"
12 : : #include "spdk/util.h"
13 : : #include "spdk/log.h"
14 : : #include "spdk/likely.h"
15 : : #include "spdk/endian.h"
16 : :
17 : : /* The flag is used to exit the program while keep alive fails on the transport */
18 : : static bool g_exit;
19 : : static struct spdk_nvme_ctrlr *g_ctrlr;
20 : : static struct spdk_nvme_transport_id g_trid;
21 : : static const char *g_hostnqn;
22 : : static bool g_discovery_in_progress;
23 : : static bool g_pending_discovery;
24 : :
25 : : static void get_discovery_log_page(struct spdk_nvme_ctrlr *ctrlr);
26 : :
27 : : static void
28 : 0 : print_discovery_log(struct spdk_nvmf_discovery_log_page *log_page)
29 : : {
30 : : uint64_t numrec;
31 : 0 : char str[512];
32 : : uint32_t i;
33 : :
34 [ # # ]: 0 : printf("Discovery Log Page\n");
35 [ # # ]: 0 : printf("==================\n");
36 : :
37 : 0 : numrec = from_le64(&log_page->numrec);
38 : :
39 [ # # ]: 0 : printf("Generation Counter: %" PRIu64 "\n", from_le64(&log_page->genctr));
40 [ # # ]: 0 : printf("Number of Records: %" PRIu64 "\n", numrec);
41 [ # # ]: 0 : printf("Record Format: %" PRIu16 "\n", from_le16(&log_page->recfmt));
42 : 0 : printf("\n");
43 : :
44 [ # # ]: 0 : for (i = 0; i < numrec; i++) {
45 : 0 : struct spdk_nvmf_discovery_log_page_entry *entry = &log_page->entries[i];
46 : :
47 [ # # ]: 0 : printf("Discovery Log Entry %u\n", i);
48 [ # # ]: 0 : printf("----------------------\n");
49 : 0 : printf("Transport Type: %u (%s)\n",
50 [ # # ]: 0 : entry->trtype, spdk_nvme_transport_id_trtype_str(entry->trtype));
51 : 0 : printf("Address Family: %u (%s)\n",
52 [ # # ]: 0 : entry->adrfam, spdk_nvme_transport_id_adrfam_str(entry->adrfam));
53 : 0 : printf("Subsystem Type: %u (%s)\n",
54 [ # # ]: 0 : entry->subtype,
55 [ # # ]: 0 : entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY ? "Referral to a discovery service" :
56 [ # # ]: 0 : entry->subtype == SPDK_NVMF_SUBTYPE_NVME ? "NVM Subsystem" :
57 [ # # ]: 0 : entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY_CURRENT ? "Current Discovery Subsystem" :
58 : : "Unknown");
59 [ # # ]: 0 : printf("Port ID: %" PRIu16 " (0x%04" PRIx16 ")\n",
60 : 0 : from_le16(&entry->portid), from_le16(&entry->portid));
61 [ # # ]: 0 : printf("Controller ID: %" PRIu16 " (0x%04" PRIx16 ")\n",
62 : 0 : from_le16(&entry->cntlid), from_le16(&entry->cntlid));
63 [ # # ]: 0 : snprintf(str, sizeof(entry->trsvcid) + 1, "%s", entry->trsvcid);
64 [ # # ]: 0 : printf("Transport Service Identifier: %s\n", str);
65 [ # # ]: 0 : snprintf(str, sizeof(entry->subnqn) + 1, "%s", entry->subnqn);
66 [ # # ]: 0 : printf("NVM Subsystem Qualified Name: %s\n", str);
67 [ # # ]: 0 : snprintf(str, sizeof(entry->traddr) + 1, "%s", entry->traddr);
68 [ # # ]: 0 : printf("Transport Address: %s\n", str);
69 : : }
70 : 0 : }
71 : :
72 : : static void
73 : 0 : get_log_page_completion(void *cb_arg, int rc, const struct spdk_nvme_cpl *cpl,
74 : : struct spdk_nvmf_discovery_log_page *log_page)
75 : : {
76 [ # # # # : 0 : if (rc || spdk_nvme_cpl_is_error(cpl)) {
# # ]
77 [ # # # # ]: 0 : fprintf(stderr, "get discovery log page failed\n");
78 : 0 : exit(1);
79 : : }
80 : :
81 : 0 : print_discovery_log(log_page);
82 : 0 : free(log_page);
83 : :
84 : 0 : g_discovery_in_progress = false;
85 [ # # # # ]: 0 : if (g_pending_discovery) {
86 : 0 : get_discovery_log_page(g_ctrlr);
87 : 0 : g_pending_discovery = false;
88 : : }
89 : 0 : }
90 : :
91 : : static void
92 : 0 : get_discovery_log_page(struct spdk_nvme_ctrlr *ctrlr)
93 : : {
94 [ # # # # ]: 0 : if (g_discovery_in_progress) {
95 : 0 : g_pending_discovery = true;
96 : : }
97 : :
98 : 0 : g_discovery_in_progress = true;
99 : :
100 [ # # ]: 0 : if (spdk_nvme_ctrlr_get_discovery_log_page(ctrlr, get_log_page_completion, NULL)) {
101 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ctrlr_get_discovery_log_page() failed\n");
102 : 0 : exit(1);
103 : : }
104 : 0 : }
105 : :
106 : : static void
107 : 0 : usage(char *program_name)
108 : : {
109 [ # # ]: 0 : printf("%s options", program_name);
110 : 0 : printf("\n");
111 [ # # ]: 0 : printf("\t[-r, --transport <fmt> Transport ID for NVMeoF discovery subsystem]\n");
112 [ # # ]: 0 : printf("\t Format: 'key:value [key:value] ...'\n");
113 [ # # ]: 0 : printf("\t Keys:\n");
114 [ # # ]: 0 : printf("\t trtype Transport type (e.g. TCP, RDMA)\n");
115 [ # # ]: 0 : printf("\t adrfam Address family (e.g. IPv4, IPv6)\n");
116 [ # # ]: 0 : printf("\t traddr Transport address (e.g. 192.168.100.8)\n");
117 [ # # ]: 0 : printf("\t trsvcid Transport service identifier (e.g. 4420)\n");
118 [ # # ]: 0 : printf("\t Example: -r 'trtype:TCP adrfam:IPv4 traddr:192.168.100.8 trsvcid:4420'\n");
119 : 0 : printf("\t");
120 : 0 : spdk_log_usage(stdout, "-T");
121 : : #ifdef DEBUG
122 [ # # ]: 0 : printf("\t[-G, --enable-debug enable debug logging]\n");
123 : : #else
124 : : printf("\t[-G, --enable-debug enable debug logging (flag disabled, must reconfigure with --enable-debug)]\n");
125 : : #endif
126 [ # # ]: 0 : printf("\t[-H, --hostnqn Host NQN]\n");
127 : 0 : }
128 : :
129 : : static void
130 : 0 : set_trid(const char *trid_str)
131 : : {
132 : : struct spdk_nvme_transport_id *trid;
133 : :
134 : 0 : trid = &g_trid;
135 : 0 : trid->trtype = SPDK_NVME_TRANSPORT_PCIE;
136 [ # # ]: 0 : snprintf(trid->subnqn, sizeof(trid->subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
137 : :
138 [ # # ]: 0 : if (spdk_nvme_transport_id_parse(trid, trid_str) != 0) {
139 [ # # # # ]: 0 : fprintf(stderr, "Invalid transport ID format '%s'\n", trid_str);
140 : 0 : exit(1);
141 : : }
142 : :
143 : 0 : spdk_nvme_transport_id_populate_trstring(trid,
144 : : spdk_nvme_transport_id_trtype_str(trid->trtype));
145 : 0 : }
146 : :
147 : : #define AER_GETOPT_SHORT "r:GH:T:"
148 : :
149 : : static const struct option g_aer_cmdline_opts[] = {
150 : : #define AER_TRANSPORT 'r'
151 : : {"transport", required_argument, NULL, AER_TRANSPORT},
152 : : #define AER_ENABLE_DEBUG 'G'
153 : : {"enable-debug", no_argument, NULL, AER_ENABLE_DEBUG},
154 : : #define AER_HOSTNQN 'H'
155 : : {"hostnqn", required_argument, NULL, AER_HOSTNQN},
156 : : #define AER_LOG_FLAG 'T'
157 : : {"logflag", required_argument, NULL, AER_LOG_FLAG},
158 : : /* Should be the last element */
159 : : {0, 0, 0, 0}
160 : : };
161 : :
162 : : static int
163 : 0 : parse_args(int argc, char **argv, struct spdk_env_opts *env_opts)
164 : : {
165 : 0 : int op, long_idx;
166 : : int rc;
167 : :
168 [ # # # # : 0 : while ((op = getopt_long(argc, argv, AER_GETOPT_SHORT, g_aer_cmdline_opts, &long_idx)) != -1) {
# # ]
169 [ # # # # : 0 : switch (op) {
# ]
170 : 0 : case AER_TRANSPORT:
171 : 0 : set_trid(optarg);
172 : 0 : break;
173 : 0 : case AER_ENABLE_DEBUG:
174 : : #ifndef DEBUG
175 : : fprintf(stderr, "%s must be configured with --enable-debug for -G flag\n",
176 : : argv[0]);
177 : : usage(argv[0]);
178 : : return 1;
179 : : #else
180 : 0 : spdk_log_set_flag("nvme");
181 : 0 : spdk_log_set_print_level(SPDK_LOG_DEBUG);
182 : 0 : break;
183 : : #endif
184 : 0 : case AER_HOSTNQN:
185 : 0 : g_hostnqn = optarg;
186 : 0 : break;
187 : 0 : case AER_LOG_FLAG:
188 : 0 : rc = spdk_log_set_flag(optarg);
189 [ # # ]: 0 : if (rc < 0) {
190 [ # # # # ]: 0 : fprintf(stderr, "unknown flag\n");
191 : 0 : usage(argv[0]);
192 : 0 : exit(EXIT_FAILURE);
193 : : }
194 : : #ifdef DEBUG
195 : 0 : spdk_log_set_print_level(SPDK_LOG_DEBUG);
196 : : #endif
197 : 0 : break;
198 : 0 : default:
199 : 0 : usage(argv[0]);
200 : 0 : return 1;
201 : : }
202 : : }
203 : :
204 : 0 : return 0;
205 : : }
206 : :
207 : : static void
208 : 0 : aer_cb(void *arg, const struct spdk_nvme_cpl *cpl)
209 : : {
210 : 0 : uint32_t log_page_id = (cpl->cdw0 & 0xFF0000) >> 16;
211 : :
212 [ # # # # ]: 0 : if (spdk_nvme_cpl_is_error(cpl)) {
213 [ # # # # ]: 0 : fprintf(stderr, "aer failed\n");
214 : 0 : exit(1);
215 : : }
216 : :
217 [ # # ]: 0 : if (log_page_id != SPDK_NVME_LOG_DISCOVERY) {
218 [ # # # # ]: 0 : fprintf(stderr, "unexpected log page 0x%x\n", log_page_id);
219 : 0 : exit(1);
220 : : }
221 : :
222 : 0 : get_discovery_log_page(g_ctrlr);
223 : 0 : }
224 : :
225 : : static void
226 : 0 : sig_handler(int signo)
227 : : {
228 : 0 : g_exit = true;
229 : 0 : }
230 : :
231 : : static void
232 : 0 : setup_sig_handlers(void)
233 : : {
234 : 0 : struct sigaction sigact = {};
235 : : int rc;
236 : :
237 : 0 : sigemptyset(&sigact.sa_mask);
238 : 0 : sigact.sa_handler = sig_handler;
239 : 0 : rc = sigaction(SIGINT, &sigact, NULL);
240 [ # # ]: 0 : if (rc < 0) {
241 [ # # ]: 0 : fprintf(stderr, "sigaction(SIGINT) failed, errno %d (%s)\n", errno, strerror(errno));
242 : 0 : exit(1);
243 : : }
244 : :
245 : 0 : rc = sigaction(SIGTERM, &sigact, NULL);
246 [ # # ]: 0 : if (rc < 0) {
247 [ # # ]: 0 : fprintf(stderr, "sigaction(SIGTERM) failed, errno %d (%s)\n", errno, strerror(errno));
248 : 0 : exit(1);
249 : : }
250 : 0 : }
251 : :
252 : : int
253 : 0 : main(int argc, char **argv)
254 : : {
255 : : int rc;
256 : 0 : struct spdk_env_opts opts;
257 : 0 : struct spdk_nvme_ctrlr_opts ctrlr_opts;
258 : 0 : struct spdk_nvme_detach_ctx *detach_ctx = NULL;
259 : :
260 : 0 : spdk_env_opts_init(&opts);
261 : 0 : opts.name = "discovery_aer";
262 : 0 : rc = parse_args(argc, argv, &opts);
263 [ # # ]: 0 : if (rc != 0) {
264 : 0 : exit(1);
265 : : }
266 : :
267 [ # # ]: 0 : if (g_trid.subnqn[0] == '\0') {
268 [ # # ]: 0 : fprintf(stderr, "Discovery subsystem transport ID not specified\n");
269 : 0 : usage(argv[0]);
270 : 0 : exit(1);
271 : : }
272 : :
273 [ # # ]: 0 : if (spdk_env_init(&opts) < 0) {
274 [ # # ]: 0 : fprintf(stderr, "Unable to initialize SPDK env\n");
275 : 0 : exit(1);
276 : : }
277 : :
278 : 0 : setup_sig_handlers();
279 : :
280 : 0 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctrlr_opts, sizeof(ctrlr_opts));
281 [ # # ]: 0 : if (g_hostnqn) {
282 : 0 : snprintf(ctrlr_opts.hostnqn, sizeof(ctrlr_opts.hostnqn), "%s", g_hostnqn);
283 : : }
284 : :
285 : 0 : g_ctrlr = spdk_nvme_connect(&g_trid, &ctrlr_opts, sizeof(ctrlr_opts));
286 [ # # ]: 0 : if (g_ctrlr == NULL) {
287 [ # # ]: 0 : fprintf(stderr, "spdk_nvme_connect() failed for transport address '%s'\n", g_trid.traddr);
288 : 0 : exit(1);
289 : : }
290 : :
291 : 0 : spdk_nvme_ctrlr_register_aer_callback(g_ctrlr, aer_cb, NULL);
292 : :
293 : 0 : get_discovery_log_page(g_ctrlr);
294 : :
295 [ # # # # ]: 0 : while (spdk_likely(!g_exit)) {
296 : 0 : spdk_nvme_ctrlr_process_admin_completions(g_ctrlr);
297 : : }
298 : :
299 : 0 : spdk_nvme_detach_async(g_ctrlr, &detach_ctx);
300 : :
301 [ # # ]: 0 : if (detach_ctx) {
302 : 0 : spdk_nvme_detach_poll(detach_ctx);
303 : : }
304 : :
305 : 0 : spdk_env_fini();
306 : :
307 : 0 : return 0;
308 : : }
|