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 : 0 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
34 : : struct spdk_nvme_ctrlr_opts *opts)
35 : : {
36 [ # # ]: 0 : printf("Attaching to %s\n", trid->traddr);
37 : :
38 : 0 : return true;
39 : : }
40 : :
41 : : static void
42 : 10 : 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 : 10 : dev = &devs[num_devs++];
50 [ - + ]: 10 : if (num_devs >= MAX_DEVS) {
51 : 0 : return;
52 : : }
53 : :
54 : 10 : dev->ctrlr = ctrlr;
55 : 10 : nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
56 : 10 : dev->ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
57 : :
58 : 10 : dev->qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
59 [ - + ]: 10 : if (dev->qpair == NULL) {
60 : 0 : failed = 1;
61 : 0 : return;
62 : : }
63 : :
64 [ - + ]: 10 : snprintf(dev->name, sizeof(dev->name), "%s",
65 : 10 : trid->traddr);
66 : :
67 [ - + ]: 10 : printf("Attached to %s\n", dev->name);
68 : : }
69 : :
70 : : static void
71 : 20 : get_feature_test_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl)
72 : : {
73 : 20 : struct dev *dev = cb_arg;
74 : :
75 : 20 : outstanding_commands--;
76 : :
77 [ + + - + : 20 : if (spdk_nvme_cpl_is_error(cpl) && dev->error_expected) {
+ + + - ]
78 [ + - ]: 10 : if (cpl->status.sct != SPDK_NVME_SCT_GENERIC ||
79 [ - + ]: 10 : cpl->status.sc != SPDK_NVME_SC_INVALID_FIELD) {
80 : 0 : failed = 1;
81 : : }
82 [ - + ]: 10 : printf("%s: get features failed as expected\n", dev->name);
83 : 10 : return;
84 : : }
85 : :
86 [ + - + - : 10 : if (!spdk_nvme_cpl_is_error(cpl) && !dev->error_expected) {
+ + + - ]
87 [ - + ]: 10 : printf("%s: get features successfully as expected\n", dev->name);
88 : 10 : return;
89 : : }
90 : :
91 : 0 : failed = 1;
92 : : }
93 : :
94 : : static void
95 : 12 : get_feature_test(bool error_expected)
96 : : {
97 : : struct dev *dev;
98 : 6 : struct spdk_nvme_cmd cmd;
99 : :
100 [ - + ]: 12 : memset(&cmd, 0, sizeof(cmd));
101 : 12 : cmd.opc = SPDK_NVME_OPC_GET_FEATURES;
102 : 12 : cmd.cdw10_bits.get_features.fid = SPDK_NVME_FEAT_NUMBER_OF_QUEUES;
103 : :
104 [ + + ]: 32 : foreach_dev(dev) {
105 : 20 : dev->error_expected = error_expected;
106 [ - + ]: 20 : if (spdk_nvme_ctrlr_cmd_admin_raw(dev->ctrlr, &cmd, NULL, 0,
107 : : 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 : 20 : outstanding_commands++;
113 : : }
114 : :
115 : 12 : cleanup:
116 : :
117 [ + + ]: 5288 : while (outstanding_commands) {
118 [ + + ]: 11723 : foreach_dev(dev) {
119 : 6447 : spdk_nvme_ctrlr_process_admin_completions(dev->ctrlr);
120 : : }
121 : : }
122 : 12 : }
123 : :
124 : : static void
125 : 20 : read_test_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl)
126 : : {
127 : 20 : struct dev *dev = cb_arg;
128 : :
129 : 20 : outstanding_commands--;
130 : 20 : spdk_free(dev->data);
131 : :
132 [ + + - + : 20 : if (spdk_nvme_cpl_is_error(cpl) && dev->error_expected) {
+ + + - ]
133 [ + - ]: 10 : if (cpl->status.sct != SPDK_NVME_SCT_MEDIA_ERROR ||
134 [ - + ]: 10 : cpl->status.sc != SPDK_NVME_SC_UNRECOVERED_READ_ERROR) {
135 : 0 : failed = 1;
136 : : }
137 [ - + ]: 10 : printf("%s: read failed as expected\n", dev->name);
138 : 10 : return;
139 : : }
140 : :
141 [ + - + - : 10 : if (!spdk_nvme_cpl_is_error(cpl) && !dev->error_expected) {
+ + + - ]
142 [ - + ]: 10 : printf("%s: read successfully as expected\n", dev->name);
143 : 10 : return;
144 : : }
145 : :
146 : 0 : failed = 1;
147 : : }
148 : :
149 : : static void
150 : 12 : read_test(bool error_expected)
151 : : {
152 : : struct dev *dev;
153 : :
154 [ + + ]: 32 : foreach_dev(dev) {
155 [ - + ]: 20 : if (dev->ns == NULL) {
156 : 0 : continue;
157 : : }
158 : :
159 : 20 : dev->error_expected = error_expected;
160 : 20 : dev->data = spdk_zmalloc(0x1000, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
161 [ - + ]: 20 : if (!dev->data) {
162 : 0 : failed = 1;
163 : 0 : goto cleanup;
164 : : }
165 : :
166 [ - + ]: 20 : if (spdk_nvme_ns_cmd_read(dev->ns, dev->qpair, dev->data,
167 : : 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 : 20 : outstanding_commands++;
174 : : }
175 : :
176 : 12 : cleanup:
177 : :
178 [ + + ]: 1515 : while (outstanding_commands) {
179 [ + + ]: 3386 : foreach_dev(dev) {
180 : 1883 : spdk_nvme_qpair_process_completions(dev->qpair, 0);
181 : : }
182 : : }
183 : 12 : }
184 : :
185 : : int
186 : 6 : main(int argc, char **argv)
187 : : {
188 : : struct dev *dev;
189 : 3 : struct spdk_env_opts opts;
190 : : int rc;
191 : 6 : struct spdk_nvme_detach_ctx *detach_ctx = NULL;
192 : :
193 : 6 : spdk_env_opts_init(&opts);
194 : 6 : opts.name = "err_injection";
195 : 6 : opts.core_mask = "0x1";
196 : 6 : opts.shm_id = 0;
197 [ - + ]: 6 : if (spdk_env_init(&opts) < 0) {
198 [ # # # # ]: 0 : fprintf(stderr, "Unable to initialize SPDK env\n");
199 : 0 : return 1;
200 : : }
201 : :
202 [ - + ]: 6 : printf("NVMe Error Injection test\n");
203 : :
204 [ - + ]: 6 : if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
205 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
206 : 0 : return 1;
207 : : }
208 : :
209 [ - + ]: 6 : if (failed) {
210 : 0 : goto exit;
211 : : }
212 : :
213 [ - + ]: 6 : if (!num_devs) {
214 [ # # ]: 0 : printf("No NVMe controller found, %s exiting\n", argv[0]);
215 : 0 : return 1;
216 : : }
217 : :
218 [ + + ]: 16 : foreach_dev(dev) {
219 : : /* Admin error injection at submission path */
220 : 10 : rc = spdk_nvme_qpair_add_cmd_error_injection(dev->ctrlr, NULL,
221 : : SPDK_NVME_OPC_GET_FEATURES, true, 5000, 1,
222 : : SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_INVALID_FIELD);
223 : 10 : failed += rc;
224 : : /* IO error injection at completion path */
225 : 10 : rc = spdk_nvme_qpair_add_cmd_error_injection(dev->ctrlr, dev->qpair,
226 : : SPDK_NVME_OPC_READ, false, 0, 1,
227 : : SPDK_NVME_SCT_MEDIA_ERROR, SPDK_NVME_SC_UNRECOVERED_READ_ERROR);
228 : 10 : failed += rc;
229 : : }
230 : :
231 [ - + ]: 6 : if (failed) {
232 : 0 : goto exit;
233 : : }
234 : :
235 : : /* Admin Get Feature, expect error return */
236 : 6 : get_feature_test(true);
237 : : /* Admin Get Feature, expect successful return */
238 : 6 : get_feature_test(false);
239 : : /* Read, expect error return */
240 : 6 : read_test(true);
241 : : /* Read, expect successful return */
242 : 6 : read_test(false);
243 : :
244 : 6 : exit:
245 [ - + ]: 6 : printf("Cleaning up...\n");
246 [ + + ]: 16 : foreach_dev(dev) {
247 : 10 : spdk_nvme_detach_async(dev->ctrlr, &detach_ctx);
248 : : }
249 [ - + ]: 6 : if (detach_ctx) {
250 : 0 : spdk_nvme_detach_poll(detach_ctx);
251 : : }
252 : :
253 : 6 : return failed;
254 : : }
|