Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2019 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/nvme.h"
9 : : #include "spdk/env.h"
10 : : #include "spdk/string.h"
11 : :
12 : : struct ctrlr_entry {
13 : : struct spdk_nvme_ctrlr *ctrlr;
14 : : TAILQ_ENTRY(ctrlr_entry) link;
15 : : char name[1024];
16 : : };
17 : :
18 : : struct ns_entry {
19 : : struct spdk_nvme_ctrlr *ctrlr;
20 : : struct spdk_nvme_ns *ns;
21 : : TAILQ_ENTRY(ns_entry) link;
22 : : struct spdk_nvme_qpair *qpair;
23 : : };
24 : :
25 : : static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers);
26 : : static TAILQ_HEAD(, ns_entry) g_namespaces = TAILQ_HEAD_INITIALIZER(g_namespaces);
27 : : static int g_startup_time = 0;
28 : :
29 : : static bool
30 : 0 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
31 : : struct spdk_nvme_ctrlr_opts *opts)
32 : : {
33 [ # # ]: 0 : printf("Attaching to %s\n", trid->traddr);
34 : :
35 : 0 : return true;
36 : : }
37 : :
38 : : static void
39 : 6 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
40 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
41 : : {
42 : :
43 : : struct ctrlr_entry *entry;
44 : : const struct spdk_nvme_ctrlr_data *cdata;
45 : :
46 : 6 : entry = malloc(sizeof(struct ctrlr_entry));
47 [ - + ]: 6 : if (entry == NULL) {
48 : 0 : perror("ctrlr_entry malloc");
49 : 0 : exit(1);
50 : : }
51 : :
52 [ - + ]: 6 : printf("Attached to %s\n", trid->traddr);
53 : :
54 : : /*
55 : : * spdk_nvme_ctrlr is the logical abstraction in SPDK for an NVMe
56 : : * controller. During initialization, the IDENTIFY data for the
57 : : * controller is read using an NVMe admin command, and that data
58 : : * can be retrieved using spdk_nvme_ctrlr_get_data() to get
59 : : * detailed information on the controller. Refer to the NVMe
60 : : * specification for more details on IDENTIFY for NVMe controllers.
61 : : */
62 : 6 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
63 : :
64 [ - + ]: 6 : snprintf(entry->name, sizeof(entry->name), "%-20.20s (%-20.20s)", cdata->mn, cdata->sn);
65 : :
66 : 6 : entry->ctrlr = ctrlr;
67 : 6 : TAILQ_INSERT_TAIL(&g_controllers, entry, link);
68 : 6 : }
69 : :
70 : : static void
71 : 5 : cleanup(void)
72 : : {
73 : : struct ns_entry *ns_entry, *tmp_ns_entry;
74 : : struct ctrlr_entry *ctrlr_entry, *tmp_ctrlr_entry;
75 : 5 : struct spdk_nvme_detach_ctx *detach_ctx = NULL;
76 : :
77 [ - + ]: 5 : TAILQ_FOREACH_SAFE(ns_entry, &g_namespaces, link, tmp_ns_entry) {
78 [ # # ]: 0 : TAILQ_REMOVE(&g_namespaces, ns_entry, link);
79 : 0 : free(ns_entry);
80 : : }
81 : :
82 [ + + ]: 11 : TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp_ctrlr_entry) {
83 [ + + ]: 6 : TAILQ_REMOVE(&g_controllers, ctrlr_entry, link);
84 : 6 : spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx);
85 : 6 : free(ctrlr_entry);
86 : : }
87 : :
88 [ - + ]: 5 : if (detach_ctx) {
89 : 0 : spdk_nvme_detach_poll(detach_ctx);
90 : : }
91 : 5 : }
92 : :
93 : : static void
94 : 0 : usage(const char *program_name)
95 : : {
96 [ # # ]: 0 : printf("%s [options]", program_name);
97 : 0 : printf("\n");
98 [ # # ]: 0 : printf("options:\n");
99 [ # # ]: 0 : printf(" -t The maximum time needed for startup. The unit is us. The value should be bigger than 0.\n");
100 : 0 : }
101 : :
102 : : static int
103 : 5 : parse_args(int argc, char **argv)
104 : : {
105 : : int op;
106 : :
107 [ + + - + : 10 : while ((op = getopt(argc, argv, "t:")) != -1) {
+ + ]
108 [ + - ]: 5 : switch (op) {
109 : 5 : case 't':
110 : 5 : g_startup_time = spdk_strtol(optarg, 10);
111 [ - + ]: 5 : if (g_startup_time < 0) {
112 [ # # # # ]: 0 : fprintf(stderr, "Invalid nvme startup time\n");
113 : 0 : return g_startup_time;
114 : : }
115 : 5 : break;
116 : 0 : default:
117 : 0 : usage(argv[0]);
118 : 0 : return 1;
119 : : }
120 : : }
121 : :
122 : 5 : return 0;
123 : : }
124 : :
125 : : int
126 : 5 : main(int argc, char **argv)
127 : : {
128 : : int rc;
129 : 2 : struct spdk_env_opts opts;
130 : : uint64_t start_tsc, end_tsc, tsc_diff;
131 : : float time_used_in_usec;
132 : :
133 : 5 : rc = parse_args(argc, argv);
134 [ - + ]: 5 : if (rc != 0) {
135 : 0 : return rc;
136 : : }
137 : :
138 [ - + ]: 5 : if (g_startup_time == 0) {
139 : 0 : usage(argv[0]);
140 : 0 : return 1;
141 : : }
142 : :
143 : 5 : start_tsc = spdk_get_ticks();
144 : : /*
145 : : * SPDK relies on an abstraction around the local environment
146 : : * named env that handles memory allocation and PCI device operations.
147 : : * This library must be initialized first.
148 : : *
149 : : */
150 : 5 : spdk_env_opts_init(&opts);
151 : 5 : opts.name = "startup";
152 : 5 : opts.shm_id = 0;
153 [ - + ]: 5 : if (spdk_env_init(&opts) < 0) {
154 [ # # # # ]: 0 : fprintf(stderr, "Unable to initialize SPDK env\n");
155 : 0 : return 1;
156 : : }
157 : :
158 [ - + ]: 5 : printf("Initializing NVMe Controllers\n");
159 : :
160 : :
161 : : /*
162 : : * Start the SPDK NVMe enumeration process. probe_cb will be called
163 : : * for each NVMe controller found, giving our application a choice on
164 : : * whether to attach to each controller. attach_cb will then be
165 : : * called for each controller after the SPDK NVMe driver has completed
166 : : * initializing the controller we chose to attach.
167 : : */
168 : 5 : rc = spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL);
169 [ - + ]: 5 : if (rc != 0) {
170 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
171 : 0 : cleanup();
172 : 0 : return 1;
173 : : }
174 : :
175 [ - + ]: 5 : if (TAILQ_EMPTY(&g_controllers)) {
176 [ # # # # ]: 0 : fprintf(stderr, "no NVMe controllers found\n");
177 : 0 : return 0;
178 : : }
179 : :
180 : 5 : end_tsc = spdk_get_ticks();
181 : 5 : tsc_diff = end_tsc - start_tsc;
182 : 5 : time_used_in_usec = ((float)tsc_diff) * 1000 * 1000 / spdk_get_ticks_hz();
183 [ - + ]: 5 : printf("Initialization complete.\n");
184 [ - + ]: 5 : printf("Time used:%-16.3f(us).\n", time_used_in_usec);
185 [ - + ]: 5 : if (time_used_in_usec > g_startup_time) {
186 [ # # # # ]: 0 : fprintf(stderr, "Too long time for initialization.\n");
187 : 0 : cleanup();
188 : 0 : return 1;
189 : : }
190 : 5 : cleanup();
191 : 5 : return 0;
192 : : }
|