]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/test/nvme/e2edp/nvme_dp.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / spdk / test / nvme / e2edp / nvme_dp.c
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
38 #include "spdk/stdinc.h"
39
40 #include "spdk/nvme.h"
41 #include "spdk/env.h"
42 #include "spdk/crc16.h"
43 #include "spdk/endian.h"
44
45 #define MAX_DEVS 64
46
47 #define DATA_PATTERN 0x5A
48
49 struct dev {
50 struct spdk_nvme_ctrlr *ctrlr;
51 char name[SPDK_NVMF_TRADDR_MAX_LEN + 1];
52 };
53
54 static struct dev devs[MAX_DEVS];
55 static int num_devs = 0;
56
57 #define foreach_dev(iter) \
58 for (iter = devs; iter - devs < num_devs; iter++)
59
60 static int io_complete_flag = 0;
61
62 struct io_request {
63 void *contig;
64 void *metadata;
65 bool use_extended_lba;
66 bool use_sgl;
67 uint32_t sgl_offset;
68 uint32_t buf_size;
69 uint64_t lba;
70 uint32_t lba_count;
71 uint16_t apptag_mask;
72 uint16_t apptag;
73 };
74
75 static void
76 io_complete(void *ctx, const struct spdk_nvme_cpl *cpl)
77 {
78 if (spdk_nvme_cpl_is_error(cpl)) {
79 io_complete_flag = 2;
80 } else {
81 io_complete_flag = 1;
82 }
83 }
84
85 static void
86 ns_data_buffer_reset(struct spdk_nvme_ns *ns, struct io_request *req, uint8_t data_pattern)
87 {
88 uint32_t md_size, sector_size;
89 uint32_t i, offset = 0;
90 uint8_t *buf;
91
92 sector_size = spdk_nvme_ns_get_sector_size(ns);
93 md_size = spdk_nvme_ns_get_md_size(ns);
94
95 for (i = 0; i < req->lba_count; i++) {
96 if (req->use_extended_lba) {
97 offset = (sector_size + md_size) * i;
98 } else {
99 offset = sector_size * i;
100 }
101
102 buf = (uint8_t *)req->contig + offset;
103 memset(buf, data_pattern, sector_size);
104 }
105 }
106
107 static void nvme_req_reset_sgl(void *cb_arg, uint32_t sgl_offset)
108 {
109 struct io_request *req = (struct io_request *)cb_arg;
110
111 req->sgl_offset = sgl_offset;
112 return;
113 }
114
115 static int nvme_req_next_sge(void *cb_arg, void **address, uint32_t *length)
116 {
117 struct io_request *req = (struct io_request *)cb_arg;
118 void *payload;
119
120 payload = req->contig + req->sgl_offset;
121 *address = payload;
122
123 *length = req->buf_size - req->sgl_offset;
124
125 return 0;
126 }
127
128 /* CRC-16 Guard checked for extended lba format */
129 static uint32_t dp_guard_check_extended_lba_test(struct spdk_nvme_ns *ns, struct io_request *req,
130 uint32_t *io_flags)
131 {
132 struct spdk_nvme_protection_info *pi;
133 uint32_t md_size, sector_size;
134
135 req->lba_count = 2;
136
137 /* extended LBA only for the test case */
138 if (!(spdk_nvme_ns_supports_extended_lba(ns))) {
139 return 0;
140 }
141
142 sector_size = spdk_nvme_ns_get_sector_size(ns);
143 md_size = spdk_nvme_ns_get_md_size(ns);
144 req->contig = spdk_dma_zmalloc((sector_size + md_size) * req->lba_count, 0x1000, NULL);
145 if (!req->contig) {
146 return 0;
147 }
148
149 req->lba = 0x200000;
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 */
157 to_be16(&pi->guard, spdk_crc16_t10dif(req->contig, sector_size));
158
159 pi = (struct spdk_nvme_protection_info *)(req->contig + (sector_size + md_size) * 2 - 8);
160 to_be16(&pi->guard, spdk_crc16_t10dif(req->contig + sector_size + md_size, sector_size));
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 {
175 uint32_t sector_size;
176
177 req->lba_count = 8;
178
179 sector_size = spdk_nvme_ns_get_sector_size(ns);
180 /* No additional metadata buffer provided */
181 req->contig = spdk_dma_zmalloc(sector_size * req->lba_count, 0x1000, NULL);
182 if (!req->contig) {
183 return 0;
184 }
185
186 switch (spdk_nvme_ns_get_pi_type(ns)) {
187 case SPDK_NVME_FMT_NVM_PROTECTION_TYPE3:
188 *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_GUARD | SPDK_NVME_IO_FLAGS_PRACT;
189 break;
190 case SPDK_NVME_FMT_NVM_PROTECTION_TYPE1:
191 case SPDK_NVME_FMT_NVM_PROTECTION_TYPE2:
192 *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_GUARD | SPDK_NVME_IO_FLAGS_PRCHK_REFTAG |
193 SPDK_NVME_IO_FLAGS_PRACT;
194 break;
195 default:
196 *io_flags = 0;
197 break;
198 }
199
200 req->lba = 0x100000;
201 req->use_extended_lba = false;
202 req->metadata = NULL;
203
204 return req->lba_count;
205 }
206
207 /* Block Reference Tag checked for TYPE1 and TYPE2 with PRACT setting to 0 */
208 static uint32_t dp_without_pract_extended_lba_test(struct spdk_nvme_ns *ns, struct io_request *req,
209 uint32_t *io_flags)
210 {
211 struct spdk_nvme_protection_info *pi;
212 uint32_t md_size, sector_size;
213
214 req->lba_count = 2;
215
216 switch (spdk_nvme_ns_get_pi_type(ns)) {
217 case SPDK_NVME_FMT_NVM_PROTECTION_TYPE3:
218 return 0;
219 default:
220 break;
221 }
222
223 /* extended LBA only for the test case */
224 if (!(spdk_nvme_ns_supports_extended_lba(ns))) {
225 return 0;
226 }
227
228 sector_size = spdk_nvme_ns_get_sector_size(ns);
229 md_size = spdk_nvme_ns_get_md_size(ns);
230 req->contig = spdk_dma_zmalloc((sector_size + md_size) * req->lba_count, 0x1000, NULL);
231 if (!req->contig) {
232 return 0;
233 }
234
235 req->lba = 0x200000;
236 req->use_extended_lba = true;
237 req->metadata = NULL;
238 pi = (struct spdk_nvme_protection_info *)(req->contig + sector_size + md_size - 8);
239 /* big-endian for reference tag */
240 to_be32(&pi->ref_tag, (uint32_t)req->lba);
241
242 pi = (struct spdk_nvme_protection_info *)(req->contig + (sector_size + md_size) * 2 - 8);
243 /* is incremented for each subsequent logical block */
244 to_be32(&pi->ref_tag, (uint32_t)(req->lba + 1));
245
246 *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
247
248 return req->lba_count;
249 }
250
251 /* LBA + Metadata without data protection bits setting */
252 static uint32_t dp_without_flags_extended_lba_test(struct spdk_nvme_ns *ns, struct io_request *req,
253 uint32_t *io_flags)
254 {
255 uint32_t md_size, sector_size;
256
257 req->lba_count = 16;
258
259 /* extended LBA only for the test case */
260 if (!(spdk_nvme_ns_supports_extended_lba(ns))) {
261 return 0;
262 }
263
264 sector_size = spdk_nvme_ns_get_sector_size(ns);
265 md_size = spdk_nvme_ns_get_md_size(ns);
266 req->contig = spdk_dma_zmalloc((sector_size + md_size) * req->lba_count, 0x1000, NULL);
267 if (!req->contig) {
268 return 0;
269 }
270
271 req->lba = 0x400000;
272 req->use_extended_lba = true;
273 req->metadata = NULL;
274 *io_flags = 0;
275
276 return req->lba_count;
277 }
278
279 /* Block Reference Tag checked for TYPE1 and TYPE2 with PRACT setting to 0 */
280 static uint32_t dp_without_pract_separate_meta_test(struct spdk_nvme_ns *ns, struct io_request *req,
281 uint32_t *io_flags)
282 {
283 struct spdk_nvme_protection_info *pi;
284 uint32_t md_size, sector_size;
285
286 req->lba_count = 2;
287
288 switch (spdk_nvme_ns_get_pi_type(ns)) {
289 case SPDK_NVME_FMT_NVM_PROTECTION_TYPE3:
290 return 0;
291 default:
292 break;
293 }
294
295 /* separate metadata payload for the test case */
296 if (spdk_nvme_ns_supports_extended_lba(ns)) {
297 return 0;
298 }
299
300 sector_size = spdk_nvme_ns_get_sector_size(ns);
301 md_size = spdk_nvme_ns_get_md_size(ns);
302 req->contig = spdk_dma_zmalloc(sector_size * req->lba_count, 0x1000, NULL);
303 if (!req->contig) {
304 return 0;
305 }
306
307 req->metadata = spdk_dma_zmalloc(md_size * req->lba_count, 0x1000, NULL);
308 if (!req->metadata) {
309 spdk_dma_free(req->contig);
310 return 0;
311 }
312
313 req->lba = 0x400000;
314 req->use_extended_lba = false;
315
316 /* last 8 bytes if the metadata size bigger than 8 */
317 pi = (struct spdk_nvme_protection_info *)(req->metadata + md_size - 8);
318 /* big-endian for reference tag */
319 to_be32(&pi->ref_tag, (uint32_t)req->lba);
320
321 pi = (struct spdk_nvme_protection_info *)(req->metadata + md_size * 2 - 8);
322 /* is incremented for each subsequent logical block */
323 to_be32(&pi->ref_tag, (uint32_t)(req->lba + 1));
324
325 *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
326
327 return req->lba_count;
328 }
329
330 /* Application Tag checked with PRACT setting to 0 */
331 static uint32_t dp_without_pract_separate_meta_apptag_test(struct spdk_nvme_ns *ns,
332 struct io_request *req,
333 uint32_t *io_flags)
334 {
335 struct spdk_nvme_protection_info *pi;
336 uint32_t md_size, sector_size;
337
338 req->lba_count = 1;
339
340 /* separate metadata payload for the test case */
341 if (spdk_nvme_ns_supports_extended_lba(ns)) {
342 return 0;
343 }
344
345 sector_size = spdk_nvme_ns_get_sector_size(ns);
346 md_size = spdk_nvme_ns_get_md_size(ns);
347 req->contig = spdk_dma_zmalloc(sector_size * req->lba_count, 0x1000, NULL);
348 if (!req->contig) {
349 return 0;
350 }
351
352 req->metadata = spdk_dma_zmalloc(md_size * req->lba_count, 0x1000, NULL);
353 if (!req->metadata) {
354 spdk_dma_free(req->contig);
355 return 0;
356 }
357
358 req->lba = 0x500000;
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);
365 to_be16(&pi->app_tag, req->lba_count);
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 */
384 if (spdk_nvme_ns_supports_extended_lba(ns)) {
385 return 0;
386 }
387
388 sector_size = spdk_nvme_ns_get_sector_size(ns);
389 md_size = spdk_nvme_ns_get_md_size(ns);
390 req->contig = spdk_dma_zmalloc(sector_size * req->lba_count, 0x1000, NULL);
391 if (!req->contig) {
392 return 0;
393 }
394
395 req->metadata = spdk_dma_zmalloc(md_size * req->lba_count, 0x1000, NULL);
396 if (!req->metadata) {
397 spdk_dma_free(req->contig);
398 return 0;
399 }
400
401 req->lba = 0x600000;
402 req->use_extended_lba = false;
403 *io_flags = 0;
404
405 return req->lba_count;
406 }
407
408 typedef uint32_t (*nvme_build_io_req_fn_t)(struct spdk_nvme_ns *ns, struct io_request *req,
409 uint32_t *lba_count);
410
411 static void
412 free_req(struct io_request *req)
413 {
414 if (req == NULL) {
415 return;
416 }
417
418 if (req->contig) {
419 spdk_dma_free(req->contig);
420 }
421
422 if (req->metadata) {
423 spdk_dma_free(req->metadata);
424 }
425
426 spdk_dma_free(req);
427 }
428
429 static int
430 ns_data_buffer_compare(struct spdk_nvme_ns *ns, struct io_request *req, uint8_t data_pattern)
431 {
432 uint32_t md_size, sector_size;
433 uint32_t i, j, offset = 0;
434 uint8_t *buf;
435
436 sector_size = spdk_nvme_ns_get_sector_size(ns);
437 md_size = spdk_nvme_ns_get_md_size(ns);
438
439 for (i = 0; i < req->lba_count; i++) {
440 if (req->use_extended_lba) {
441 offset = (sector_size + md_size) * i;
442 } else {
443 offset = sector_size * i;
444 }
445
446 buf = (uint8_t *)req->contig + offset;
447 for (j = 0; j < sector_size; j++) {
448 if (buf[j] != data_pattern) {
449 return -1;
450 }
451 }
452 }
453
454 return 0;
455 }
456
457 static int
458 write_read_e2e_dp_tests(struct dev *dev, nvme_build_io_req_fn_t build_io_fn, const char *test_name)
459 {
460 int rc = 0;
461 uint32_t lba_count;
462 uint32_t io_flags = 0;
463
464 struct io_request *req;
465 struct spdk_nvme_ns *ns;
466 struct spdk_nvme_qpair *qpair;
467 const struct spdk_nvme_ns_data *nsdata;
468
469 ns = spdk_nvme_ctrlr_get_ns(dev->ctrlr, 1);
470 if (!ns) {
471 fprintf(stderr, "Null namespace\n");
472 return 0;
473 }
474
475 if (!(spdk_nvme_ns_get_flags(ns) & SPDK_NVME_NS_DPS_PI_SUPPORTED)) {
476 return 0;
477 }
478
479 nsdata = spdk_nvme_ns_get_data(ns);
480 if (!nsdata || !spdk_nvme_ns_get_sector_size(ns)) {
481 fprintf(stderr, "Empty nsdata or wrong sector size\n");
482 return 0;
483 }
484
485 req = spdk_dma_zmalloc(sizeof(*req), 0, NULL);
486 if (!req) {
487 fprintf(stderr, "Allocate request failed\n");
488 return 0;
489 }
490
491 /* IO parameters setting */
492 lba_count = build_io_fn(ns, req, &io_flags);
493
494 if (!lba_count) {
495 fprintf(stderr, "%s: %s bypass the test case\n", dev->name, test_name);
496 free_req(req);
497 return 0;
498 }
499
500 qpair = spdk_nvme_ctrlr_alloc_io_qpair(dev->ctrlr, NULL, 0);
501 if (!qpair) {
502 free_req(req);
503 return -1;
504 }
505
506 ns_data_buffer_reset(ns, req, DATA_PATTERN);
507 if (req->use_extended_lba && req->use_sgl) {
508 rc = spdk_nvme_ns_cmd_writev(ns, qpair, req->lba, lba_count, io_complete, req, io_flags,
509 nvme_req_reset_sgl, nvme_req_next_sge);
510 } else if (req->use_extended_lba) {
511 rc = spdk_nvme_ns_cmd_write(ns, qpair, req->contig, req->lba, lba_count,
512 io_complete, req, io_flags);
513 } else {
514 rc = spdk_nvme_ns_cmd_write_with_md(ns, qpair, req->contig, req->metadata, req->lba, lba_count,
515 io_complete, req, io_flags, req->apptag_mask, req->apptag);
516 }
517
518 if (rc != 0) {
519 fprintf(stderr, "%s: %s write submit failed\n", dev->name, test_name);
520 spdk_nvme_ctrlr_free_io_qpair(qpair);
521 free_req(req);
522 return -1;
523 }
524
525 io_complete_flag = 0;
526
527 while (!io_complete_flag) {
528 spdk_nvme_qpair_process_completions(qpair, 1);
529 }
530
531 if (io_complete_flag != 1) {
532 fprintf(stderr, "%s: %s write exec failed\n", dev->name, test_name);
533 spdk_nvme_ctrlr_free_io_qpair(qpair);
534 free_req(req);
535 return -1;
536 }
537
538 /* reset completion flag */
539 io_complete_flag = 0;
540
541 ns_data_buffer_reset(ns, req, 0);
542 if (req->use_extended_lba && req->use_sgl) {
543 rc = spdk_nvme_ns_cmd_readv(ns, qpair, req->lba, lba_count, io_complete, req, io_flags,
544 nvme_req_reset_sgl, nvme_req_next_sge);
545
546 } else if (req->use_extended_lba) {
547 rc = spdk_nvme_ns_cmd_read(ns, qpair, req->contig, req->lba, lba_count,
548 io_complete, req, io_flags);
549 } else {
550 rc = spdk_nvme_ns_cmd_read_with_md(ns, qpair, req->contig, req->metadata, req->lba, lba_count,
551 io_complete, req, io_flags, req->apptag_mask, req->apptag);
552 }
553
554 if (rc != 0) {
555 fprintf(stderr, "%s: %s read failed\n", dev->name, test_name);
556 spdk_nvme_ctrlr_free_io_qpair(qpair);
557 free_req(req);
558 return -1;
559 }
560
561 while (!io_complete_flag) {
562 spdk_nvme_qpair_process_completions(qpair, 1);
563 }
564
565 if (io_complete_flag != 1) {
566 fprintf(stderr, "%s: %s read failed\n", dev->name, test_name);
567 spdk_nvme_ctrlr_free_io_qpair(qpair);
568 free_req(req);
569 return -1;
570 }
571
572 rc = ns_data_buffer_compare(ns, req, DATA_PATTERN);
573 if (rc < 0) {
574 fprintf(stderr, "%s: %s write/read success, but memcmp Failed\n", dev->name, test_name);
575 spdk_nvme_ctrlr_free_io_qpair(qpair);
576 free_req(req);
577 return -1;
578 }
579
580 fprintf(stdout, "%s: %s test passed\n", dev->name, test_name);
581 spdk_nvme_ctrlr_free_io_qpair(qpair);
582 free_req(req);
583 return rc;
584 }
585
586 static bool
587 probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
588 struct spdk_nvme_ctrlr_opts *opts)
589 {
590 printf("Attaching to %s\n", trid->traddr);
591
592 return true;
593 }
594
595 static void
596 attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
597 struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
598 {
599 struct dev *dev;
600
601 /* add to dev list */
602 dev = &devs[num_devs++];
603
604 dev->ctrlr = ctrlr;
605
606 snprintf(dev->name, sizeof(dev->name), "%s",
607 trid->traddr);
608
609 printf("Attached to %s\n", dev->name);
610 }
611
612 int main(int argc, char **argv)
613 {
614 struct dev *iter;
615 int rc, i;
616 struct spdk_env_opts opts;
617
618 spdk_env_opts_init(&opts);
619 opts.name = "nvme_dp";
620 opts.core_mask = "0x1";
621 opts.shm_id = 0;
622 if (spdk_env_init(&opts) < 0) {
623 fprintf(stderr, "Unable to initialize SPDK env\n");
624 return 1;
625 }
626
627 printf("NVMe Write/Read with End-to-End data protection test\n");
628
629 if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
630 fprintf(stderr, "nvme_probe() failed\n");
631 exit(1);
632 }
633
634 rc = 0;
635 foreach_dev(iter) {
636 #define TEST(x) write_read_e2e_dp_tests(iter, x, #x)
637 if (TEST(dp_with_pract_test)
638 || TEST(dp_guard_check_extended_lba_test)
639 || TEST(dp_without_pract_extended_lba_test)
640 || TEST(dp_without_flags_extended_lba_test)
641 || TEST(dp_without_pract_separate_meta_test)
642 || TEST(dp_without_pract_separate_meta_apptag_test)
643 || TEST(dp_without_flags_separate_meta_test)) {
644 #undef TEST
645 rc = 1;
646 printf("%s: failed End-to-End data protection tests\n", iter->name);
647 }
648 }
649
650 printf("Cleaning up...\n");
651
652 for (i = 0; i < num_devs; i++) {
653 struct dev *dev = &devs[i];
654
655 spdk_nvme_detach(dev->ctrlr);
656 }
657
658 return rc;
659 }