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 #include "spdk/dif.h" 35 #include "spdk/crc16.h" 36 #include "spdk/crc32.h" 37 #include "spdk/endian.h" 38 #include "spdk/log.h" 39 #include "spdk/util.h" 40 41 /* Context to iterate or create a iovec array. 42 * Each sgl is either iterated or created at a time. 43 */ 44 struct _dif_sgl { 45 /* Current iovec in the iteration or creation */ 46 struct iovec *iov; 47 48 /* Remaining count of iovecs in the iteration or creation. */ 49 int iovcnt; 50 51 /* Current offset in the iovec */ 52 uint32_t iov_offset; 53 54 /* Size of the created iovec array in bytes */ 55 uint32_t total_size; 56 }; 57 58 static inline void 59 _dif_sgl_init(struct _dif_sgl *s, struct iovec *iovs, int iovcnt) 60 { 61 s->iov = iovs; 62 s->iovcnt = iovcnt; 63 s->iov_offset = 0; 64 s->total_size = 0; 65 } 66 67 static void 68 _dif_sgl_advance(struct _dif_sgl *s, uint32_t step) 69 { 70 s->iov_offset += step; 71 while (s->iovcnt != 0) { 72 if (s->iov_offset < s->iov->iov_len) { 73 break; 74 } 75 76 s->iov_offset -= s->iov->iov_len; 77 s->iov++; 78 s->iovcnt--; 79 } 80 } 81 82 static inline void 83 _dif_sgl_get_buf(struct _dif_sgl *s, void **_buf, uint32_t *_buf_len) 84 { 85 if (_buf != NULL) { 86 *_buf = s->iov->iov_base + s->iov_offset; 87 } 88 if (_buf_len != NULL) { 89 *_buf_len = s->iov->iov_len - s->iov_offset; 90 } 91 } 92 93 static inline bool 94 _dif_sgl_append(struct _dif_sgl *s, uint8_t *data, uint32_t data_len) 95 { 96 assert(s->iovcnt > 0); 97 s->iov->iov_base = data; 98 s->iov->iov_len = data_len; 99 s->total_size += data_len; 100 s->iov++; 101 s->iovcnt--; 102 103 if (s->iovcnt > 0) { 104 return true; 105 } else { 106 return false; 107 } 108 } 109 110 static inline bool 111 _dif_sgl_append_split(struct _dif_sgl *dst, struct _dif_sgl *src, uint32_t data_len) 112 { 113 uint8_t *buf; 114 uint32_t buf_len; 115 116 while (data_len != 0) { 117 _dif_sgl_get_buf(src, (void *)&buf, &buf_len); 118 buf_len = spdk_min(buf_len, data_len); 119 120 if (!_dif_sgl_append(dst, buf, buf_len)) { 121 return false; 122 } 123 124 _dif_sgl_advance(src, buf_len); 125 data_len -= buf_len; 126 } 127 128 return true; 129 } 130 131 /* This function must be used before starting iteration. */ 132 static bool 133 _dif_sgl_is_bytes_multiple(struct _dif_sgl *s, uint32_t bytes) 134 { 135 int i; 136 137 for (i = 0; i < s->iovcnt; i++) { 138 if (s->iov[i].iov_len % bytes) { 139 return false; 140 } 141 } 142 143 return true; 144 } 145 146 /* This function must be used before starting iteration. */ 147 static bool 148 _dif_sgl_is_valid(struct _dif_sgl *s, uint32_t bytes) 149 { 150 uint64_t total = 0; 151 int i; 152 153 for (i = 0; i < s->iovcnt; i++) { 154 total += s->iov[i].iov_len; 155 } 156 157 return total >= bytes; 158 } 159 160 static void 161 _dif_sgl_copy(struct _dif_sgl *to, struct _dif_sgl *from) 162 { 163 memcpy(to, from, sizeof(struct _dif_sgl)); 164 } 165 166 static bool 167 _dif_type_is_valid(enum spdk_dif_type dif_type, uint32_t dif_flags) 168 { 169 switch (dif_type) { 170 case SPDK_DIF_TYPE1: 171 case SPDK_DIF_TYPE2: 172 case SPDK_DIF_DISABLE: 173 break; 174 case SPDK_DIF_TYPE3: 175 if (dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) { 176 SPDK_ERRLOG("Reference Tag should not be checked for Type 3\n"); 177 return false; 178 } 179 break; 180 default: 181 SPDK_ERRLOG("Unknown DIF Type: %d\n", dif_type); 182 return false; 183 } 184 185 return true; 186 } 187 188 static bool 189 _dif_is_disabled(enum spdk_dif_type dif_type) 190 { 191 if (dif_type == SPDK_DIF_DISABLE) { 192 return true; 193 } else { 194 return false; 195 } 196 } 197 198 199 static uint32_t 200 _get_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc, bool md_interleave) 201 { 202 if (!dif_loc) { 203 /* For metadata formats with more than 8 bytes, if the DIF is 204 * contained in the last 8 bytes of metadata, then the CRC 205 * covers all metadata up to but excluding these last 8 bytes. 206 */ 207 if (md_interleave) { 208 return block_size - sizeof(struct spdk_dif); 209 } else { 210 return md_size - sizeof(struct spdk_dif); 211 } 212 } else { 213 /* For metadata formats with more than 8 bytes, if the DIF is 214 * contained in the first 8 bytes of metadata, then the CRC 215 * does not cover any metadata. 216 */ 217 if (md_interleave) { 218 return block_size - md_size; 219 } else { 220 return 0; 221 } 222 } 223 } 224 225 int 226 spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size, 227 bool md_interleave, bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags, 228 uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag, 229 uint32_t data_offset, uint16_t guard_seed) 230 { 231 uint32_t data_block_size; 232 233 if (md_size < sizeof(struct spdk_dif)) { 234 SPDK_ERRLOG("Metadata size is smaller than DIF size.\n"); 235 return -EINVAL; 236 } 237 238 if (md_interleave) { 239 if (block_size < md_size) { 240 SPDK_ERRLOG("Block size is smaller than DIF size.\n"); 241 return -EINVAL; 242 } 243 data_block_size = block_size - md_size; 244 } else { 245 if (block_size == 0 || (block_size % 512) != 0) { 246 SPDK_ERRLOG("Zero block size is not allowed\n"); 247 return -EINVAL; 248 } 249 data_block_size = block_size; 250 } 251 252 if (!_dif_type_is_valid(dif_type, dif_flags)) { 253 SPDK_ERRLOG("DIF type is invalid.\n"); 254 return -EINVAL; 255 } 256 257 ctx->block_size = block_size; 258 ctx->md_size = md_size; 259 ctx->md_interleave = md_interleave; 260 ctx->guard_interval = _get_guard_interval(block_size, md_size, dif_loc, md_interleave); 261 ctx->dif_type = dif_type; 262 ctx->dif_flags = dif_flags; 263 ctx->init_ref_tag = init_ref_tag; 264 ctx->apptag_mask = apptag_mask; 265 ctx->app_tag = app_tag; 266 ctx->data_offset = data_offset; 267 ctx->ref_tag_offset = data_offset / data_block_size; 268 ctx->last_guard = guard_seed; 269 ctx->guard_seed = guard_seed; 270 ctx->remapped_init_ref_tag = 0; 271 272 return 0; 273 } 274 275 void 276 spdk_dif_ctx_set_data_offset(struct spdk_dif_ctx *ctx, uint32_t data_offset) 277 { 278 uint32_t data_block_size; 279 280 if (ctx->md_interleave) { 281 data_block_size = ctx->block_size - ctx->md_size; 282 } else { 283 data_block_size = ctx->block_size; 284 } 285 286 ctx->data_offset = data_offset; 287 ctx->ref_tag_offset = data_offset / data_block_size; 288 } 289 290 void 291 spdk_dif_ctx_set_remapped_init_ref_tag(struct spdk_dif_ctx *ctx, 292 uint32_t remapped_init_ref_tag) 293 { 294 ctx->remapped_init_ref_tag = remapped_init_ref_tag; 295 } 296 297 static void 298 _dif_generate(void *_dif, uint16_t guard, uint32_t offset_blocks, 299 const struct spdk_dif_ctx *ctx) 300 { 301 struct spdk_dif *dif = _dif; 302 uint32_t ref_tag; 303 304 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 305 to_be16(&dif->guard, guard); 306 } 307 308 if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) { 309 to_be16(&dif->app_tag, ctx->app_tag); 310 } 311 312 if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) { 313 /* For type 1 and 2, the reference tag is incremented for each 314 * subsequent logical block. For type 3, the reference tag 315 * remains the same as the initial reference tag. 316 */ 317 if (ctx->dif_type != SPDK_DIF_TYPE3) { 318 ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks; 319 } else { 320 ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset; 321 } 322 323 to_be32(&dif->ref_tag, ref_tag); 324 } 325 } 326 327 static void 328 dif_generate(struct _dif_sgl *sgl, uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 329 { 330 uint32_t offset_blocks = 0; 331 void *buf; 332 uint16_t guard = 0; 333 334 while (offset_blocks < num_blocks) { 335 _dif_sgl_get_buf(sgl, &buf, NULL); 336 337 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 338 guard = spdk_crc16_t10dif(ctx->guard_seed, buf, ctx->guard_interval); 339 } 340 341 _dif_generate(buf + ctx->guard_interval, guard, offset_blocks, ctx); 342 343 _dif_sgl_advance(sgl, ctx->block_size); 344 offset_blocks++; 345 } 346 } 347 348 static uint16_t 349 _dif_generate_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len, 350 uint16_t guard, uint32_t offset_blocks, const struct spdk_dif_ctx *ctx) 351 { 352 uint32_t offset_in_dif, buf_len; 353 void *buf; 354 struct spdk_dif dif = {}; 355 356 assert(offset_in_block < ctx->guard_interval); 357 assert(offset_in_block + data_len < ctx->guard_interval || 358 offset_in_block + data_len == ctx->block_size); 359 360 /* Compute CRC over split logical block data. */ 361 while (data_len != 0 && offset_in_block < ctx->guard_interval) { 362 _dif_sgl_get_buf(sgl, &buf, &buf_len); 363 buf_len = spdk_min(buf_len, data_len); 364 buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block); 365 366 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 367 guard = spdk_crc16_t10dif(guard, buf, buf_len); 368 } 369 370 _dif_sgl_advance(sgl, buf_len); 371 offset_in_block += buf_len; 372 data_len -= buf_len; 373 } 374 375 if (offset_in_block < ctx->guard_interval) { 376 return guard; 377 } 378 379 /* If a whole logical block data is parsed, generate DIF 380 * and save it to the temporary DIF area. 381 */ 382 _dif_generate(&dif, guard, offset_blocks, ctx); 383 384 /* Copy generated DIF field to the split DIF field, and then 385 * skip metadata field after DIF field (if any). 386 */ 387 while (offset_in_block < ctx->block_size) { 388 _dif_sgl_get_buf(sgl, &buf, &buf_len); 389 390 if (offset_in_block < ctx->guard_interval + sizeof(struct spdk_dif)) { 391 offset_in_dif = offset_in_block - ctx->guard_interval; 392 buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif); 393 394 memcpy(buf, ((uint8_t *)&dif) + offset_in_dif, buf_len); 395 } else { 396 buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block); 397 } 398 399 _dif_sgl_advance(sgl, buf_len); 400 offset_in_block += buf_len; 401 } 402 403 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 404 guard = ctx->guard_seed; 405 } 406 407 return guard; 408 } 409 410 static void 411 dif_generate_split(struct _dif_sgl *sgl, uint32_t num_blocks, 412 const struct spdk_dif_ctx *ctx) 413 { 414 uint32_t offset_blocks; 415 uint16_t guard = 0; 416 417 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 418 guard = ctx->guard_seed; 419 } 420 421 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 422 _dif_generate_split(sgl, 0, ctx->block_size, guard, offset_blocks, ctx); 423 } 424 } 425 426 int 427 spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks, 428 const struct spdk_dif_ctx *ctx) 429 { 430 struct _dif_sgl sgl; 431 432 _dif_sgl_init(&sgl, iovs, iovcnt); 433 434 if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) { 435 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 436 return -EINVAL; 437 } 438 439 if (_dif_is_disabled(ctx->dif_type)) { 440 return 0; 441 } 442 443 if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) { 444 dif_generate(&sgl, num_blocks, ctx); 445 } else { 446 dif_generate_split(&sgl, num_blocks, ctx); 447 } 448 449 return 0; 450 } 451 452 static void 453 _dif_error_set(struct spdk_dif_error *err_blk, uint8_t err_type, 454 uint32_t expected, uint32_t actual, uint32_t err_offset) 455 { 456 if (err_blk) { 457 err_blk->err_type = err_type; 458 err_blk->expected = expected; 459 err_blk->actual = actual; 460 err_blk->err_offset = err_offset; 461 } 462 } 463 464 static int 465 _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks, 466 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 467 { 468 struct spdk_dif *dif = _dif; 469 uint16_t _guard; 470 uint16_t _app_tag; 471 uint32_t ref_tag, _ref_tag; 472 473 switch (ctx->dif_type) { 474 case SPDK_DIF_TYPE1: 475 case SPDK_DIF_TYPE2: 476 /* If Type 1 or 2 is used, then all DIF checks are disabled when 477 * the Application Tag is 0xFFFF. 478 */ 479 if (dif->app_tag == 0xFFFF) { 480 return 0; 481 } 482 break; 483 case SPDK_DIF_TYPE3: 484 /* If Type 3 is used, then all DIF checks are disabled when the 485 * Application Tag is 0xFFFF and the Reference Tag is 0xFFFFFFFF. 486 */ 487 if (dif->app_tag == 0xFFFF && dif->ref_tag == 0xFFFFFFFF) { 488 return 0; 489 } 490 break; 491 default: 492 break; 493 } 494 495 /* For type 1 and 2, the reference tag is incremented for each 496 * subsequent logical block. For type 3, the reference tag 497 * remains the same as the initial reference tag. 498 */ 499 if (ctx->dif_type != SPDK_DIF_TYPE3) { 500 ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks; 501 } else { 502 ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset; 503 } 504 505 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 506 /* Compare the DIF Guard field to the CRC computed over the logical 507 * block data. 508 */ 509 _guard = from_be16(&dif->guard); 510 if (_guard != guard) { 511 _dif_error_set(err_blk, SPDK_DIF_GUARD_ERROR, _guard, guard, 512 offset_blocks); 513 SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu32 "," \ 514 " Expected=%x, Actual=%x\n", 515 ref_tag, _guard, guard); 516 return -1; 517 } 518 } 519 520 if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) { 521 /* Compare unmasked bits in the DIF Application Tag field to the 522 * passed Application Tag. 523 */ 524 _app_tag = from_be16(&dif->app_tag); 525 if ((_app_tag & ctx->apptag_mask) != ctx->app_tag) { 526 _dif_error_set(err_blk, SPDK_DIF_APPTAG_ERROR, ctx->app_tag, 527 (_app_tag & ctx->apptag_mask), offset_blocks); 528 SPDK_ERRLOG("Failed to compare App Tag: LBA=%" PRIu32 "," \ 529 " Expected=%x, Actual=%x\n", 530 ref_tag, ctx->app_tag, (_app_tag & ctx->apptag_mask)); 531 return -1; 532 } 533 } 534 535 if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) { 536 switch (ctx->dif_type) { 537 case SPDK_DIF_TYPE1: 538 case SPDK_DIF_TYPE2: 539 /* Compare the DIF Reference Tag field to the passed Reference Tag. 540 * The passed Reference Tag will be the least significant 4 bytes 541 * of the LBA when Type 1 is used, and application specific value 542 * if Type 2 is used, 543 */ 544 _ref_tag = from_be32(&dif->ref_tag); 545 if (_ref_tag != ref_tag) { 546 _dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, ref_tag, 547 _ref_tag, offset_blocks); 548 SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu32 "," \ 549 " Expected=%x, Actual=%x\n", 550 ref_tag, ref_tag, _ref_tag); 551 return -1; 552 } 553 break; 554 case SPDK_DIF_TYPE3: 555 /* For Type 3, computed Reference Tag remains unchanged. 556 * Hence ignore the Reference Tag field. 557 */ 558 break; 559 default: 560 break; 561 } 562 } 563 564 return 0; 565 } 566 567 static int 568 dif_verify(struct _dif_sgl *sgl, uint32_t num_blocks, 569 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 570 { 571 uint32_t offset_blocks = 0; 572 int rc; 573 void *buf; 574 uint16_t guard = 0; 575 576 while (offset_blocks < num_blocks) { 577 _dif_sgl_get_buf(sgl, &buf, NULL); 578 579 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 580 guard = spdk_crc16_t10dif(ctx->guard_seed, buf, ctx->guard_interval); 581 } 582 583 rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 584 if (rc != 0) { 585 return rc; 586 } 587 588 _dif_sgl_advance(sgl, ctx->block_size); 589 offset_blocks++; 590 } 591 592 return 0; 593 } 594 595 static int 596 _dif_verify_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len, 597 uint16_t *_guard, uint32_t offset_blocks, 598 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 599 { 600 uint32_t offset_in_dif, buf_len; 601 void *buf; 602 uint16_t guard; 603 struct spdk_dif dif = {}; 604 int rc; 605 606 assert(_guard != NULL); 607 assert(offset_in_block < ctx->guard_interval); 608 assert(offset_in_block + data_len < ctx->guard_interval || 609 offset_in_block + data_len == ctx->block_size); 610 611 guard = *_guard; 612 613 /* Compute CRC over split logical block data. */ 614 while (data_len != 0 && offset_in_block < ctx->guard_interval) { 615 _dif_sgl_get_buf(sgl, &buf, &buf_len); 616 buf_len = spdk_min(buf_len, data_len); 617 buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block); 618 619 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 620 guard = spdk_crc16_t10dif(guard, buf, buf_len); 621 } 622 623 _dif_sgl_advance(sgl, buf_len); 624 offset_in_block += buf_len; 625 data_len -= buf_len; 626 } 627 628 if (offset_in_block < ctx->guard_interval) { 629 *_guard = guard; 630 return 0; 631 } 632 633 /* Copy the split DIF field to the temporary DIF buffer, and then 634 * skip metadata field after DIF field (if any). */ 635 while (offset_in_block < ctx->block_size) { 636 _dif_sgl_get_buf(sgl, &buf, &buf_len); 637 638 if (offset_in_block < ctx->guard_interval + sizeof(struct spdk_dif)) { 639 offset_in_dif = offset_in_block - ctx->guard_interval; 640 buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif); 641 642 memcpy((uint8_t *)&dif + offset_in_dif, buf, buf_len); 643 } else { 644 buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block); 645 } 646 _dif_sgl_advance(sgl, buf_len); 647 offset_in_block += buf_len; 648 } 649 650 rc = _dif_verify(&dif, guard, offset_blocks, ctx, err_blk); 651 if (rc != 0) { 652 return rc; 653 } 654 655 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 656 guard = ctx->guard_seed; 657 } 658 659 *_guard = guard; 660 return 0; 661 } 662 663 static int 664 dif_verify_split(struct _dif_sgl *sgl, uint32_t num_blocks, 665 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 666 { 667 uint32_t offset_blocks; 668 uint16_t guard = 0; 669 int rc; 670 671 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 672 guard = ctx->guard_seed; 673 } 674 675 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 676 rc = _dif_verify_split(sgl, 0, ctx->block_size, &guard, offset_blocks, 677 ctx, err_blk); 678 if (rc != 0) { 679 return rc; 680 } 681 } 682 683 return 0; 684 } 685 686 int 687 spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks, 688 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 689 { 690 struct _dif_sgl sgl; 691 692 _dif_sgl_init(&sgl, iovs, iovcnt); 693 694 if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) { 695 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 696 return -EINVAL; 697 } 698 699 if (_dif_is_disabled(ctx->dif_type)) { 700 return 0; 701 } 702 703 if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) { 704 return dif_verify(&sgl, num_blocks, ctx, err_blk); 705 } else { 706 return dif_verify_split(&sgl, num_blocks, ctx, err_blk); 707 } 708 } 709 710 static uint32_t 711 dif_update_crc32c(struct _dif_sgl *sgl, uint32_t num_blocks, 712 uint32_t crc32c, const struct spdk_dif_ctx *ctx) 713 { 714 uint32_t offset_blocks; 715 void *buf; 716 717 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 718 _dif_sgl_get_buf(sgl, &buf, NULL); 719 720 crc32c = spdk_crc32c_update(buf, ctx->block_size - ctx->md_size, crc32c); 721 722 _dif_sgl_advance(sgl, ctx->block_size); 723 } 724 725 return crc32c; 726 } 727 728 static uint32_t 729 _dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len, 730 uint32_t crc32c, const struct spdk_dif_ctx *ctx) 731 { 732 uint32_t data_block_size, buf_len; 733 void *buf; 734 735 data_block_size = ctx->block_size - ctx->md_size; 736 737 assert(offset_in_block + data_len <= ctx->block_size); 738 739 while (data_len != 0) { 740 _dif_sgl_get_buf(sgl, &buf, &buf_len); 741 buf_len = spdk_min(buf_len, data_len); 742 743 if (offset_in_block < data_block_size) { 744 buf_len = spdk_min(buf_len, data_block_size - offset_in_block); 745 crc32c = spdk_crc32c_update(buf, buf_len, crc32c); 746 } 747 748 _dif_sgl_advance(sgl, buf_len); 749 offset_in_block += buf_len; 750 data_len -= buf_len; 751 } 752 753 return crc32c; 754 } 755 756 static uint32_t 757 dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t num_blocks, 758 uint32_t crc32c, const struct spdk_dif_ctx *ctx) 759 { 760 uint32_t offset_blocks; 761 762 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 763 crc32c = _dif_update_crc32c_split(sgl, 0, ctx->block_size, crc32c, ctx); 764 } 765 766 return crc32c; 767 } 768 769 int 770 spdk_dif_update_crc32c(struct iovec *iovs, int iovcnt, uint32_t num_blocks, 771 uint32_t *_crc32c, const struct spdk_dif_ctx *ctx) 772 { 773 struct _dif_sgl sgl; 774 775 if (_crc32c == NULL) { 776 return -EINVAL; 777 } 778 779 _dif_sgl_init(&sgl, iovs, iovcnt); 780 781 if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) { 782 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 783 return -EINVAL; 784 } 785 786 if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) { 787 *_crc32c = dif_update_crc32c(&sgl, num_blocks, *_crc32c, ctx); 788 } else { 789 *_crc32c = dif_update_crc32c_split(&sgl, num_blocks, *_crc32c, ctx); 790 } 791 792 return 0; 793 } 794 795 static void 796 dif_generate_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 797 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 798 { 799 uint32_t offset_blocks = 0, data_block_size; 800 void *src, *dst; 801 uint16_t guard; 802 803 data_block_size = ctx->block_size - ctx->md_size; 804 805 while (offset_blocks < num_blocks) { 806 _dif_sgl_get_buf(src_sgl, &src, NULL); 807 _dif_sgl_get_buf(dst_sgl, &dst, NULL); 808 809 guard = 0; 810 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 811 guard = spdk_crc16_t10dif_copy(ctx->guard_seed, dst, src, data_block_size); 812 guard = spdk_crc16_t10dif(guard, dst + data_block_size, 813 ctx->guard_interval - data_block_size); 814 } else { 815 memcpy(dst, src, data_block_size); 816 } 817 818 _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx); 819 820 _dif_sgl_advance(src_sgl, data_block_size); 821 _dif_sgl_advance(dst_sgl, ctx->block_size); 822 offset_blocks++; 823 } 824 } 825 826 static void 827 _dif_generate_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 828 uint32_t offset_blocks, const struct spdk_dif_ctx *ctx) 829 { 830 uint32_t offset_in_block, src_len, data_block_size; 831 uint16_t guard = 0; 832 void *src, *dst; 833 834 _dif_sgl_get_buf(dst_sgl, &dst, NULL); 835 836 data_block_size = ctx->block_size - ctx->md_size; 837 838 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 839 guard = ctx->guard_seed; 840 } 841 offset_in_block = 0; 842 843 while (offset_in_block < data_block_size) { 844 /* Compute CRC over split logical block data and copy 845 * data to bounce buffer. 846 */ 847 _dif_sgl_get_buf(src_sgl, &src, &src_len); 848 src_len = spdk_min(src_len, data_block_size - offset_in_block); 849 850 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 851 guard = spdk_crc16_t10dif_copy(guard, dst + offset_in_block, 852 src, src_len); 853 } else { 854 memcpy(dst + offset_in_block, src, src_len); 855 } 856 857 _dif_sgl_advance(src_sgl, src_len); 858 offset_in_block += src_len; 859 } 860 861 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 862 guard = spdk_crc16_t10dif(guard, dst + data_block_size, 863 ctx->guard_interval - data_block_size); 864 } 865 866 _dif_sgl_advance(dst_sgl, ctx->block_size); 867 868 _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx); 869 } 870 871 static void 872 dif_generate_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 873 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 874 { 875 uint32_t offset_blocks; 876 877 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 878 _dif_generate_copy_split(src_sgl, dst_sgl, offset_blocks, ctx); 879 } 880 } 881 882 int 883 spdk_dif_generate_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, 884 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 885 { 886 struct _dif_sgl src_sgl, dst_sgl; 887 uint32_t data_block_size; 888 889 _dif_sgl_init(&src_sgl, iovs, iovcnt); 890 _dif_sgl_init(&dst_sgl, bounce_iov, 1); 891 892 data_block_size = ctx->block_size - ctx->md_size; 893 894 if (!_dif_sgl_is_valid(&src_sgl, data_block_size * num_blocks) || 895 !_dif_sgl_is_valid(&dst_sgl, ctx->block_size * num_blocks)) { 896 SPDK_ERRLOG("Size of iovec arrays are not valid.\n"); 897 return -EINVAL; 898 } 899 900 if (_dif_is_disabled(ctx->dif_type)) { 901 return 0; 902 } 903 904 if (_dif_sgl_is_bytes_multiple(&src_sgl, data_block_size)) { 905 dif_generate_copy(&src_sgl, &dst_sgl, num_blocks, ctx); 906 } else { 907 dif_generate_copy_split(&src_sgl, &dst_sgl, num_blocks, ctx); 908 } 909 910 return 0; 911 } 912 913 static int 914 dif_verify_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 915 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 916 struct spdk_dif_error *err_blk) 917 { 918 uint32_t offset_blocks = 0, data_block_size; 919 void *src, *dst; 920 int rc; 921 uint16_t guard; 922 923 data_block_size = ctx->block_size - ctx->md_size; 924 925 while (offset_blocks < num_blocks) { 926 _dif_sgl_get_buf(src_sgl, &src, NULL); 927 _dif_sgl_get_buf(dst_sgl, &dst, NULL); 928 929 guard = 0; 930 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 931 guard = spdk_crc16_t10dif_copy(ctx->guard_seed, dst, src, data_block_size); 932 guard = spdk_crc16_t10dif(guard, src + data_block_size, 933 ctx->guard_interval - data_block_size); 934 } else { 935 memcpy(dst, src, data_block_size); 936 } 937 938 rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 939 if (rc != 0) { 940 return rc; 941 } 942 943 _dif_sgl_advance(src_sgl, ctx->block_size); 944 _dif_sgl_advance(dst_sgl, data_block_size); 945 offset_blocks++; 946 } 947 948 return 0; 949 } 950 951 static int 952 _dif_verify_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 953 uint32_t offset_blocks, const struct spdk_dif_ctx *ctx, 954 struct spdk_dif_error *err_blk) 955 { 956 uint32_t offset_in_block, dst_len, data_block_size; 957 uint16_t guard = 0; 958 void *src, *dst; 959 960 _dif_sgl_get_buf(src_sgl, &src, NULL); 961 962 data_block_size = ctx->block_size - ctx->md_size; 963 964 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 965 guard = ctx->guard_seed; 966 } 967 offset_in_block = 0; 968 969 while (offset_in_block < data_block_size) { 970 /* Compute CRC over split logical block data and copy 971 * data to bounce buffer. 972 */ 973 _dif_sgl_get_buf(dst_sgl, &dst, &dst_len); 974 dst_len = spdk_min(dst_len, data_block_size - offset_in_block); 975 976 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 977 guard = spdk_crc16_t10dif_copy(guard, dst, 978 src + offset_in_block, dst_len); 979 } else { 980 memcpy(dst, src + offset_in_block, dst_len); 981 } 982 983 _dif_sgl_advance(dst_sgl, dst_len); 984 offset_in_block += dst_len; 985 } 986 987 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 988 guard = spdk_crc16_t10dif(guard, src + data_block_size, 989 ctx->guard_interval - data_block_size); 990 } 991 992 _dif_sgl_advance(src_sgl, ctx->block_size); 993 994 return _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 995 } 996 997 static int 998 dif_verify_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 999 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1000 struct spdk_dif_error *err_blk) 1001 { 1002 uint32_t offset_blocks; 1003 int rc; 1004 1005 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 1006 rc = _dif_verify_copy_split(src_sgl, dst_sgl, offset_blocks, ctx, err_blk); 1007 if (rc != 0) { 1008 return rc; 1009 } 1010 } 1011 1012 return 0; 1013 } 1014 1015 int 1016 spdk_dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, 1017 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1018 struct spdk_dif_error *err_blk) 1019 { 1020 struct _dif_sgl src_sgl, dst_sgl; 1021 uint32_t data_block_size; 1022 1023 _dif_sgl_init(&src_sgl, bounce_iov, 1); 1024 _dif_sgl_init(&dst_sgl, iovs, iovcnt); 1025 1026 data_block_size = ctx->block_size - ctx->md_size; 1027 1028 if (!_dif_sgl_is_valid(&dst_sgl, data_block_size * num_blocks) || 1029 !_dif_sgl_is_valid(&src_sgl, ctx->block_size * num_blocks)) { 1030 SPDK_ERRLOG("Size of iovec arrays are not valid\n"); 1031 return -EINVAL; 1032 } 1033 1034 if (_dif_is_disabled(ctx->dif_type)) { 1035 return 0; 1036 } 1037 1038 if (_dif_sgl_is_bytes_multiple(&dst_sgl, data_block_size)) { 1039 return dif_verify_copy(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk); 1040 } else { 1041 return dif_verify_copy_split(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk); 1042 } 1043 } 1044 1045 static void 1046 _bit_flip(uint8_t *buf, uint32_t flip_bit) 1047 { 1048 uint8_t byte; 1049 1050 byte = *buf; 1051 byte ^= 1 << flip_bit; 1052 *buf = byte; 1053 } 1054 1055 static int 1056 _dif_inject_error(struct _dif_sgl *sgl, 1057 uint32_t block_size, uint32_t num_blocks, 1058 uint32_t inject_offset_blocks, 1059 uint32_t inject_offset_bytes, 1060 uint32_t inject_offset_bits) 1061 { 1062 uint32_t offset_in_block, buf_len; 1063 void *buf; 1064 1065 _dif_sgl_advance(sgl, block_size * inject_offset_blocks); 1066 1067 offset_in_block = 0; 1068 1069 while (offset_in_block < block_size) { 1070 _dif_sgl_get_buf(sgl, &buf, &buf_len); 1071 buf_len = spdk_min(buf_len, block_size - offset_in_block); 1072 1073 if (inject_offset_bytes >= offset_in_block && 1074 inject_offset_bytes < offset_in_block + buf_len) { 1075 buf += inject_offset_bytes - offset_in_block; 1076 _bit_flip(buf, inject_offset_bits); 1077 return 0; 1078 } 1079 1080 _dif_sgl_advance(sgl, buf_len); 1081 offset_in_block += buf_len; 1082 } 1083 1084 return -1; 1085 } 1086 1087 static int 1088 dif_inject_error(struct _dif_sgl *sgl, uint32_t block_size, uint32_t num_blocks, 1089 uint32_t start_inject_bytes, uint32_t inject_range_bytes, 1090 uint32_t *inject_offset) 1091 { 1092 uint32_t inject_offset_blocks, inject_offset_bytes, inject_offset_bits; 1093 uint32_t offset_blocks; 1094 int rc; 1095 1096 srand(time(0)); 1097 1098 inject_offset_blocks = rand() % num_blocks; 1099 inject_offset_bytes = start_inject_bytes + (rand() % inject_range_bytes); 1100 inject_offset_bits = rand() % 8; 1101 1102 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 1103 if (offset_blocks == inject_offset_blocks) { 1104 rc = _dif_inject_error(sgl, block_size, num_blocks, 1105 inject_offset_blocks, 1106 inject_offset_bytes, 1107 inject_offset_bits); 1108 if (rc == 0) { 1109 *inject_offset = inject_offset_blocks; 1110 } 1111 return rc; 1112 } 1113 } 1114 1115 return -1; 1116 } 1117 1118 #define _member_size(type, member) sizeof(((type *)0)->member) 1119 1120 int 1121 spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks, 1122 const struct spdk_dif_ctx *ctx, uint32_t inject_flags, 1123 uint32_t *inject_offset) 1124 { 1125 struct _dif_sgl sgl; 1126 int rc; 1127 1128 _dif_sgl_init(&sgl, iovs, iovcnt); 1129 1130 if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) { 1131 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 1132 return -EINVAL; 1133 } 1134 1135 if (inject_flags & SPDK_DIF_REFTAG_ERROR) { 1136 rc = dif_inject_error(&sgl, ctx->block_size, num_blocks, 1137 ctx->guard_interval + offsetof(struct spdk_dif, ref_tag), 1138 _member_size(struct spdk_dif, ref_tag), 1139 inject_offset); 1140 if (rc != 0) { 1141 SPDK_ERRLOG("Failed to inject error to Reference Tag.\n"); 1142 return rc; 1143 } 1144 } 1145 1146 if (inject_flags & SPDK_DIF_APPTAG_ERROR) { 1147 rc = dif_inject_error(&sgl, ctx->block_size, num_blocks, 1148 ctx->guard_interval + offsetof(struct spdk_dif, app_tag), 1149 _member_size(struct spdk_dif, app_tag), 1150 inject_offset); 1151 if (rc != 0) { 1152 SPDK_ERRLOG("Failed to inject error to Application Tag.\n"); 1153 return rc; 1154 } 1155 } 1156 if (inject_flags & SPDK_DIF_GUARD_ERROR) { 1157 rc = dif_inject_error(&sgl, ctx->block_size, num_blocks, 1158 ctx->guard_interval, 1159 _member_size(struct spdk_dif, guard), 1160 inject_offset); 1161 if (rc != 0) { 1162 SPDK_ERRLOG("Failed to inject error to Guard.\n"); 1163 return rc; 1164 } 1165 } 1166 1167 if (inject_flags & SPDK_DIF_DATA_ERROR) { 1168 /* If the DIF information is contained within the last 8 bytes of 1169 * metadata, then the CRC covers all metadata bytes up to but excluding 1170 * the last 8 bytes. But error injection does not cover these metadata 1171 * because classification is not determined yet. 1172 * 1173 * Note: Error injection to data block is expected to be detected as 1174 * guard error. 1175 */ 1176 rc = dif_inject_error(&sgl, ctx->block_size, num_blocks, 1177 0, 1178 ctx->block_size - ctx->md_size, 1179 inject_offset); 1180 if (rc != 0) { 1181 SPDK_ERRLOG("Failed to inject error to data block.\n"); 1182 return rc; 1183 } 1184 } 1185 1186 return 0; 1187 } 1188 1189 static void 1190 dix_generate(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1191 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 1192 { 1193 uint32_t offset_blocks = 0; 1194 uint16_t guard; 1195 void *data_buf, *md_buf; 1196 1197 while (offset_blocks < num_blocks) { 1198 _dif_sgl_get_buf(data_sgl, &data_buf, NULL); 1199 _dif_sgl_get_buf(md_sgl, &md_buf, NULL); 1200 1201 guard = 0; 1202 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1203 guard = spdk_crc16_t10dif(ctx->guard_seed, data_buf, ctx->block_size); 1204 guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval); 1205 } 1206 1207 _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx); 1208 1209 _dif_sgl_advance(data_sgl, ctx->block_size); 1210 _dif_sgl_advance(md_sgl, ctx->md_size); 1211 offset_blocks++; 1212 } 1213 } 1214 1215 static void 1216 _dix_generate_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1217 uint32_t offset_blocks, const struct spdk_dif_ctx *ctx) 1218 { 1219 uint32_t offset_in_block, data_buf_len; 1220 uint16_t guard = 0; 1221 void *data_buf, *md_buf; 1222 1223 _dif_sgl_get_buf(md_sgl, &md_buf, NULL); 1224 1225 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1226 guard = ctx->guard_seed; 1227 } 1228 offset_in_block = 0; 1229 1230 while (offset_in_block < ctx->block_size) { 1231 _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len); 1232 data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block); 1233 1234 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1235 guard = spdk_crc16_t10dif(guard, data_buf, data_buf_len); 1236 } 1237 1238 _dif_sgl_advance(data_sgl, data_buf_len); 1239 offset_in_block += data_buf_len; 1240 } 1241 1242 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1243 guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval); 1244 } 1245 1246 _dif_sgl_advance(md_sgl, ctx->md_size); 1247 1248 _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx); 1249 } 1250 1251 static void 1252 dix_generate_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1253 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 1254 { 1255 uint32_t offset_blocks; 1256 1257 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 1258 _dix_generate_split(data_sgl, md_sgl, offset_blocks, ctx); 1259 } 1260 } 1261 1262 int 1263 spdk_dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov, 1264 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 1265 { 1266 struct _dif_sgl data_sgl, md_sgl; 1267 1268 _dif_sgl_init(&data_sgl, iovs, iovcnt); 1269 _dif_sgl_init(&md_sgl, md_iov, 1); 1270 1271 if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) || 1272 !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) { 1273 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 1274 return -EINVAL; 1275 } 1276 1277 if (_dif_is_disabled(ctx->dif_type)) { 1278 return 0; 1279 } 1280 1281 if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) { 1282 dix_generate(&data_sgl, &md_sgl, num_blocks, ctx); 1283 } else { 1284 dix_generate_split(&data_sgl, &md_sgl, num_blocks, ctx); 1285 } 1286 1287 return 0; 1288 } 1289 1290 static int 1291 dix_verify(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1292 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1293 struct spdk_dif_error *err_blk) 1294 { 1295 uint32_t offset_blocks = 0; 1296 uint16_t guard; 1297 void *data_buf, *md_buf; 1298 int rc; 1299 1300 while (offset_blocks < num_blocks) { 1301 _dif_sgl_get_buf(data_sgl, &data_buf, NULL); 1302 _dif_sgl_get_buf(md_sgl, &md_buf, NULL); 1303 1304 guard = 0; 1305 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1306 guard = spdk_crc16_t10dif(ctx->guard_seed, data_buf, ctx->block_size); 1307 guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval); 1308 } 1309 1310 rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 1311 if (rc != 0) { 1312 return rc; 1313 } 1314 1315 _dif_sgl_advance(data_sgl, ctx->block_size); 1316 _dif_sgl_advance(md_sgl, ctx->md_size); 1317 offset_blocks++; 1318 } 1319 1320 return 0; 1321 } 1322 1323 static int 1324 _dix_verify_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1325 uint32_t offset_blocks, const struct spdk_dif_ctx *ctx, 1326 struct spdk_dif_error *err_blk) 1327 { 1328 uint32_t offset_in_block, data_buf_len; 1329 uint16_t guard = 0; 1330 void *data_buf, *md_buf; 1331 1332 _dif_sgl_get_buf(md_sgl, &md_buf, NULL); 1333 1334 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1335 guard = ctx->guard_seed; 1336 } 1337 offset_in_block = 0; 1338 1339 while (offset_in_block < ctx->block_size) { 1340 _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len); 1341 data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block); 1342 1343 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1344 guard = spdk_crc16_t10dif(guard, data_buf, data_buf_len); 1345 } 1346 1347 _dif_sgl_advance(data_sgl, data_buf_len); 1348 offset_in_block += data_buf_len; 1349 } 1350 1351 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1352 guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval); 1353 } 1354 1355 _dif_sgl_advance(md_sgl, ctx->md_size); 1356 1357 return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 1358 } 1359 1360 static int 1361 dix_verify_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1362 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1363 struct spdk_dif_error *err_blk) 1364 { 1365 uint32_t offset_blocks; 1366 int rc; 1367 1368 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 1369 rc = _dix_verify_split(data_sgl, md_sgl, offset_blocks, ctx, err_blk); 1370 if (rc != 0) { 1371 return rc; 1372 } 1373 } 1374 1375 return 0; 1376 } 1377 1378 int 1379 spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov, 1380 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1381 struct spdk_dif_error *err_blk) 1382 { 1383 struct _dif_sgl data_sgl, md_sgl; 1384 1385 _dif_sgl_init(&data_sgl, iovs, iovcnt); 1386 _dif_sgl_init(&md_sgl, md_iov, 1); 1387 1388 if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) || 1389 !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) { 1390 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 1391 return -EINVAL; 1392 } 1393 1394 if (_dif_is_disabled(ctx->dif_type)) { 1395 return 0; 1396 } 1397 1398 if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) { 1399 return dix_verify(&data_sgl, &md_sgl, num_blocks, ctx, err_blk); 1400 } else { 1401 return dix_verify_split(&data_sgl, &md_sgl, num_blocks, ctx, err_blk); 1402 } 1403 } 1404 1405 int 1406 spdk_dix_inject_error(struct iovec *iovs, int iovcnt, struct iovec *md_iov, 1407 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1408 uint32_t inject_flags, uint32_t *inject_offset) 1409 { 1410 struct _dif_sgl data_sgl, md_sgl; 1411 int rc; 1412 1413 _dif_sgl_init(&data_sgl, iovs, iovcnt); 1414 _dif_sgl_init(&md_sgl, md_iov, 1); 1415 1416 if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) || 1417 !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) { 1418 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 1419 return -EINVAL; 1420 } 1421 1422 if (inject_flags & SPDK_DIF_REFTAG_ERROR) { 1423 rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks, 1424 ctx->guard_interval + offsetof(struct spdk_dif, ref_tag), 1425 _member_size(struct spdk_dif, ref_tag), 1426 inject_offset); 1427 if (rc != 0) { 1428 SPDK_ERRLOG("Failed to inject error to Reference Tag.\n"); 1429 return rc; 1430 } 1431 } 1432 1433 if (inject_flags & SPDK_DIF_APPTAG_ERROR) { 1434 rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks, 1435 ctx->guard_interval + offsetof(struct spdk_dif, app_tag), 1436 _member_size(struct spdk_dif, app_tag), 1437 inject_offset); 1438 if (rc != 0) { 1439 SPDK_ERRLOG("Failed to inject error to Application Tag.\n"); 1440 return rc; 1441 } 1442 } 1443 1444 if (inject_flags & SPDK_DIF_GUARD_ERROR) { 1445 rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks, 1446 ctx->guard_interval, 1447 _member_size(struct spdk_dif, guard), 1448 inject_offset); 1449 if (rc != 0) { 1450 SPDK_ERRLOG("Failed to inject error to Guard.\n"); 1451 return rc; 1452 } 1453 } 1454 1455 if (inject_flags & SPDK_DIF_DATA_ERROR) { 1456 /* Note: Error injection to data block is expected to be detected 1457 * as guard error. 1458 */ 1459 rc = dif_inject_error(&data_sgl, ctx->block_size, num_blocks, 1460 0, 1461 ctx->block_size, 1462 inject_offset); 1463 if (rc != 0) { 1464 SPDK_ERRLOG("Failed to inject error to Guard.\n"); 1465 return rc; 1466 } 1467 } 1468 1469 return 0; 1470 } 1471 1472 static uint32_t 1473 _to_next_boundary(uint32_t offset, uint32_t boundary) 1474 { 1475 return boundary - (offset % boundary); 1476 } 1477 1478 static uint32_t 1479 _to_size_with_md(uint32_t size, uint32_t data_block_size, uint32_t block_size) 1480 { 1481 return (size / data_block_size) * block_size + (size % data_block_size); 1482 } 1483 1484 int 1485 spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt, 1486 struct iovec *buf_iovs, int buf_iovcnt, 1487 uint32_t data_offset, uint32_t data_len, 1488 uint32_t *_mapped_len, 1489 const struct spdk_dif_ctx *ctx) 1490 { 1491 uint32_t data_block_size, data_unalign, buf_len, buf_offset, len; 1492 struct _dif_sgl dif_sgl; 1493 struct _dif_sgl buf_sgl; 1494 1495 if (iovs == NULL || iovcnt == 0 || buf_iovs == NULL || buf_iovcnt == 0) { 1496 return -EINVAL; 1497 } 1498 1499 data_block_size = ctx->block_size - ctx->md_size; 1500 1501 data_unalign = ctx->data_offset % data_block_size; 1502 1503 buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size, 1504 ctx->block_size); 1505 buf_len -= data_unalign; 1506 1507 _dif_sgl_init(&dif_sgl, iovs, iovcnt); 1508 _dif_sgl_init(&buf_sgl, buf_iovs, buf_iovcnt); 1509 1510 if (!_dif_sgl_is_valid(&buf_sgl, buf_len)) { 1511 SPDK_ERRLOG("Buffer overflow will occur.\n"); 1512 return -ERANGE; 1513 } 1514 1515 buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size); 1516 buf_offset -= data_unalign; 1517 1518 _dif_sgl_advance(&buf_sgl, buf_offset); 1519 1520 while (data_len != 0) { 1521 len = spdk_min(data_len, _to_next_boundary(ctx->data_offset + data_offset, data_block_size)); 1522 if (!_dif_sgl_append_split(&dif_sgl, &buf_sgl, len)) { 1523 break; 1524 } 1525 _dif_sgl_advance(&buf_sgl, ctx->md_size); 1526 data_offset += len; 1527 data_len -= len; 1528 } 1529 1530 if (_mapped_len != NULL) { 1531 *_mapped_len = dif_sgl.total_size; 1532 } 1533 1534 return iovcnt - dif_sgl.iovcnt; 1535 } 1536 1537 static int 1538 _dif_sgl_setup_stream(struct _dif_sgl *sgl, uint32_t *_buf_offset, uint32_t *_buf_len, 1539 uint32_t data_offset, uint32_t data_len, 1540 const struct spdk_dif_ctx *ctx) 1541 { 1542 uint32_t data_block_size, data_unalign, buf_len, buf_offset; 1543 1544 data_block_size = ctx->block_size - ctx->md_size; 1545 1546 data_unalign = ctx->data_offset % data_block_size; 1547 1548 /* If the last data block is complete, DIF of the data block is 1549 * inserted or verified in this turn. 1550 */ 1551 buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size, 1552 ctx->block_size); 1553 buf_len -= data_unalign; 1554 1555 if (!_dif_sgl_is_valid(sgl, buf_len)) { 1556 return -ERANGE; 1557 } 1558 1559 buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size); 1560 buf_offset -= data_unalign; 1561 1562 _dif_sgl_advance(sgl, buf_offset); 1563 buf_len -= buf_offset; 1564 1565 buf_offset += data_unalign; 1566 1567 *_buf_offset = buf_offset; 1568 *_buf_len = buf_len; 1569 1570 return 0; 1571 } 1572 1573 int 1574 spdk_dif_generate_stream(struct iovec *iovs, int iovcnt, 1575 uint32_t data_offset, uint32_t data_len, 1576 struct spdk_dif_ctx *ctx) 1577 { 1578 uint32_t buf_len = 0, buf_offset = 0; 1579 uint32_t len, offset_in_block, offset_blocks; 1580 uint16_t guard = 0; 1581 struct _dif_sgl sgl; 1582 int rc; 1583 1584 if (iovs == NULL || iovcnt == 0) { 1585 return -EINVAL; 1586 } 1587 1588 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1589 guard = ctx->last_guard; 1590 } 1591 1592 _dif_sgl_init(&sgl, iovs, iovcnt); 1593 1594 rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx); 1595 if (rc != 0) { 1596 return rc; 1597 } 1598 1599 while (buf_len != 0) { 1600 len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size)); 1601 offset_in_block = buf_offset % ctx->block_size; 1602 offset_blocks = buf_offset / ctx->block_size; 1603 1604 guard = _dif_generate_split(&sgl, offset_in_block, len, guard, offset_blocks, ctx); 1605 1606 buf_len -= len; 1607 buf_offset += len; 1608 } 1609 1610 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1611 ctx->last_guard = guard; 1612 } 1613 1614 return 0; 1615 } 1616 1617 int 1618 spdk_dif_verify_stream(struct iovec *iovs, int iovcnt, 1619 uint32_t data_offset, uint32_t data_len, 1620 struct spdk_dif_ctx *ctx, 1621 struct spdk_dif_error *err_blk) 1622 { 1623 uint32_t buf_len = 0, buf_offset = 0; 1624 uint32_t len, offset_in_block, offset_blocks; 1625 uint16_t guard = 0; 1626 struct _dif_sgl sgl; 1627 int rc = 0; 1628 1629 if (iovs == NULL || iovcnt == 0) { 1630 return -EINVAL; 1631 } 1632 1633 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1634 guard = ctx->last_guard; 1635 } 1636 1637 _dif_sgl_init(&sgl, iovs, iovcnt); 1638 1639 rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx); 1640 if (rc != 0) { 1641 return rc; 1642 } 1643 1644 while (buf_len != 0) { 1645 len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size)); 1646 offset_in_block = buf_offset % ctx->block_size; 1647 offset_blocks = buf_offset / ctx->block_size; 1648 1649 rc = _dif_verify_split(&sgl, offset_in_block, len, &guard, offset_blocks, 1650 ctx, err_blk); 1651 if (rc != 0) { 1652 goto error; 1653 } 1654 1655 buf_len -= len; 1656 buf_offset += len; 1657 } 1658 1659 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1660 ctx->last_guard = guard; 1661 } 1662 error: 1663 return rc; 1664 } 1665 1666 int 1667 spdk_dif_update_crc32c_stream(struct iovec *iovs, int iovcnt, 1668 uint32_t data_offset, uint32_t data_len, 1669 uint32_t *_crc32c, const struct spdk_dif_ctx *ctx) 1670 { 1671 uint32_t buf_len = 0, buf_offset = 0, len, offset_in_block; 1672 uint32_t crc32c; 1673 struct _dif_sgl sgl; 1674 int rc; 1675 1676 if (iovs == NULL || iovcnt == 0) { 1677 return -EINVAL; 1678 } 1679 1680 crc32c = *_crc32c; 1681 _dif_sgl_init(&sgl, iovs, iovcnt); 1682 1683 rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx); 1684 if (rc != 0) { 1685 return rc; 1686 } 1687 1688 while (buf_len != 0) { 1689 len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size)); 1690 offset_in_block = buf_offset % ctx->block_size; 1691 1692 crc32c = _dif_update_crc32c_split(&sgl, offset_in_block, len, crc32c, ctx); 1693 1694 buf_len -= len; 1695 buf_offset += len; 1696 } 1697 1698 *_crc32c = crc32c; 1699 1700 return 0; 1701 } 1702 1703 void 1704 spdk_dif_get_range_with_md(uint32_t data_offset, uint32_t data_len, 1705 uint32_t *_buf_offset, uint32_t *_buf_len, 1706 const struct spdk_dif_ctx *ctx) 1707 { 1708 uint32_t data_block_size, data_unalign, buf_offset, buf_len; 1709 1710 if (!ctx->md_interleave) { 1711 buf_offset = data_offset; 1712 buf_len = data_len; 1713 } else { 1714 data_block_size = ctx->block_size - ctx->md_size; 1715 1716 data_unalign = data_offset % data_block_size; 1717 1718 buf_offset = _to_size_with_md(data_offset, data_block_size, ctx->block_size); 1719 buf_len = _to_size_with_md(data_unalign + data_len, data_block_size, ctx->block_size) - 1720 data_unalign; 1721 } 1722 1723 if (_buf_offset != NULL) { 1724 *_buf_offset = buf_offset; 1725 } 1726 1727 if (_buf_len != NULL) { 1728 *_buf_len = buf_len; 1729 } 1730 } 1731 1732 uint32_t 1733 spdk_dif_get_length_with_md(uint32_t data_len, const struct spdk_dif_ctx *ctx) 1734 { 1735 uint32_t data_block_size; 1736 1737 if (!ctx->md_interleave) { 1738 return data_len; 1739 } else { 1740 data_block_size = ctx->block_size - ctx->md_size; 1741 1742 return _to_size_with_md(data_len, data_block_size, ctx->block_size); 1743 } 1744 } 1745 1746 static int 1747 _dif_remap_ref_tag(struct _dif_sgl *sgl, uint32_t offset_blocks, 1748 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 1749 { 1750 uint32_t offset, buf_len, expected = 0, _actual, remapped; 1751 void *buf; 1752 struct _dif_sgl tmp_sgl; 1753 struct spdk_dif dif; 1754 1755 /* Fast forward to DIF field. */ 1756 _dif_sgl_advance(sgl, ctx->guard_interval); 1757 _dif_sgl_copy(&tmp_sgl, sgl); 1758 1759 /* Copy the split DIF field to the temporary DIF buffer */ 1760 offset = 0; 1761 while (offset < sizeof(struct spdk_dif)) { 1762 _dif_sgl_get_buf(sgl, &buf, &buf_len); 1763 buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset); 1764 1765 memcpy((uint8_t *)&dif + offset, buf, buf_len); 1766 1767 _dif_sgl_advance(sgl, buf_len); 1768 offset += buf_len; 1769 } 1770 1771 switch (ctx->dif_type) { 1772 case SPDK_DIF_TYPE1: 1773 case SPDK_DIF_TYPE2: 1774 /* If Type 1 or 2 is used, then all DIF checks are disabled when 1775 * the Application Tag is 0xFFFF. 1776 */ 1777 if (dif.app_tag == 0xFFFF) { 1778 goto end; 1779 } 1780 break; 1781 case SPDK_DIF_TYPE3: 1782 /* If Type 3 is used, then all DIF checks are disabled when the 1783 * Application Tag is 0xFFFF and the Reference Tag is 0xFFFFFFFF. 1784 */ 1785 if (dif.app_tag == 0xFFFF && dif.ref_tag == 0xFFFFFFFF) { 1786 goto end; 1787 } 1788 break; 1789 default: 1790 break; 1791 } 1792 1793 /* For type 1 and 2, the Reference Tag is incremented for each 1794 * subsequent logical block. For type 3, the Reference Tag 1795 * remains the same as the initial Reference Tag. 1796 */ 1797 if (ctx->dif_type != SPDK_DIF_TYPE3) { 1798 expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks; 1799 remapped = ctx->remapped_init_ref_tag + ctx->ref_tag_offset + offset_blocks; 1800 } else { 1801 remapped = ctx->remapped_init_ref_tag; 1802 } 1803 1804 /* Verify the stored Reference Tag. */ 1805 switch (ctx->dif_type) { 1806 case SPDK_DIF_TYPE1: 1807 case SPDK_DIF_TYPE2: 1808 /* Compare the DIF Reference Tag field to the computed Reference Tag. 1809 * The computed Reference Tag will be the least significant 4 bytes 1810 * of the LBA when Type 1 is used, and application specific value 1811 * if Type 2 is used. 1812 */ 1813 _actual = from_be32(&dif.ref_tag); 1814 if (_actual != expected) { 1815 _dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, expected, 1816 _actual, offset_blocks); 1817 SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu32 "," \ 1818 " Expected=%x, Actual=%x\n", 1819 expected, expected, _actual); 1820 return -1; 1821 } 1822 break; 1823 case SPDK_DIF_TYPE3: 1824 /* For type 3, the computed Reference Tag remains unchanged. 1825 * Hence ignore the Reference Tag field. 1826 */ 1827 break; 1828 default: 1829 break; 1830 } 1831 1832 /* Update the stored Reference Tag to the remapped one. */ 1833 to_be32(&dif.ref_tag, remapped); 1834 1835 offset = 0; 1836 while (offset < sizeof(struct spdk_dif)) { 1837 _dif_sgl_get_buf(&tmp_sgl, &buf, &buf_len); 1838 buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset); 1839 1840 memcpy(buf, (uint8_t *)&dif + offset, buf_len); 1841 1842 _dif_sgl_advance(&tmp_sgl, buf_len); 1843 offset += buf_len; 1844 } 1845 1846 end: 1847 _dif_sgl_advance(sgl, ctx->block_size - ctx->guard_interval - sizeof(struct spdk_dif)); 1848 1849 return 0; 1850 } 1851 1852 int 1853 spdk_dif_remap_ref_tag(struct iovec *iovs, int iovcnt, uint32_t num_blocks, 1854 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 1855 { 1856 struct _dif_sgl sgl; 1857 uint32_t offset_blocks; 1858 int rc; 1859 1860 _dif_sgl_init(&sgl, iovs, iovcnt); 1861 1862 if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) { 1863 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 1864 return -EINVAL; 1865 } 1866 1867 if (_dif_is_disabled(ctx->dif_type)) { 1868 return 0; 1869 } 1870 1871 if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) { 1872 return 0; 1873 } 1874 1875 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 1876 rc = _dif_remap_ref_tag(&sgl, offset_blocks, ctx, err_blk); 1877 if (rc != 0) { 1878 return rc; 1879 } 1880 } 1881 1882 return 0; 1883 } 1884 1885 static int 1886 _dix_remap_ref_tag(struct _dif_sgl *md_sgl, uint32_t offset_blocks, 1887 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 1888 { 1889 uint32_t expected = 0, _actual, remapped; 1890 uint8_t *md_buf; 1891 struct spdk_dif *dif; 1892 1893 _dif_sgl_get_buf(md_sgl, (void *)&md_buf, NULL); 1894 1895 dif = (struct spdk_dif *)(md_buf + ctx->guard_interval); 1896 1897 switch (ctx->dif_type) { 1898 case SPDK_DIF_TYPE1: 1899 case SPDK_DIF_TYPE2: 1900 /* If Type 1 or 2 is used, then all DIF checks are disabled when 1901 * the Application Tag is 0xFFFF. 1902 */ 1903 if (dif->app_tag == 0xFFFF) { 1904 goto end; 1905 } 1906 break; 1907 case SPDK_DIF_TYPE3: 1908 /* If Type 3 is used, then all DIF checks are disabled when the 1909 * Application Tag is 0xFFFF and the Reference Tag is 0xFFFFFFFF. 1910 */ 1911 if (dif->app_tag == 0xFFFF && dif->ref_tag == 0xFFFFFFFF) { 1912 goto end; 1913 } 1914 break; 1915 default: 1916 break; 1917 } 1918 1919 /* For type 1 and 2, the Reference Tag is incremented for each 1920 * subsequent logical block. For type 3, the Reference Tag 1921 * remains the same as the initialReference Tag. 1922 */ 1923 if (ctx->dif_type != SPDK_DIF_TYPE3) { 1924 expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks; 1925 remapped = ctx->remapped_init_ref_tag + ctx->ref_tag_offset + offset_blocks; 1926 } else { 1927 remapped = ctx->remapped_init_ref_tag; 1928 } 1929 1930 /* Verify the stored Reference Tag. */ 1931 switch (ctx->dif_type) { 1932 case SPDK_DIF_TYPE1: 1933 case SPDK_DIF_TYPE2: 1934 /* Compare the DIF Reference Tag field to the computed Reference Tag. 1935 * The computed Reference Tag will be the least significant 4 bytes 1936 * of the LBA when Type 1 is used, and application specific value 1937 * if Type 2 is used. 1938 */ 1939 _actual = from_be32(&dif->ref_tag); 1940 if (_actual != expected) { 1941 _dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, expected, 1942 _actual, offset_blocks); 1943 SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu32 "," \ 1944 " Expected=%x, Actual=%x\n", 1945 expected, expected, _actual); 1946 return -1; 1947 } 1948 break; 1949 case SPDK_DIF_TYPE3: 1950 /* For type 3, the computed Reference Tag remains unchanged. 1951 * Hence ignore the Reference Tag field. 1952 */ 1953 break; 1954 default: 1955 break; 1956 } 1957 1958 /* Update the stored Reference Tag to the remapped one. */ 1959 to_be32(&dif->ref_tag, remapped); 1960 1961 end: 1962 _dif_sgl_advance(md_sgl, ctx->md_size); 1963 1964 return 0; 1965 } 1966 1967 int 1968 spdk_dix_remap_ref_tag(struct iovec *md_iov, uint32_t num_blocks, 1969 const struct spdk_dif_ctx *ctx, 1970 struct spdk_dif_error *err_blk) 1971 { 1972 struct _dif_sgl md_sgl; 1973 uint32_t offset_blocks; 1974 int rc; 1975 1976 _dif_sgl_init(&md_sgl, md_iov, 1); 1977 1978 if (!_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) { 1979 SPDK_ERRLOG("Size of metadata iovec array is not valid.\n"); 1980 return -EINVAL; 1981 } 1982 1983 if (_dif_is_disabled(ctx->dif_type)) { 1984 return 0; 1985 } 1986 1987 if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) { 1988 return 0; 1989 } 1990 1991 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 1992 rc = _dix_remap_ref_tag(&md_sgl, offset_blocks, ctx, err_blk); 1993 if (rc != 0) { 1994 return rc; 1995 } 1996 } 1997 1998 return 0; 1999 } 2000