Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2018 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/log.h"
9 : : #include "spdk/nvme.h"
10 : : #include "spdk/env.h"
11 : :
12 : : #define MAX_DEVS 64
13 : :
14 : : struct dev {
15 : : bool error_expected;
16 : : struct spdk_nvme_ctrlr *ctrlr;
17 : : struct spdk_nvme_ns *ns;
18 : : struct spdk_nvme_qpair *qpair;
19 : : void *data;
20 : : char name[SPDK_NVMF_TRADDR_MAX_LEN + 1];
21 : : };
22 : :
23 : : static struct dev devs[MAX_DEVS];
24 : : static int num_devs = 0;
25 : :
26 : : #define foreach_dev(iter) \
27 : : for (iter = devs; iter - devs < num_devs; iter++)
28 : :
29 : : static int outstanding_commands = 0;
30 : : static int failed = 0;
31 : :
32 : : static bool
33 : 1 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
34 : : struct spdk_nvme_ctrlr_opts *opts)
35 : : {
36 [ # # ]: 1 : printf("Attaching to %s\n", trid->traddr);
37 : :
38 : 1 : return true;
39 : : }
40 : :
41 : : static void
42 : 11 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
43 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
44 : : {
45 : : struct dev *dev;
46 : : uint32_t nsid;
47 : :
48 : : /* add to dev list */
49 [ # # # # : 11 : dev = &devs[num_devs++];
# # ]
50 [ - + ]: 11 : if (num_devs >= MAX_DEVS) {
51 : 0 : return;
52 : : }
53 : :
54 [ # # # # ]: 11 : dev->ctrlr = ctrlr;
55 : 11 : nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
56 [ # # # # ]: 11 : dev->ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
57 : :
58 [ # # # # ]: 11 : dev->qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
59 [ - + # # : 11 : if (dev->qpair == NULL) {
# # ]
60 : 0 : failed = 1;
61 : 0 : return;
62 : : }
63 : :
64 [ - + ]: 12 : snprintf(dev->name, sizeof(dev->name), "%s",
65 [ # # ]: 11 : trid->traddr);
66 : :
67 [ - + ]: 11 : printf("Attached to %s\n", dev->name);
68 : 1 : }
69 : :
70 : : static void
71 : 22 : get_feature_test_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl)
72 : : {
73 : 22 : struct dev *dev = cb_arg;
74 : :
75 [ # # ]: 22 : outstanding_commands--;
76 : :
77 [ + + + + : 22 : if (spdk_nvme_cpl_is_error(cpl) && dev->error_expected) {
+ + + - #
# # # # #
# # # # #
# # # ]
78 [ + - - + : 11 : if (cpl->status.sct != SPDK_NVME_SCT_GENERIC ||
# # # # #
# ]
79 [ - + # # : 11 : cpl->status.sc != SPDK_NVME_SC_INVALID_FIELD) {
# # ]
80 : 0 : failed = 1;
81 : 0 : }
82 [ - + ]: 11 : printf("%s: get features failed as expected\n", dev->name);
83 : 11 : return;
84 : : }
85 : :
86 [ + - + - : 11 : if (!spdk_nvme_cpl_is_error(cpl) && !dev->error_expected) {
+ + + - #
# # # # #
# # # # #
# # # #
# ]
87 [ - + ]: 11 : printf("%s: get features successfully as expected\n", dev->name);
88 : 11 : return;
89 : : }
90 : :
91 : 0 : failed = 1;
92 : 2 : }
93 : :
94 : : static void
95 : 14 : get_feature_test(bool error_expected)
96 : : {
97 : : struct dev *dev;
98 : 6 : struct spdk_nvme_cmd cmd;
99 : :
100 [ - + ]: 14 : memset(&cmd, 0, sizeof(cmd));
101 : 14 : cmd.opc = SPDK_NVME_OPC_GET_FEATURES;
102 [ # # # # : 14 : cmd.cdw10_bits.get_features.fid = SPDK_NVME_FEAT_NUMBER_OF_QUEUES;
# # ]
103 : :
104 [ + + # # ]: 36 : foreach_dev(dev) {
105 [ # # # # : 22 : dev->error_expected = error_expected;
# # ]
106 [ - + - + : 26 : if (spdk_nvme_ctrlr_cmd_admin_raw(dev->ctrlr, &cmd, NULL, 0,
- + # # #
# ]
107 : 4 : get_feature_test_cb, dev) != 0) {
108 [ # # ]: 0 : printf("Error: failed to send Get Features command for dev=%p\n", dev);
109 : 0 : failed = 1;
110 : 0 : goto cleanup;
111 : : }
112 [ # # ]: 22 : outstanding_commands++;
113 : 4 : }
114 : :
115 : 12 : cleanup:
116 : :
117 [ + + ]: 10323 : while (outstanding_commands) {
118 [ + + # # ]: 22405 : foreach_dev(dev) {
119 [ # # # # ]: 12096 : spdk_nvme_ctrlr_process_admin_completions(dev->ctrlr);
120 : 2855 : }
121 : : }
122 : 14 : }
123 : :
124 : : static void
125 : 22 : read_test_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl)
126 : : {
127 : 22 : struct dev *dev = cb_arg;
128 : :
129 [ # # ]: 22 : outstanding_commands--;
130 [ # # # # ]: 22 : spdk_free(dev->data);
131 : :
132 [ + + + + : 22 : if (spdk_nvme_cpl_is_error(cpl) && dev->error_expected) {
+ + + - #
# # # # #
# # # # #
# # # ]
133 [ + - - + : 11 : if (cpl->status.sct != SPDK_NVME_SCT_MEDIA_ERROR ||
# # # # #
# ]
134 [ - + # # : 11 : cpl->status.sc != SPDK_NVME_SC_UNRECOVERED_READ_ERROR) {
# # ]
135 : 0 : failed = 1;
136 : 0 : }
137 [ - + ]: 11 : printf("%s: read failed as expected\n", dev->name);
138 : 11 : return;
139 : : }
140 : :
141 [ + - + - : 11 : if (!spdk_nvme_cpl_is_error(cpl) && !dev->error_expected) {
+ + + - #
# # # # #
# # # # #
# # # #
# ]
142 [ - + ]: 11 : printf("%s: read successfully as expected\n", dev->name);
143 : 11 : return;
144 : : }
145 : :
146 : 0 : failed = 1;
147 : 2 : }
148 : :
149 : : static void
150 : 14 : read_test(bool error_expected)
151 : : {
152 : : struct dev *dev;
153 : :
154 [ + + # # ]: 36 : foreach_dev(dev) {
155 [ + + # # : 22 : if (dev->ns == NULL) {
# # ]
156 : 0 : continue;
157 : : }
158 : :
159 [ # # # # : 22 : dev->error_expected = error_expected;
# # ]
160 [ # # # # ]: 22 : dev->data = spdk_zmalloc(0x1000, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
161 [ + + # # : 22 : if (!dev->data) {
# # ]
162 : 0 : failed = 1;
163 : 0 : goto cleanup;
164 : : }
165 : :
166 [ - + - + : 26 : if (spdk_nvme_ns_cmd_read(dev->ns, dev->qpair, dev->data,
- + # # #
# # # # #
# # # # ]
167 : 4 : 0, 1, read_test_cb, dev, 0) != 0) {
168 [ # # ]: 0 : printf("Error: failed to send Read command for dev=%p\n", dev);
169 : 0 : failed = 1;
170 : 0 : goto cleanup;
171 : : }
172 : :
173 [ # # ]: 22 : outstanding_commands++;
174 : 4 : }
175 : :
176 : 12 : cleanup:
177 : :
178 [ + + ]: 5733 : while (outstanding_commands) {
179 [ + + # # ]: 11819 : foreach_dev(dev) {
180 [ # # # # ]: 6100 : spdk_nvme_qpair_process_completions(dev->qpair, 0);
181 : 2506 : }
182 : : }
183 : 14 : }
184 : :
185 : : int
186 : 7 : main(int argc, char **argv)
187 : : {
188 : : struct dev *dev;
189 : 3 : struct spdk_env_opts opts;
190 : : int rc;
191 : 7 : struct spdk_nvme_detach_ctx *detach_ctx = NULL;
192 : :
193 [ # # ]: 7 : opts.opts_size = sizeof(opts);
194 : 7 : spdk_env_opts_init(&opts);
195 : 7 : opts.name = "err_injection";
196 [ # # ]: 7 : opts.core_mask = "0x1";
197 [ # # ]: 7 : opts.shm_id = 0;
198 [ + + ]: 7 : if (spdk_env_init(&opts) < 0) {
199 [ # # # # ]: 0 : fprintf(stderr, "Unable to initialize SPDK env\n");
200 : 0 : return 1;
201 : : }
202 : :
203 [ - + ]: 7 : printf("NVMe Error Injection test\n");
204 : :
205 [ - + ]: 7 : if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
206 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
207 : 0 : return 1;
208 : : }
209 : :
210 [ - + ]: 7 : if (failed) {
211 : 0 : goto exit;
212 : : }
213 : :
214 [ + + ]: 7 : if (!num_devs) {
215 [ # # # # ]: 0 : printf("No NVMe controller found, %s exiting\n", argv[0]);
216 : 0 : return 1;
217 : : }
218 : :
219 [ + + # # ]: 18 : foreach_dev(dev) {
220 : : /* Admin error injection at submission path */
221 [ # # # # ]: 11 : rc = spdk_nvme_qpair_add_cmd_error_injection(dev->ctrlr, NULL,
222 : : SPDK_NVME_OPC_GET_FEATURES, true, 5000, 1,
223 : : SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_INVALID_FIELD);
224 [ # # ]: 11 : failed += rc;
225 : : /* IO error injection at completion path */
226 [ # # # # : 11 : rc = spdk_nvme_qpair_add_cmd_error_injection(dev->ctrlr, dev->qpair,
# # # # ]
227 : : SPDK_NVME_OPC_READ, false, 0, 1,
228 : : SPDK_NVME_SCT_MEDIA_ERROR, SPDK_NVME_SC_UNRECOVERED_READ_ERROR);
229 [ # # ]: 11 : failed += rc;
230 : 1 : }
231 : :
232 [ + + ]: 7 : if (failed) {
233 : 0 : goto exit;
234 : : }
235 : :
236 : : /* Admin Get Feature, expect error return */
237 : 7 : get_feature_test(true);
238 : : /* Admin Get Feature, expect successful return */
239 : 7 : get_feature_test(false);
240 : : /* Read, expect error return */
241 : 7 : read_test(true);
242 : : /* Read, expect successful return */
243 : 7 : read_test(false);
244 : :
245 : 6 : exit:
246 [ - + ]: 7 : printf("Cleaning up...\n");
247 [ + + # # ]: 18 : foreach_dev(dev) {
248 [ # # # # ]: 11 : spdk_nvme_detach_async(dev->ctrlr, &detach_ctx);
249 : 1 : }
250 [ - + ]: 7 : if (detach_ctx) {
251 : 1 : spdk_nvme_detach_poll(detach_ctx);
252 : 1 : }
253 : :
254 : 7 : return failed;
255 : 1 : }
|