]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright (c) Intel Corporation. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * * Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * * Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * * Neither the name of Intel Corporation nor the names of its | |
18 | * contributors may be used to endorse or promote products derived | |
19 | * from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
25 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * NVMe end-to-end data protection test | |
36 | */ | |
37 | ||
11fdf7f2 | 38 | #include "spdk/stdinc.h" |
7c673cae FG |
39 | |
40 | #include "spdk/nvme.h" | |
41 | #include "spdk/env.h" | |
11fdf7f2 TL |
42 | #include "spdk/crc16.h" |
43 | #include "spdk/endian.h" | |
f67539c2 | 44 | #include "spdk/memory.h" |
9f95a23c | 45 | |
7c673cae FG |
46 | #define MAX_DEVS 64 |
47 | ||
48 | #define DATA_PATTERN 0x5A | |
49 | ||
50 | struct dev { | |
51 | struct spdk_nvme_ctrlr *ctrlr; | |
11fdf7f2 | 52 | char name[SPDK_NVMF_TRADDR_MAX_LEN + 1]; |
7c673cae FG |
53 | }; |
54 | ||
55 | static struct dev devs[MAX_DEVS]; | |
56 | static int num_devs = 0; | |
57 | ||
58 | #define foreach_dev(iter) \ | |
59 | for (iter = devs; iter - devs < num_devs; iter++) | |
60 | ||
61 | static int io_complete_flag = 0; | |
62 | ||
63 | struct io_request { | |
64 | void *contig; | |
65 | void *metadata; | |
66 | bool use_extended_lba; | |
67 | bool use_sgl; | |
68 | uint32_t sgl_offset; | |
69 | uint32_t buf_size; | |
70 | uint64_t lba; | |
71 | uint32_t lba_count; | |
72 | uint16_t apptag_mask; | |
73 | uint16_t apptag; | |
74 | }; | |
75 | ||
76 | static void | |
77 | io_complete(void *ctx, const struct spdk_nvme_cpl *cpl) | |
78 | { | |
11fdf7f2 | 79 | if (spdk_nvme_cpl_is_error(cpl)) { |
7c673cae | 80 | io_complete_flag = 2; |
11fdf7f2 | 81 | } else { |
7c673cae | 82 | io_complete_flag = 1; |
11fdf7f2 | 83 | } |
7c673cae FG |
84 | } |
85 | ||
86 | static void | |
87 | ns_data_buffer_reset(struct spdk_nvme_ns *ns, struct io_request *req, uint8_t data_pattern) | |
88 | { | |
89 | uint32_t md_size, sector_size; | |
90 | uint32_t i, offset = 0; | |
91 | uint8_t *buf; | |
92 | ||
93 | sector_size = spdk_nvme_ns_get_sector_size(ns); | |
94 | md_size = spdk_nvme_ns_get_md_size(ns); | |
95 | ||
96 | for (i = 0; i < req->lba_count; i++) { | |
11fdf7f2 | 97 | if (req->use_extended_lba) { |
7c673cae | 98 | offset = (sector_size + md_size) * i; |
11fdf7f2 | 99 | } else { |
7c673cae | 100 | offset = sector_size * i; |
11fdf7f2 | 101 | } |
7c673cae FG |
102 | |
103 | buf = (uint8_t *)req->contig + offset; | |
104 | memset(buf, data_pattern, sector_size); | |
105 | } | |
106 | } | |
107 | ||
108 | static void nvme_req_reset_sgl(void *cb_arg, uint32_t sgl_offset) | |
109 | { | |
110 | struct io_request *req = (struct io_request *)cb_arg; | |
111 | ||
112 | req->sgl_offset = sgl_offset; | |
113 | return; | |
114 | } | |
115 | ||
116 | static int nvme_req_next_sge(void *cb_arg, void **address, uint32_t *length) | |
117 | { | |
118 | struct io_request *req = (struct io_request *)cb_arg; | |
119 | void *payload; | |
120 | ||
121 | payload = req->contig + req->sgl_offset; | |
122 | *address = payload; | |
123 | ||
124 | *length = req->buf_size - req->sgl_offset; | |
125 | ||
126 | return 0; | |
127 | } | |
128 | ||
129 | /* CRC-16 Guard checked for extended lba format */ | |
130 | static uint32_t dp_guard_check_extended_lba_test(struct spdk_nvme_ns *ns, struct io_request *req, | |
131 | uint32_t *io_flags) | |
132 | { | |
133 | struct spdk_nvme_protection_info *pi; | |
134 | uint32_t md_size, sector_size; | |
135 | ||
136 | req->lba_count = 2; | |
137 | ||
138 | /* extended LBA only for the test case */ | |
11fdf7f2 | 139 | if (!(spdk_nvme_ns_supports_extended_lba(ns))) { |
7c673cae | 140 | return 0; |
11fdf7f2 | 141 | } |
7c673cae FG |
142 | |
143 | sector_size = spdk_nvme_ns_get_sector_size(ns); | |
144 | md_size = spdk_nvme_ns_get_md_size(ns); | |
f67539c2 TL |
145 | req->contig = spdk_zmalloc((sector_size + md_size) * req->lba_count, 0x1000, NULL, |
146 | SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); | |
147 | assert(req->contig); | |
7c673cae | 148 | |
f67539c2 | 149 | req->lba = 0; |
7c673cae FG |
150 | req->use_extended_lba = true; |
151 | req->use_sgl = true; | |
152 | req->buf_size = (sector_size + md_size) * req->lba_count; | |
153 | req->metadata = NULL; | |
154 | ns_data_buffer_reset(ns, req, DATA_PATTERN); | |
155 | pi = (struct spdk_nvme_protection_info *)(req->contig + sector_size + md_size - 8); | |
156 | /* big-endian for guard */ | |
9f95a23c | 157 | to_be16(&pi->guard, spdk_crc16_t10dif(0, req->contig, sector_size)); |
7c673cae FG |
158 | |
159 | pi = (struct spdk_nvme_protection_info *)(req->contig + (sector_size + md_size) * 2 - 8); | |
9f95a23c | 160 | to_be16(&pi->guard, spdk_crc16_t10dif(0, req->contig + sector_size + md_size, sector_size)); |
7c673cae FG |
161 | |
162 | *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_GUARD; | |
163 | ||
164 | return req->lba_count; | |
165 | } | |
166 | ||
167 | /* | |
168 | * No protection information with PRACT setting to 1, | |
169 | * both extended LBA format and separate metadata can | |
170 | * run the test case. | |
171 | */ | |
172 | static uint32_t dp_with_pract_test(struct spdk_nvme_ns *ns, struct io_request *req, | |
173 | uint32_t *io_flags) | |
174 | { | |
f67539c2 | 175 | uint32_t md_size, sector_size, data_len; |
7c673cae FG |
176 | |
177 | req->lba_count = 8; | |
178 | ||
179 | sector_size = spdk_nvme_ns_get_sector_size(ns); | |
f67539c2 TL |
180 | md_size = spdk_nvme_ns_get_md_size(ns); |
181 | if (md_size == 8) { | |
182 | /* No additional metadata buffer provided */ | |
183 | data_len = sector_size * req->lba_count; | |
184 | } else { | |
185 | data_len = (sector_size + md_size) * req->lba_count; | |
11fdf7f2 | 186 | } |
f67539c2 TL |
187 | req->contig = spdk_zmalloc(data_len, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, |
188 | SPDK_MALLOC_DMA); | |
189 | assert(req->contig); | |
190 | ||
191 | req->metadata = spdk_zmalloc(md_size * req->lba_count, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, | |
192 | SPDK_MALLOC_DMA); | |
193 | assert(req->metadata); | |
7c673cae FG |
194 | |
195 | switch (spdk_nvme_ns_get_pi_type(ns)) { | |
196 | case SPDK_NVME_FMT_NVM_PROTECTION_TYPE3: | |
197 | *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_GUARD | SPDK_NVME_IO_FLAGS_PRACT; | |
198 | break; | |
199 | case SPDK_NVME_FMT_NVM_PROTECTION_TYPE1: | |
200 | case SPDK_NVME_FMT_NVM_PROTECTION_TYPE2: | |
201 | *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_GUARD | SPDK_NVME_IO_FLAGS_PRCHK_REFTAG | | |
202 | SPDK_NVME_IO_FLAGS_PRACT; | |
203 | break; | |
204 | default: | |
205 | *io_flags = 0; | |
206 | break; | |
207 | } | |
208 | ||
f67539c2 | 209 | req->lba = 0; |
7c673cae | 210 | req->use_extended_lba = false; |
7c673cae FG |
211 | |
212 | return req->lba_count; | |
213 | } | |
214 | ||
215 | /* Block Reference Tag checked for TYPE1 and TYPE2 with PRACT setting to 0 */ | |
216 | static uint32_t dp_without_pract_extended_lba_test(struct spdk_nvme_ns *ns, struct io_request *req, | |
217 | uint32_t *io_flags) | |
218 | { | |
219 | struct spdk_nvme_protection_info *pi; | |
220 | uint32_t md_size, sector_size; | |
221 | ||
222 | req->lba_count = 2; | |
223 | ||
224 | switch (spdk_nvme_ns_get_pi_type(ns)) { | |
225 | case SPDK_NVME_FMT_NVM_PROTECTION_TYPE3: | |
226 | return 0; | |
227 | default: | |
228 | break; | |
229 | } | |
230 | ||
231 | /* extended LBA only for the test case */ | |
11fdf7f2 | 232 | if (!(spdk_nvme_ns_supports_extended_lba(ns))) { |
7c673cae | 233 | return 0; |
11fdf7f2 | 234 | } |
7c673cae FG |
235 | |
236 | sector_size = spdk_nvme_ns_get_sector_size(ns); | |
237 | md_size = spdk_nvme_ns_get_md_size(ns); | |
f67539c2 TL |
238 | req->contig = spdk_zmalloc((sector_size + md_size) * req->lba_count, 0x1000, NULL, |
239 | SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); | |
240 | assert(req->contig); | |
7c673cae | 241 | |
f67539c2 | 242 | req->lba = 0; |
7c673cae FG |
243 | req->use_extended_lba = true; |
244 | req->metadata = NULL; | |
245 | pi = (struct spdk_nvme_protection_info *)(req->contig + sector_size + md_size - 8); | |
246 | /* big-endian for reference tag */ | |
11fdf7f2 | 247 | to_be32(&pi->ref_tag, (uint32_t)req->lba); |
7c673cae FG |
248 | |
249 | pi = (struct spdk_nvme_protection_info *)(req->contig + (sector_size + md_size) * 2 - 8); | |
250 | /* is incremented for each subsequent logical block */ | |
11fdf7f2 | 251 | to_be32(&pi->ref_tag, (uint32_t)(req->lba + 1)); |
7c673cae FG |
252 | |
253 | *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_REFTAG; | |
254 | ||
255 | return req->lba_count; | |
256 | } | |
257 | ||
258 | /* LBA + Metadata without data protection bits setting */ | |
259 | static uint32_t dp_without_flags_extended_lba_test(struct spdk_nvme_ns *ns, struct io_request *req, | |
260 | uint32_t *io_flags) | |
261 | { | |
262 | uint32_t md_size, sector_size; | |
263 | ||
264 | req->lba_count = 16; | |
265 | ||
266 | /* extended LBA only for the test case */ | |
11fdf7f2 | 267 | if (!(spdk_nvme_ns_supports_extended_lba(ns))) { |
7c673cae | 268 | return 0; |
11fdf7f2 | 269 | } |
7c673cae FG |
270 | |
271 | sector_size = spdk_nvme_ns_get_sector_size(ns); | |
272 | md_size = spdk_nvme_ns_get_md_size(ns); | |
f67539c2 TL |
273 | req->contig = spdk_zmalloc((sector_size + md_size) * req->lba_count, 0x1000, NULL, |
274 | SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); | |
275 | assert(req->contig); | |
7c673cae | 276 | |
f67539c2 | 277 | req->lba = 0; |
7c673cae FG |
278 | req->use_extended_lba = true; |
279 | req->metadata = NULL; | |
280 | *io_flags = 0; | |
281 | ||
282 | return req->lba_count; | |
283 | } | |
284 | ||
285 | /* Block Reference Tag checked for TYPE1 and TYPE2 with PRACT setting to 0 */ | |
286 | static uint32_t dp_without_pract_separate_meta_test(struct spdk_nvme_ns *ns, struct io_request *req, | |
287 | uint32_t *io_flags) | |
288 | { | |
289 | struct spdk_nvme_protection_info *pi; | |
290 | uint32_t md_size, sector_size; | |
291 | ||
292 | req->lba_count = 2; | |
293 | ||
294 | switch (spdk_nvme_ns_get_pi_type(ns)) { | |
295 | case SPDK_NVME_FMT_NVM_PROTECTION_TYPE3: | |
296 | return 0; | |
297 | default: | |
298 | break; | |
299 | } | |
300 | ||
301 | /* separate metadata payload for the test case */ | |
11fdf7f2 | 302 | if (spdk_nvme_ns_supports_extended_lba(ns)) { |
7c673cae | 303 | return 0; |
11fdf7f2 | 304 | } |
7c673cae FG |
305 | |
306 | sector_size = spdk_nvme_ns_get_sector_size(ns); | |
307 | md_size = spdk_nvme_ns_get_md_size(ns); | |
f67539c2 TL |
308 | req->contig = spdk_zmalloc(sector_size * req->lba_count, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, |
309 | SPDK_MALLOC_DMA); | |
310 | assert(req->contig); | |
7c673cae | 311 | |
f67539c2 TL |
312 | req->metadata = spdk_zmalloc(md_size * req->lba_count, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, |
313 | SPDK_MALLOC_DMA); | |
314 | assert(req->metadata); | |
7c673cae | 315 | |
f67539c2 | 316 | req->lba = 0; |
7c673cae FG |
317 | req->use_extended_lba = false; |
318 | ||
319 | /* last 8 bytes if the metadata size bigger than 8 */ | |
320 | pi = (struct spdk_nvme_protection_info *)(req->metadata + md_size - 8); | |
321 | /* big-endian for reference tag */ | |
11fdf7f2 | 322 | to_be32(&pi->ref_tag, (uint32_t)req->lba); |
7c673cae FG |
323 | |
324 | pi = (struct spdk_nvme_protection_info *)(req->metadata + md_size * 2 - 8); | |
325 | /* is incremented for each subsequent logical block */ | |
11fdf7f2 | 326 | to_be32(&pi->ref_tag, (uint32_t)(req->lba + 1)); |
7c673cae FG |
327 | |
328 | *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_REFTAG; | |
329 | ||
330 | return req->lba_count; | |
331 | } | |
332 | ||
333 | /* Application Tag checked with PRACT setting to 0 */ | |
334 | static uint32_t dp_without_pract_separate_meta_apptag_test(struct spdk_nvme_ns *ns, | |
335 | struct io_request *req, | |
336 | uint32_t *io_flags) | |
337 | { | |
338 | struct spdk_nvme_protection_info *pi; | |
339 | uint32_t md_size, sector_size; | |
340 | ||
341 | req->lba_count = 1; | |
342 | ||
343 | /* separate metadata payload for the test case */ | |
11fdf7f2 | 344 | if (spdk_nvme_ns_supports_extended_lba(ns)) { |
7c673cae | 345 | return 0; |
11fdf7f2 | 346 | } |
7c673cae FG |
347 | |
348 | sector_size = spdk_nvme_ns_get_sector_size(ns); | |
349 | md_size = spdk_nvme_ns_get_md_size(ns); | |
f67539c2 TL |
350 | req->contig = spdk_zmalloc(sector_size * req->lba_count, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, |
351 | SPDK_MALLOC_DMA); | |
352 | assert(req->contig); | |
7c673cae | 353 | |
f67539c2 TL |
354 | req->metadata = spdk_zmalloc(md_size * req->lba_count, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, |
355 | SPDK_MALLOC_DMA); | |
356 | assert(req->metadata); | |
7c673cae | 357 | |
f67539c2 | 358 | req->lba = 0; |
7c673cae FG |
359 | req->use_extended_lba = false; |
360 | req->apptag_mask = 0xFFFF; | |
361 | req->apptag = req->lba_count; | |
362 | ||
363 | /* last 8 bytes if the metadata size bigger than 8 */ | |
364 | pi = (struct spdk_nvme_protection_info *)(req->metadata + md_size - 8); | |
11fdf7f2 | 365 | to_be16(&pi->app_tag, req->lba_count); |
7c673cae FG |
366 | |
367 | *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_APPTAG; | |
368 | ||
369 | return req->lba_count; | |
370 | } | |
371 | ||
372 | /* | |
373 | * LBA + Metadata without data protection bits setting, | |
374 | * separate metadata payload for the test case. | |
375 | */ | |
376 | static uint32_t dp_without_flags_separate_meta_test(struct spdk_nvme_ns *ns, struct io_request *req, | |
377 | uint32_t *io_flags) | |
378 | { | |
379 | uint32_t md_size, sector_size; | |
380 | ||
381 | req->lba_count = 16; | |
382 | ||
383 | /* separate metadata payload for the test case */ | |
11fdf7f2 | 384 | if (spdk_nvme_ns_supports_extended_lba(ns)) { |
7c673cae | 385 | return 0; |
11fdf7f2 | 386 | } |
7c673cae FG |
387 | |
388 | sector_size = spdk_nvme_ns_get_sector_size(ns); | |
389 | md_size = spdk_nvme_ns_get_md_size(ns); | |
f67539c2 TL |
390 | req->contig = spdk_zmalloc(sector_size * req->lba_count, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, |
391 | SPDK_MALLOC_DMA); | |
392 | assert(req->contig); | |
7c673cae | 393 | |
f67539c2 TL |
394 | req->metadata = spdk_zmalloc(md_size * req->lba_count, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, |
395 | SPDK_MALLOC_DMA); | |
396 | assert(req->metadata); | |
7c673cae | 397 | |
f67539c2 | 398 | req->lba = 0; |
7c673cae FG |
399 | req->use_extended_lba = false; |
400 | *io_flags = 0; | |
401 | ||
402 | return req->lba_count; | |
403 | } | |
404 | ||
405 | typedef uint32_t (*nvme_build_io_req_fn_t)(struct spdk_nvme_ns *ns, struct io_request *req, | |
406 | uint32_t *lba_count); | |
407 | ||
408 | static void | |
409 | free_req(struct io_request *req) | |
410 | { | |
411 | if (req == NULL) { | |
412 | return; | |
413 | } | |
414 | ||
11fdf7f2 | 415 | if (req->contig) { |
f67539c2 | 416 | spdk_free(req->contig); |
11fdf7f2 | 417 | } |
7c673cae | 418 | |
11fdf7f2 | 419 | if (req->metadata) { |
f67539c2 | 420 | spdk_free(req->metadata); |
11fdf7f2 | 421 | } |
7c673cae | 422 | |
f67539c2 | 423 | spdk_free(req); |
7c673cae FG |
424 | } |
425 | ||
426 | static int | |
427 | ns_data_buffer_compare(struct spdk_nvme_ns *ns, struct io_request *req, uint8_t data_pattern) | |
428 | { | |
429 | uint32_t md_size, sector_size; | |
430 | uint32_t i, j, offset = 0; | |
431 | uint8_t *buf; | |
432 | ||
433 | sector_size = spdk_nvme_ns_get_sector_size(ns); | |
434 | md_size = spdk_nvme_ns_get_md_size(ns); | |
435 | ||
436 | for (i = 0; i < req->lba_count; i++) { | |
11fdf7f2 | 437 | if (req->use_extended_lba) { |
7c673cae | 438 | offset = (sector_size + md_size) * i; |
11fdf7f2 | 439 | } else { |
7c673cae | 440 | offset = sector_size * i; |
11fdf7f2 | 441 | } |
7c673cae FG |
442 | |
443 | buf = (uint8_t *)req->contig + offset; | |
444 | for (j = 0; j < sector_size; j++) { | |
445 | if (buf[j] != data_pattern) { | |
446 | return -1; | |
447 | } | |
448 | } | |
449 | } | |
450 | ||
451 | return 0; | |
452 | } | |
453 | ||
454 | static int | |
455 | write_read_e2e_dp_tests(struct dev *dev, nvme_build_io_req_fn_t build_io_fn, const char *test_name) | |
456 | { | |
457 | int rc = 0; | |
458 | uint32_t lba_count; | |
459 | uint32_t io_flags = 0; | |
460 | ||
461 | struct io_request *req; | |
462 | struct spdk_nvme_ns *ns; | |
463 | struct spdk_nvme_qpair *qpair; | |
464 | const struct spdk_nvme_ns_data *nsdata; | |
465 | ||
466 | ns = spdk_nvme_ctrlr_get_ns(dev->ctrlr, 1); | |
467 | if (!ns) { | |
f67539c2 | 468 | printf("Null namespace\n"); |
7c673cae FG |
469 | return 0; |
470 | } | |
471 | ||
11fdf7f2 | 472 | if (!(spdk_nvme_ns_get_flags(ns) & SPDK_NVME_NS_DPS_PI_SUPPORTED)) { |
7c673cae | 473 | return 0; |
11fdf7f2 | 474 | } |
7c673cae FG |
475 | |
476 | nsdata = spdk_nvme_ns_get_data(ns); | |
477 | if (!nsdata || !spdk_nvme_ns_get_sector_size(ns)) { | |
478 | fprintf(stderr, "Empty nsdata or wrong sector size\n"); | |
f67539c2 | 479 | return -EINVAL; |
7c673cae FG |
480 | } |
481 | ||
f67539c2 TL |
482 | req = spdk_zmalloc(sizeof(*req), 0, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); |
483 | assert(req); | |
7c673cae FG |
484 | |
485 | /* IO parameters setting */ | |
486 | lba_count = build_io_fn(ns, req, &io_flags); | |
7c673cae | 487 | if (!lba_count) { |
f67539c2 | 488 | printf("%s: %s bypass the test case\n", dev->name, test_name); |
7c673cae FG |
489 | free_req(req); |
490 | return 0; | |
491 | } | |
492 | ||
11fdf7f2 | 493 | qpair = spdk_nvme_ctrlr_alloc_io_qpair(dev->ctrlr, NULL, 0); |
7c673cae FG |
494 | if (!qpair) { |
495 | free_req(req); | |
496 | return -1; | |
497 | } | |
498 | ||
499 | ns_data_buffer_reset(ns, req, DATA_PATTERN); | |
500 | if (req->use_extended_lba && req->use_sgl) { | |
501 | rc = spdk_nvme_ns_cmd_writev(ns, qpair, req->lba, lba_count, io_complete, req, io_flags, | |
502 | nvme_req_reset_sgl, nvme_req_next_sge); | |
503 | } else if (req->use_extended_lba) { | |
504 | rc = spdk_nvme_ns_cmd_write(ns, qpair, req->contig, req->lba, lba_count, | |
505 | io_complete, req, io_flags); | |
506 | } else { | |
507 | rc = spdk_nvme_ns_cmd_write_with_md(ns, qpair, req->contig, req->metadata, req->lba, lba_count, | |
508 | io_complete, req, io_flags, req->apptag_mask, req->apptag); | |
509 | } | |
510 | ||
511 | if (rc != 0) { | |
512 | fprintf(stderr, "%s: %s write submit failed\n", dev->name, test_name); | |
513 | spdk_nvme_ctrlr_free_io_qpair(qpair); | |
514 | free_req(req); | |
515 | return -1; | |
516 | } | |
517 | ||
518 | io_complete_flag = 0; | |
519 | ||
11fdf7f2 | 520 | while (!io_complete_flag) { |
7c673cae | 521 | spdk_nvme_qpair_process_completions(qpair, 1); |
11fdf7f2 | 522 | } |
7c673cae FG |
523 | |
524 | if (io_complete_flag != 1) { | |
525 | fprintf(stderr, "%s: %s write exec failed\n", dev->name, test_name); | |
526 | spdk_nvme_ctrlr_free_io_qpair(qpair); | |
527 | free_req(req); | |
528 | return -1; | |
529 | } | |
530 | ||
531 | /* reset completion flag */ | |
532 | io_complete_flag = 0; | |
533 | ||
534 | ns_data_buffer_reset(ns, req, 0); | |
535 | if (req->use_extended_lba && req->use_sgl) { | |
536 | rc = spdk_nvme_ns_cmd_readv(ns, qpair, req->lba, lba_count, io_complete, req, io_flags, | |
537 | nvme_req_reset_sgl, nvme_req_next_sge); | |
538 | ||
539 | } else if (req->use_extended_lba) { | |
540 | rc = spdk_nvme_ns_cmd_read(ns, qpair, req->contig, req->lba, lba_count, | |
541 | io_complete, req, io_flags); | |
542 | } else { | |
543 | rc = spdk_nvme_ns_cmd_read_with_md(ns, qpair, req->contig, req->metadata, req->lba, lba_count, | |
544 | io_complete, req, io_flags, req->apptag_mask, req->apptag); | |
545 | } | |
546 | ||
547 | if (rc != 0) { | |
548 | fprintf(stderr, "%s: %s read failed\n", dev->name, test_name); | |
549 | spdk_nvme_ctrlr_free_io_qpair(qpair); | |
550 | free_req(req); | |
551 | return -1; | |
552 | } | |
553 | ||
11fdf7f2 | 554 | while (!io_complete_flag) { |
7c673cae | 555 | spdk_nvme_qpair_process_completions(qpair, 1); |
11fdf7f2 | 556 | } |
7c673cae FG |
557 | |
558 | if (io_complete_flag != 1) { | |
559 | fprintf(stderr, "%s: %s read failed\n", dev->name, test_name); | |
560 | spdk_nvme_ctrlr_free_io_qpair(qpair); | |
561 | free_req(req); | |
562 | return -1; | |
563 | } | |
564 | ||
565 | rc = ns_data_buffer_compare(ns, req, DATA_PATTERN); | |
566 | if (rc < 0) { | |
567 | fprintf(stderr, "%s: %s write/read success, but memcmp Failed\n", dev->name, test_name); | |
568 | spdk_nvme_ctrlr_free_io_qpair(qpair); | |
569 | free_req(req); | |
570 | return -1; | |
571 | } | |
572 | ||
f67539c2 | 573 | printf("%s: %s test passed\n", dev->name, test_name); |
7c673cae FG |
574 | spdk_nvme_ctrlr_free_io_qpair(qpair); |
575 | free_req(req); | |
f67539c2 | 576 | return 0; |
7c673cae FG |
577 | } |
578 | ||
579 | static bool | |
580 | probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, | |
581 | struct spdk_nvme_ctrlr_opts *opts) | |
582 | { | |
583 | printf("Attaching to %s\n", trid->traddr); | |
584 | ||
585 | return true; | |
586 | } | |
587 | ||
588 | static void | |
589 | attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, | |
590 | struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) | |
591 | { | |
592 | struct dev *dev; | |
593 | ||
594 | /* add to dev list */ | |
595 | dev = &devs[num_devs++]; | |
596 | ||
597 | dev->ctrlr = ctrlr; | |
598 | ||
599 | snprintf(dev->name, sizeof(dev->name), "%s", | |
600 | trid->traddr); | |
601 | ||
602 | printf("Attached to %s\n", dev->name); | |
603 | } | |
604 | ||
605 | int main(int argc, char **argv) | |
606 | { | |
607 | struct dev *iter; | |
608 | int rc, i; | |
609 | struct spdk_env_opts opts; | |
610 | ||
611 | spdk_env_opts_init(&opts); | |
612 | opts.name = "nvme_dp"; | |
613 | opts.core_mask = "0x1"; | |
11fdf7f2 TL |
614 | opts.shm_id = 0; |
615 | if (spdk_env_init(&opts) < 0) { | |
616 | fprintf(stderr, "Unable to initialize SPDK env\n"); | |
617 | return 1; | |
618 | } | |
7c673cae FG |
619 | |
620 | printf("NVMe Write/Read with End-to-End data protection test\n"); | |
621 | ||
622 | if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { | |
623 | fprintf(stderr, "nvme_probe() failed\n"); | |
624 | exit(1); | |
625 | } | |
626 | ||
627 | rc = 0; | |
628 | foreach_dev(iter) { | |
629 | #define TEST(x) write_read_e2e_dp_tests(iter, x, #x) | |
630 | if (TEST(dp_with_pract_test) | |
631 | || TEST(dp_guard_check_extended_lba_test) | |
632 | || TEST(dp_without_pract_extended_lba_test) | |
633 | || TEST(dp_without_flags_extended_lba_test) | |
634 | || TEST(dp_without_pract_separate_meta_test) | |
635 | || TEST(dp_without_pract_separate_meta_apptag_test) | |
636 | || TEST(dp_without_flags_separate_meta_test)) { | |
637 | #undef TEST | |
638 | rc = 1; | |
639 | printf("%s: failed End-to-End data protection tests\n", iter->name); | |
640 | } | |
641 | } | |
642 | ||
643 | printf("Cleaning up...\n"); | |
644 | ||
645 | for (i = 0; i < num_devs; i++) { | |
646 | struct dev *dev = &devs[i]; | |
647 | ||
648 | spdk_nvme_detach(dev->ctrlr); | |
649 | } | |
650 | ||
651 | return rc; | |
652 | } |