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