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