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