1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/dif.h" 35 #include "spdk/crc16.h" 36 #include "spdk/endian.h" 37 #include "spdk/log.h" 38 #include "spdk/util.h" 39 40 /* Context to iterate or create a iovec array. 41 * Each sgl is either iterated or created at a time. 42 */ 43 struct _dif_sgl { 44 /* Current iovec in the iteration or iteration */ 45 struct iovec *iov; 46 47 /* Remaining count of iovecs in the iteration or iteration. */ 48 int iovcnt; 49 50 /* Current offset in the iovec */ 51 uint32_t iov_offset; 52 53 /* Size of the created iovec array in bytes */ 54 uint32_t total_size; 55 }; 56 57 static inline void 58 _dif_sgl_init(struct _dif_sgl *s, struct iovec *iovs, int iovcnt) 59 { 60 s->iov = iovs; 61 s->iovcnt = iovcnt; 62 s->iov_offset = 0; 63 s->total_size = 0; 64 } 65 66 static inline void 67 _dif_sgl_advance(struct _dif_sgl *s, uint32_t step) 68 { 69 s->iov_offset += step; 70 if (s->iov_offset == s->iov->iov_len) { 71 s->iov++; 72 assert(s->iovcnt > 0); 73 s->iovcnt--; 74 s->iov_offset = 0; 75 } 76 } 77 78 static inline void 79 _dif_sgl_get_buf(struct _dif_sgl *s, void **_buf, uint32_t *_buf_len) 80 { 81 if (_buf != NULL) { 82 *_buf = s->iov->iov_base + s->iov_offset; 83 } 84 if (_buf_len != NULL) { 85 *_buf_len = s->iov->iov_len - s->iov_offset; 86 } 87 } 88 89 static void 90 _dif_sgl_fast_forward(struct _dif_sgl *s, uint32_t offset) 91 { 92 s->iov_offset += offset; 93 while (s->iovcnt != 0) { 94 if (s->iov_offset < s->iov->iov_len) { 95 break; 96 } 97 98 s->iov_offset -= s->iov->iov_len; 99 s->iov++; 100 s->iovcnt--; 101 } 102 } 103 104 static inline bool 105 _dif_sgl_append(struct _dif_sgl *s, uint8_t *data, uint32_t data_len) 106 { 107 assert(s->iovcnt > 0); 108 s->iov->iov_base = data; 109 s->iov->iov_len = data_len; 110 s->total_size += data_len; 111 s->iov++; 112 s->iovcnt--; 113 114 if (s->iovcnt > 0) { 115 return true; 116 } else { 117 return false; 118 } 119 } 120 121 /* This function must be used before starting iteration. */ 122 static bool 123 _dif_sgl_is_bytes_multiple(struct _dif_sgl *s, uint32_t bytes) 124 { 125 int i; 126 127 for (i = 0; i < s->iovcnt; i++) { 128 if (s->iov[i].iov_len % bytes) { 129 return false; 130 } 131 } 132 133 return true; 134 } 135 136 /* This function must be used before starting iteration. */ 137 static bool 138 _dif_sgl_is_valid(struct _dif_sgl *s, uint32_t bytes) 139 { 140 uint64_t total = 0; 141 int i; 142 143 for (i = 0; i < s->iovcnt; i++) { 144 total += s->iov[i].iov_len; 145 } 146 147 return total >= bytes; 148 } 149 150 static bool 151 _dif_type_is_valid(enum spdk_dif_type dif_type, uint32_t dif_flags) 152 { 153 switch (dif_type) { 154 case SPDK_DIF_TYPE1: 155 case SPDK_DIF_TYPE2: 156 case SPDK_DIF_DISABLE: 157 break; 158 case SPDK_DIF_TYPE3: 159 if (dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) { 160 SPDK_ERRLOG("Reference Tag should not be checked for Type 3\n"); 161 return false; 162 } 163 break; 164 default: 165 SPDK_ERRLOG("Unknown DIF Type: %d\n", dif_type); 166 return false; 167 } 168 169 return true; 170 } 171 172 static bool 173 _dif_is_disabled(enum spdk_dif_type dif_type) 174 { 175 if (dif_type == SPDK_DIF_DISABLE) { 176 return true; 177 } else { 178 return false; 179 } 180 } 181 182 183 static uint32_t 184 _get_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc, bool md_interleave) 185 { 186 if (!dif_loc) { 187 /* For metadata formats with more than 8 bytes, if the DIF is 188 * contained in the last 8 bytes of metadata, then the CRC 189 * covers all metadata up to but excluding these last 8 bytes. 190 */ 191 if (md_interleave) { 192 return block_size - sizeof(struct spdk_dif); 193 } else { 194 return md_size - sizeof(struct spdk_dif); 195 } 196 } else { 197 /* For metadata formats with more than 8 bytes, if the DIF is 198 * contained in the first 8 bytes of metadata, then the CRC 199 * does not cover any metadata. 200 */ 201 if (md_interleave) { 202 return block_size - md_size; 203 } else { 204 return 0; 205 } 206 } 207 } 208 209 int 210 spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size, 211 bool md_interleave, bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags, 212 uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag, 213 uint16_t guard_seed) 214 { 215 if (md_size < sizeof(struct spdk_dif)) { 216 SPDK_ERRLOG("Metadata size is smaller than DIF size.\n"); 217 return -EINVAL; 218 } 219 220 if (md_interleave) { 221 if (block_size < md_size) { 222 SPDK_ERRLOG("Block size is smaller than DIF size.\n"); 223 return -EINVAL; 224 } 225 } else { 226 if (block_size == 0 || (block_size % 512) != 0) { 227 SPDK_ERRLOG("Zero block size is not allowed\n"); 228 return -EINVAL; 229 } 230 } 231 232 if (!_dif_type_is_valid(dif_type, dif_flags)) { 233 SPDK_ERRLOG("DIF type is invalid.\n"); 234 return -EINVAL; 235 } 236 237 ctx->block_size = block_size; 238 ctx->md_size = md_size; 239 ctx->guard_interval = _get_guard_interval(block_size, md_size, dif_loc, md_interleave); 240 ctx->dif_type = dif_type; 241 ctx->dif_flags = dif_flags; 242 ctx->init_ref_tag = init_ref_tag; 243 ctx->apptag_mask = apptag_mask; 244 ctx->app_tag = app_tag; 245 ctx->guard_seed = guard_seed; 246 247 return 0; 248 } 249 250 static void 251 _dif_generate(void *_dif, uint16_t guard, uint32_t offset_blocks, 252 const struct spdk_dif_ctx *ctx) 253 { 254 struct spdk_dif *dif = _dif; 255 uint32_t ref_tag; 256 257 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 258 to_be16(&dif->guard, guard); 259 } 260 261 if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) { 262 to_be16(&dif->app_tag, ctx->app_tag); 263 } 264 265 if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) { 266 /* For type 1 and 2, the reference tag is incremented for each 267 * subsequent logical block. For type 3, the reference tag 268 * remains the same as the initial reference tag. 269 */ 270 if (ctx->dif_type != SPDK_DIF_TYPE3) { 271 ref_tag = ctx->init_ref_tag + offset_blocks; 272 } else { 273 ref_tag = ctx->init_ref_tag; 274 } 275 276 to_be32(&dif->ref_tag, ref_tag); 277 } 278 } 279 280 static void 281 dif_generate(struct _dif_sgl *sgl, uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 282 { 283 uint32_t offset_blocks = 0; 284 void *buf; 285 uint16_t guard = 0; 286 287 while (offset_blocks < num_blocks) { 288 _dif_sgl_get_buf(sgl, &buf, NULL); 289 290 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 291 guard = spdk_crc16_t10dif(ctx->guard_seed, buf, ctx->guard_interval); 292 } 293 294 _dif_generate(buf + ctx->guard_interval, guard, offset_blocks, ctx); 295 296 _dif_sgl_advance(sgl, ctx->block_size); 297 offset_blocks++; 298 } 299 } 300 301 static void 302 _dif_generate_split(struct _dif_sgl *sgl, uint32_t offset_blocks, 303 const struct spdk_dif_ctx *ctx) 304 { 305 uint32_t offset_in_block, offset_in_dif, buf_len; 306 void *buf; 307 uint16_t guard = 0; 308 struct spdk_dif dif = {}; 309 310 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 311 guard = ctx->guard_seed; 312 } 313 offset_in_block = 0; 314 315 while (offset_in_block < ctx->block_size) { 316 _dif_sgl_get_buf(sgl, &buf, &buf_len); 317 318 if (offset_in_block < ctx->guard_interval) { 319 buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block); 320 321 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 322 /* Compute CRC over split logical block data. */ 323 guard = spdk_crc16_t10dif(guard, buf, buf_len); 324 } 325 326 if (offset_in_block + buf_len == ctx->guard_interval) { 327 /* If a whole logical block data is parsed, generate DIF 328 * and save it to the temporary DIF area. 329 */ 330 _dif_generate(&dif, guard, offset_blocks, ctx); 331 } 332 } else if (offset_in_block < ctx->guard_interval + sizeof(struct spdk_dif)) { 333 /* Copy generated DIF to the split DIF field. */ 334 offset_in_dif = offset_in_block - ctx->guard_interval; 335 buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif); 336 337 memcpy(buf, ((uint8_t *)&dif) + offset_in_dif, buf_len); 338 } else { 339 /* Skip metadata field after DIF field. */ 340 buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block); 341 } 342 343 _dif_sgl_advance(sgl, buf_len); 344 offset_in_block += buf_len; 345 } 346 } 347 348 static void 349 dif_generate_split(struct _dif_sgl *sgl, uint32_t num_blocks, 350 const struct spdk_dif_ctx *ctx) 351 { 352 uint32_t offset_blocks; 353 354 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 355 _dif_generate_split(sgl, offset_blocks, ctx); 356 } 357 } 358 359 int 360 spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks, 361 const struct spdk_dif_ctx *ctx) 362 { 363 struct _dif_sgl sgl; 364 365 _dif_sgl_init(&sgl, iovs, iovcnt); 366 367 if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) { 368 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 369 return -EINVAL; 370 } 371 372 if (_dif_is_disabled(ctx->dif_type)) { 373 return 0; 374 } 375 376 if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) { 377 dif_generate(&sgl, num_blocks, ctx); 378 } else { 379 dif_generate_split(&sgl, num_blocks, ctx); 380 } 381 382 return 0; 383 } 384 385 static void 386 _dif_error_set(struct spdk_dif_error *err_blk, uint8_t err_type, 387 uint32_t expected, uint32_t actual, uint32_t err_offset) 388 { 389 if (err_blk) { 390 err_blk->err_type = err_type; 391 err_blk->expected = expected; 392 err_blk->actual = actual; 393 err_blk->err_offset = err_offset; 394 } 395 } 396 397 static int 398 _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks, 399 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 400 { 401 struct spdk_dif *dif = _dif; 402 uint16_t _guard; 403 uint16_t _app_tag; 404 uint32_t ref_tag, _ref_tag; 405 406 switch (ctx->dif_type) { 407 case SPDK_DIF_TYPE1: 408 case SPDK_DIF_TYPE2: 409 /* If Type 1 or 2 is used, then all DIF checks are disabled when 410 * the Application Tag is 0xFFFF. 411 */ 412 if (dif->app_tag == 0xFFFF) { 413 return 0; 414 } 415 break; 416 case SPDK_DIF_TYPE3: 417 /* If Type 3 is used, then all DIF checks are disabled when the 418 * Application Tag is 0xFFFF and the Reference Tag is 0xFFFFFFFF. 419 */ 420 if (dif->app_tag == 0xFFFF && dif->ref_tag == 0xFFFFFFFF) { 421 return 0; 422 } 423 break; 424 default: 425 break; 426 } 427 428 /* For type 1 and 2, the reference tag is incremented for each 429 * subsequent logical block. For type 3, the reference tag 430 * remains the same as the initial reference tag. 431 */ 432 if (ctx->dif_type != SPDK_DIF_TYPE3) { 433 ref_tag = ctx->init_ref_tag + offset_blocks; 434 } else { 435 ref_tag = ctx->init_ref_tag; 436 } 437 438 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 439 /* Compare the DIF Guard field to the CRC computed over the logical 440 * block data. 441 */ 442 _guard = from_be16(&dif->guard); 443 if (_guard != guard) { 444 _dif_error_set(err_blk, SPDK_DIF_GUARD_ERROR, _guard, guard, 445 offset_blocks); 446 SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu32 "," \ 447 " Expected=%x, Actual=%x\n", 448 ref_tag, _guard, guard); 449 return -1; 450 } 451 } 452 453 if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) { 454 /* Compare unmasked bits in the DIF Application Tag field to the 455 * passed Application Tag. 456 */ 457 _app_tag = from_be16(&dif->app_tag); 458 if ((_app_tag & ctx->apptag_mask) != ctx->app_tag) { 459 _dif_error_set(err_blk, SPDK_DIF_APPTAG_ERROR, ctx->app_tag, 460 (_app_tag & ctx->apptag_mask), offset_blocks); 461 SPDK_ERRLOG("Failed to compare App Tag: LBA=%" PRIu32 "," \ 462 " Expected=%x, Actual=%x\n", 463 ref_tag, ctx->app_tag, (_app_tag & ctx->apptag_mask)); 464 return -1; 465 } 466 } 467 468 if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) { 469 switch (ctx->dif_type) { 470 case SPDK_DIF_TYPE1: 471 case SPDK_DIF_TYPE2: 472 /* Compare the DIF Reference Tag field to the passed Reference Tag. 473 * The passed Reference Tag will be the least significant 4 bytes 474 * of the LBA when Type 1 is used, and application specific value 475 * if Type 2 is used, 476 */ 477 _ref_tag = from_be32(&dif->ref_tag); 478 if (_ref_tag != ref_tag) { 479 _dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, ref_tag, 480 _ref_tag, offset_blocks); 481 SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu32 "," \ 482 " Expected=%x, Actual=%x\n", 483 ref_tag, ref_tag, _ref_tag); 484 return -1; 485 } 486 break; 487 case SPDK_DIF_TYPE3: 488 /* For Type 3, computed Reference Tag remains unchanged. 489 * Hence ignore the Reference Tag field. 490 */ 491 break; 492 default: 493 break; 494 } 495 } 496 497 return 0; 498 } 499 500 static int 501 dif_verify(struct _dif_sgl *sgl, uint32_t num_blocks, 502 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 503 { 504 uint32_t offset_blocks = 0; 505 int rc; 506 void *buf; 507 uint16_t guard = 0; 508 509 while (offset_blocks < num_blocks) { 510 _dif_sgl_get_buf(sgl, &buf, NULL); 511 512 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 513 guard = spdk_crc16_t10dif(ctx->guard_seed, buf, ctx->guard_interval); 514 } 515 516 rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 517 if (rc != 0) { 518 return rc; 519 } 520 521 _dif_sgl_advance(sgl, ctx->block_size); 522 offset_blocks++; 523 } 524 525 return 0; 526 } 527 528 static int 529 _dif_verify_split(struct _dif_sgl *sgl, uint32_t offset_blocks, 530 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 531 { 532 uint32_t offset_in_block, offset_in_dif, buf_len; 533 void *buf; 534 uint16_t guard = 0; 535 struct spdk_dif dif = {}; 536 537 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 538 guard = ctx->guard_seed; 539 } 540 offset_in_block = 0; 541 542 while (offset_in_block < ctx->block_size) { 543 _dif_sgl_get_buf(sgl, &buf, &buf_len); 544 545 if (offset_in_block < ctx->guard_interval) { 546 buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block); 547 548 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 549 /* Compute CRC over split logical block data. */ 550 guard = spdk_crc16_t10dif(guard, buf, buf_len); 551 } 552 } else if (offset_in_block < ctx->guard_interval + sizeof(struct spdk_dif)) { 553 /* Copy the split DIF field to the temporary DIF buffer. */ 554 offset_in_dif = offset_in_block - ctx->guard_interval; 555 buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif); 556 557 memcpy((uint8_t *)&dif + offset_in_dif, buf, buf_len); 558 } else { 559 /* Skip metadata field after DIF field. */ 560 buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block); 561 } 562 563 _dif_sgl_advance(sgl, buf_len); 564 offset_in_block += buf_len; 565 } 566 567 return _dif_verify(&dif, guard, offset_blocks, ctx, err_blk); 568 } 569 570 static int 571 dif_verify_split(struct _dif_sgl *sgl, uint32_t num_blocks, 572 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 573 { 574 uint32_t offset_blocks; 575 int rc; 576 577 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 578 rc = _dif_verify_split(sgl, offset_blocks, ctx, err_blk); 579 if (rc != 0) { 580 return rc; 581 } 582 } 583 584 return 0; 585 } 586 587 int 588 spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks, 589 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk) 590 { 591 struct _dif_sgl sgl; 592 593 _dif_sgl_init(&sgl, iovs, iovcnt); 594 595 if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) { 596 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 597 return -EINVAL; 598 } 599 600 if (_dif_is_disabled(ctx->dif_type)) { 601 return 0; 602 } 603 604 if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) { 605 return dif_verify(&sgl, num_blocks, ctx, err_blk); 606 } else { 607 return dif_verify_split(&sgl, num_blocks, ctx, err_blk); 608 } 609 } 610 611 static void 612 dif_generate_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 613 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 614 { 615 uint32_t offset_blocks = 0, data_block_size; 616 void *src, *dst; 617 uint16_t guard; 618 619 data_block_size = ctx->block_size - ctx->md_size; 620 621 while (offset_blocks < num_blocks) { 622 _dif_sgl_get_buf(src_sgl, &src, NULL); 623 _dif_sgl_get_buf(dst_sgl, &dst, NULL); 624 625 guard = 0; 626 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 627 guard = spdk_crc16_t10dif_copy(ctx->guard_seed, dst, src, data_block_size); 628 guard = spdk_crc16_t10dif(guard, dst + data_block_size, 629 ctx->guard_interval - data_block_size); 630 } else { 631 memcpy(dst, src, data_block_size); 632 } 633 634 _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx); 635 636 _dif_sgl_advance(src_sgl, data_block_size); 637 _dif_sgl_advance(dst_sgl, ctx->block_size); 638 offset_blocks++; 639 } 640 } 641 642 static void 643 _dif_generate_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 644 uint32_t offset_blocks, const struct spdk_dif_ctx *ctx) 645 { 646 uint32_t offset_in_block, src_len, data_block_size; 647 uint16_t guard = 0; 648 void *src, *dst; 649 650 _dif_sgl_get_buf(dst_sgl, &dst, NULL); 651 652 data_block_size = ctx->block_size - ctx->md_size; 653 654 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 655 guard = ctx->guard_seed; 656 } 657 offset_in_block = 0; 658 659 while (offset_in_block < data_block_size) { 660 /* Compute CRC over split logical block data and copy 661 * data to bounce buffer. 662 */ 663 _dif_sgl_get_buf(src_sgl, &src, &src_len); 664 src_len = spdk_min(src_len, data_block_size - offset_in_block); 665 666 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 667 guard = spdk_crc16_t10dif_copy(guard, dst + offset_in_block, 668 src, src_len); 669 } else { 670 memcpy(dst + offset_in_block, src, src_len); 671 } 672 673 _dif_sgl_advance(src_sgl, src_len); 674 offset_in_block += src_len; 675 } 676 677 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 678 guard = spdk_crc16_t10dif(guard, dst + data_block_size, 679 ctx->guard_interval - data_block_size); 680 } 681 682 _dif_sgl_advance(dst_sgl, ctx->block_size); 683 684 _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx); 685 } 686 687 static void 688 dif_generate_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 689 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 690 { 691 uint32_t offset_blocks; 692 693 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 694 _dif_generate_copy_split(src_sgl, dst_sgl, offset_blocks, ctx); 695 } 696 } 697 698 int 699 spdk_dif_generate_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, 700 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 701 { 702 struct _dif_sgl src_sgl, dst_sgl; 703 uint32_t data_block_size; 704 705 _dif_sgl_init(&src_sgl, iovs, iovcnt); 706 _dif_sgl_init(&dst_sgl, bounce_iov, 1); 707 708 data_block_size = ctx->block_size - ctx->md_size; 709 710 if (!_dif_sgl_is_valid(&src_sgl, data_block_size * num_blocks) || 711 !_dif_sgl_is_valid(&dst_sgl, ctx->block_size * num_blocks)) { 712 SPDK_ERRLOG("Size of iovec arrays are not valid.\n"); 713 return -EINVAL; 714 } 715 716 if (_dif_is_disabled(ctx->dif_type)) { 717 return 0; 718 } 719 720 if (_dif_sgl_is_bytes_multiple(&src_sgl, data_block_size)) { 721 dif_generate_copy(&src_sgl, &dst_sgl, num_blocks, ctx); 722 } else { 723 dif_generate_copy_split(&src_sgl, &dst_sgl, num_blocks, ctx); 724 } 725 726 return 0; 727 } 728 729 static int 730 dif_verify_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 731 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 732 struct spdk_dif_error *err_blk) 733 { 734 uint32_t offset_blocks = 0, data_block_size; 735 void *src, *dst; 736 int rc; 737 uint16_t guard; 738 739 data_block_size = ctx->block_size - ctx->md_size; 740 741 while (offset_blocks < num_blocks) { 742 _dif_sgl_get_buf(src_sgl, &src, NULL); 743 _dif_sgl_get_buf(dst_sgl, &dst, NULL); 744 745 guard = 0; 746 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 747 guard = spdk_crc16_t10dif_copy(ctx->guard_seed, dst, src, data_block_size); 748 guard = spdk_crc16_t10dif(guard, src + data_block_size, 749 ctx->guard_interval - data_block_size); 750 } else { 751 memcpy(dst, src, data_block_size); 752 } 753 754 rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 755 if (rc != 0) { 756 return rc; 757 } 758 759 _dif_sgl_advance(src_sgl, ctx->block_size); 760 _dif_sgl_advance(dst_sgl, data_block_size); 761 offset_blocks++; 762 } 763 764 return 0; 765 } 766 767 static int 768 _dif_verify_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 769 uint32_t offset_blocks, const struct spdk_dif_ctx *ctx, 770 struct spdk_dif_error *err_blk) 771 { 772 uint32_t offset_in_block, dst_len, data_block_size; 773 uint16_t guard = 0; 774 void *src, *dst; 775 776 _dif_sgl_get_buf(src_sgl, &src, NULL); 777 778 data_block_size = ctx->block_size - ctx->md_size; 779 780 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 781 guard = ctx->guard_seed; 782 } 783 offset_in_block = 0; 784 785 while (offset_in_block < data_block_size) { 786 /* Compute CRC over split logical block data and copy 787 * data to bounce buffer. 788 */ 789 _dif_sgl_get_buf(dst_sgl, &dst, &dst_len); 790 dst_len = spdk_min(dst_len, data_block_size - offset_in_block); 791 792 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 793 guard = spdk_crc16_t10dif_copy(guard, dst, 794 src + offset_in_block, dst_len); 795 } else { 796 memcpy(dst, src + offset_in_block, dst_len); 797 } 798 799 _dif_sgl_advance(dst_sgl, dst_len); 800 offset_in_block += dst_len; 801 } 802 803 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 804 guard = spdk_crc16_t10dif(guard, src + data_block_size, 805 ctx->guard_interval - data_block_size); 806 } 807 808 _dif_sgl_advance(src_sgl, ctx->block_size); 809 810 return _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 811 } 812 813 static int 814 dif_verify_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl, 815 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 816 struct spdk_dif_error *err_blk) 817 { 818 uint32_t offset_blocks; 819 int rc; 820 821 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 822 rc = _dif_verify_copy_split(src_sgl, dst_sgl, offset_blocks, ctx, err_blk); 823 if (rc != 0) { 824 return rc; 825 } 826 } 827 828 return 0; 829 } 830 831 int 832 spdk_dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, 833 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 834 struct spdk_dif_error *err_blk) 835 { 836 struct _dif_sgl src_sgl, dst_sgl; 837 uint32_t data_block_size; 838 839 _dif_sgl_init(&src_sgl, bounce_iov, 1); 840 _dif_sgl_init(&dst_sgl, iovs, iovcnt); 841 842 data_block_size = ctx->block_size - ctx->md_size; 843 844 if (!_dif_sgl_is_valid(&dst_sgl, data_block_size * num_blocks) || 845 !_dif_sgl_is_valid(&src_sgl, ctx->block_size * num_blocks)) { 846 SPDK_ERRLOG("Size of iovec arrays are not valid\n"); 847 return -EINVAL; 848 } 849 850 if (_dif_is_disabled(ctx->dif_type)) { 851 return 0; 852 } 853 854 if (_dif_sgl_is_bytes_multiple(&dst_sgl, data_block_size)) { 855 return dif_verify_copy(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk); 856 } else { 857 return dif_verify_copy_split(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk); 858 } 859 } 860 861 static void 862 _bit_flip(uint8_t *buf, uint32_t flip_bit) 863 { 864 uint8_t byte; 865 866 byte = *buf; 867 byte ^= 1 << flip_bit; 868 *buf = byte; 869 } 870 871 static int 872 _dif_inject_error(struct _dif_sgl *sgl, 873 uint32_t block_size, uint32_t num_blocks, 874 uint32_t inject_offset_blocks, 875 uint32_t inject_offset_bytes, 876 uint32_t inject_offset_bits) 877 { 878 uint32_t offset_in_block, buf_len; 879 void *buf; 880 881 _dif_sgl_fast_forward(sgl, block_size * inject_offset_blocks); 882 883 offset_in_block = 0; 884 885 while (offset_in_block < block_size) { 886 _dif_sgl_get_buf(sgl, &buf, &buf_len); 887 buf_len = spdk_min(buf_len, block_size - offset_in_block); 888 889 if (inject_offset_bytes >= offset_in_block && 890 inject_offset_bytes < offset_in_block + buf_len) { 891 buf += inject_offset_bytes - offset_in_block; 892 _bit_flip(buf, inject_offset_bits); 893 return 0; 894 } 895 896 _dif_sgl_advance(sgl, buf_len); 897 offset_in_block += buf_len; 898 } 899 900 return -1; 901 } 902 903 static int 904 dif_inject_error(struct _dif_sgl *sgl, uint32_t block_size, uint32_t num_blocks, 905 uint32_t start_inject_bytes, uint32_t inject_range_bytes, 906 uint32_t *inject_offset) 907 { 908 uint32_t inject_offset_blocks, inject_offset_bytes, inject_offset_bits; 909 uint32_t offset_blocks; 910 int rc; 911 912 srand(time(0)); 913 914 inject_offset_blocks = rand() % num_blocks; 915 inject_offset_bytes = start_inject_bytes + (rand() % inject_range_bytes); 916 inject_offset_bits = rand() % 8; 917 918 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 919 if (offset_blocks == inject_offset_blocks) { 920 rc = _dif_inject_error(sgl, block_size, num_blocks, 921 inject_offset_blocks, 922 inject_offset_bytes, 923 inject_offset_bits); 924 if (rc == 0) { 925 *inject_offset = inject_offset_blocks; 926 } 927 return rc; 928 } 929 } 930 931 return -1; 932 } 933 934 #define _member_size(type, member) sizeof(((type *)0)->member) 935 936 int 937 spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks, 938 const struct spdk_dif_ctx *ctx, uint32_t inject_flags, 939 uint32_t *inject_offset) 940 { 941 struct _dif_sgl sgl; 942 int rc; 943 944 _dif_sgl_init(&sgl, iovs, iovcnt); 945 946 if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) { 947 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 948 return -EINVAL; 949 } 950 951 if (inject_flags & SPDK_DIF_REFTAG_ERROR) { 952 rc = dif_inject_error(&sgl, ctx->block_size, num_blocks, 953 ctx->guard_interval + offsetof(struct spdk_dif, ref_tag), 954 _member_size(struct spdk_dif, ref_tag), 955 inject_offset); 956 if (rc != 0) { 957 SPDK_ERRLOG("Failed to inject error to Reference Tag.\n"); 958 return rc; 959 } 960 } 961 962 if (inject_flags & SPDK_DIF_APPTAG_ERROR) { 963 rc = dif_inject_error(&sgl, ctx->block_size, num_blocks, 964 ctx->guard_interval + offsetof(struct spdk_dif, app_tag), 965 _member_size(struct spdk_dif, app_tag), 966 inject_offset); 967 if (rc != 0) { 968 SPDK_ERRLOG("Failed to inject error to Application Tag.\n"); 969 return rc; 970 } 971 } 972 if (inject_flags & SPDK_DIF_GUARD_ERROR) { 973 rc = dif_inject_error(&sgl, ctx->block_size, num_blocks, 974 ctx->guard_interval, 975 _member_size(struct spdk_dif, guard), 976 inject_offset); 977 if (rc != 0) { 978 SPDK_ERRLOG("Failed to inject error to Guard.\n"); 979 return rc; 980 } 981 } 982 983 if (inject_flags & SPDK_DIF_DATA_ERROR) { 984 /* If the DIF information is contained within the last 8 bytes of 985 * metadata, then the CRC covers all metadata bytes up to but excluding 986 * the last 8 bytes. But error injection does not cover these metadata 987 * because classification is not determined yet. 988 * 989 * Note: Error injection to data block is expected to be detected as 990 * guard error. 991 */ 992 rc = dif_inject_error(&sgl, ctx->block_size, num_blocks, 993 0, 994 ctx->block_size - ctx->md_size, 995 inject_offset); 996 if (rc != 0) { 997 SPDK_ERRLOG("Failed to inject error to data block.\n"); 998 return rc; 999 } 1000 } 1001 1002 return 0; 1003 } 1004 1005 static void 1006 dix_generate(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1007 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 1008 { 1009 uint32_t offset_blocks = 0; 1010 uint16_t guard; 1011 void *data_buf, *md_buf; 1012 1013 while (offset_blocks < num_blocks) { 1014 _dif_sgl_get_buf(data_sgl, &data_buf, NULL); 1015 _dif_sgl_get_buf(md_sgl, &md_buf, NULL); 1016 1017 guard = 0; 1018 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1019 guard = spdk_crc16_t10dif(ctx->guard_seed, data_buf, ctx->block_size); 1020 guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval); 1021 } 1022 1023 _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx); 1024 1025 _dif_sgl_advance(data_sgl, ctx->block_size); 1026 _dif_sgl_advance(md_sgl, ctx->md_size); 1027 offset_blocks++; 1028 } 1029 } 1030 1031 static void 1032 _dix_generate_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1033 uint32_t offset_blocks, const struct spdk_dif_ctx *ctx) 1034 { 1035 uint32_t offset_in_block, data_buf_len; 1036 uint16_t guard = 0; 1037 void *data_buf, *md_buf; 1038 1039 _dif_sgl_get_buf(md_sgl, &md_buf, NULL); 1040 1041 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1042 guard = ctx->guard_seed; 1043 } 1044 offset_in_block = 0; 1045 1046 while (offset_in_block < ctx->block_size) { 1047 _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len); 1048 data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block); 1049 1050 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1051 guard = spdk_crc16_t10dif(guard, data_buf, data_buf_len); 1052 } 1053 1054 _dif_sgl_advance(data_sgl, data_buf_len); 1055 offset_in_block += data_buf_len; 1056 } 1057 1058 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1059 guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval); 1060 } 1061 1062 _dif_sgl_advance(md_sgl, ctx->md_size); 1063 1064 _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx); 1065 } 1066 1067 static void 1068 dix_generate_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1069 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 1070 { 1071 uint32_t offset_blocks; 1072 1073 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 1074 _dix_generate_split(data_sgl, md_sgl, offset_blocks, ctx); 1075 } 1076 } 1077 1078 int 1079 spdk_dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov, 1080 uint32_t num_blocks, const struct spdk_dif_ctx *ctx) 1081 { 1082 struct _dif_sgl data_sgl, md_sgl; 1083 1084 _dif_sgl_init(&data_sgl, iovs, iovcnt); 1085 _dif_sgl_init(&md_sgl, md_iov, 1); 1086 1087 if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) || 1088 !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) { 1089 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 1090 return -EINVAL; 1091 } 1092 1093 if (_dif_is_disabled(ctx->dif_type)) { 1094 return 0; 1095 } 1096 1097 if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) { 1098 dix_generate(&data_sgl, &md_sgl, num_blocks, ctx); 1099 } else { 1100 dix_generate_split(&data_sgl, &md_sgl, num_blocks, ctx); 1101 } 1102 1103 return 0; 1104 } 1105 1106 static int 1107 dix_verify(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1108 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1109 struct spdk_dif_error *err_blk) 1110 { 1111 uint32_t offset_blocks = 0; 1112 uint16_t guard; 1113 void *data_buf, *md_buf; 1114 int rc; 1115 1116 while (offset_blocks < num_blocks) { 1117 _dif_sgl_get_buf(data_sgl, &data_buf, NULL); 1118 _dif_sgl_get_buf(md_sgl, &md_buf, NULL); 1119 1120 guard = 0; 1121 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1122 guard = spdk_crc16_t10dif(ctx->guard_seed, data_buf, ctx->block_size); 1123 guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval); 1124 } 1125 1126 rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 1127 if (rc != 0) { 1128 return rc; 1129 } 1130 1131 _dif_sgl_advance(data_sgl, ctx->block_size); 1132 _dif_sgl_advance(md_sgl, ctx->md_size); 1133 offset_blocks++; 1134 } 1135 1136 return 0; 1137 } 1138 1139 static int 1140 _dix_verify_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1141 uint32_t offset_blocks, const struct spdk_dif_ctx *ctx, 1142 struct spdk_dif_error *err_blk) 1143 { 1144 uint32_t offset_in_block, data_buf_len; 1145 uint16_t guard = 0; 1146 void *data_buf, *md_buf; 1147 1148 _dif_sgl_get_buf(md_sgl, &md_buf, NULL); 1149 1150 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1151 guard = ctx->guard_seed; 1152 } 1153 offset_in_block = 0; 1154 1155 while (offset_in_block < ctx->block_size) { 1156 _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len); 1157 data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block); 1158 1159 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1160 guard = spdk_crc16_t10dif(guard, data_buf, data_buf_len); 1161 } 1162 1163 _dif_sgl_advance(data_sgl, data_buf_len); 1164 offset_in_block += data_buf_len; 1165 } 1166 1167 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1168 guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval); 1169 } 1170 1171 _dif_sgl_advance(md_sgl, ctx->md_size); 1172 1173 return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); 1174 } 1175 1176 static int 1177 dix_verify_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl, 1178 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1179 struct spdk_dif_error *err_blk) 1180 { 1181 uint32_t offset_blocks; 1182 int rc; 1183 1184 for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { 1185 rc = _dix_verify_split(data_sgl, md_sgl, offset_blocks, ctx, err_blk); 1186 if (rc != 0) { 1187 return rc; 1188 } 1189 } 1190 1191 return 0; 1192 } 1193 1194 int 1195 spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov, 1196 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1197 struct spdk_dif_error *err_blk) 1198 { 1199 struct _dif_sgl data_sgl, md_sgl; 1200 1201 _dif_sgl_init(&data_sgl, iovs, iovcnt); 1202 _dif_sgl_init(&md_sgl, md_iov, 1); 1203 1204 if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) || 1205 !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) { 1206 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 1207 return -EINVAL; 1208 } 1209 1210 if (_dif_is_disabled(ctx->dif_type)) { 1211 return 0; 1212 } 1213 1214 if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) { 1215 return dix_verify(&data_sgl, &md_sgl, num_blocks, ctx, err_blk); 1216 } else { 1217 return dix_verify_split(&data_sgl, &md_sgl, num_blocks, ctx, err_blk); 1218 } 1219 } 1220 1221 int 1222 spdk_dix_inject_error(struct iovec *iovs, int iovcnt, struct iovec *md_iov, 1223 uint32_t num_blocks, const struct spdk_dif_ctx *ctx, 1224 uint32_t inject_flags, uint32_t *inject_offset) 1225 { 1226 struct _dif_sgl data_sgl, md_sgl; 1227 int rc; 1228 1229 _dif_sgl_init(&data_sgl, iovs, iovcnt); 1230 _dif_sgl_init(&md_sgl, md_iov, 1); 1231 1232 if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) || 1233 !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) { 1234 SPDK_ERRLOG("Size of iovec array is not valid.\n"); 1235 return -EINVAL; 1236 } 1237 1238 if (inject_flags & SPDK_DIF_REFTAG_ERROR) { 1239 rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks, 1240 ctx->guard_interval + offsetof(struct spdk_dif, ref_tag), 1241 _member_size(struct spdk_dif, ref_tag), 1242 inject_offset); 1243 if (rc != 0) { 1244 SPDK_ERRLOG("Failed to inject error to Reference Tag.\n"); 1245 return rc; 1246 } 1247 } 1248 1249 if (inject_flags & SPDK_DIF_APPTAG_ERROR) { 1250 rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks, 1251 ctx->guard_interval + offsetof(struct spdk_dif, app_tag), 1252 _member_size(struct spdk_dif, app_tag), 1253 inject_offset); 1254 if (rc != 0) { 1255 SPDK_ERRLOG("Failed to inject error to Application Tag.\n"); 1256 return rc; 1257 } 1258 } 1259 1260 if (inject_flags & SPDK_DIF_GUARD_ERROR) { 1261 rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks, 1262 ctx->guard_interval, 1263 _member_size(struct spdk_dif, guard), 1264 inject_offset); 1265 if (rc != 0) { 1266 SPDK_ERRLOG("Failed to inject error to Guard.\n"); 1267 return rc; 1268 } 1269 } 1270 1271 if (inject_flags & SPDK_DIF_DATA_ERROR) { 1272 /* Note: Error injection to data block is expected to be detected 1273 * as guard error. 1274 */ 1275 rc = dif_inject_error(&data_sgl, ctx->block_size, num_blocks, 1276 0, 1277 ctx->block_size, 1278 inject_offset); 1279 if (rc != 0) { 1280 SPDK_ERRLOG("Failed to inject error to Guard.\n"); 1281 return rc; 1282 } 1283 } 1284 1285 return 0; 1286 } 1287 1288 static int 1289 dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt, 1290 uint8_t *buf, uint32_t buf_len, 1291 uint32_t data_offset, uint32_t data_len, 1292 uint32_t *_mapped_len, 1293 const struct spdk_dif_ctx *ctx) 1294 { 1295 uint32_t data_block_size, head_unalign; 1296 uint32_t num_blocks, offset_blocks; 1297 struct _dif_sgl sgl; 1298 1299 data_block_size = ctx->block_size - ctx->md_size; 1300 1301 num_blocks = data_len / data_block_size; 1302 1303 if (buf_len < num_blocks * ctx->block_size) { 1304 SPDK_ERRLOG("Buffer overflow will occur. Buffer size is %" PRIu32 " but" 1305 " necessary size is %" PRIu32 "\n", 1306 buf_len, num_blocks * ctx->block_size); 1307 return -ERANGE; 1308 } 1309 1310 offset_blocks = data_offset / data_block_size; 1311 head_unalign = data_offset % data_block_size; 1312 1313 _dif_sgl_init(&sgl, iovs, iovcnt); 1314 buf += offset_blocks * ctx->block_size; 1315 1316 while (offset_blocks < num_blocks) { 1317 buf += head_unalign; 1318 1319 if (!_dif_sgl_append(&sgl, buf, data_block_size - head_unalign)) { 1320 break; 1321 } 1322 1323 buf += ctx->block_size - head_unalign; 1324 offset_blocks++; 1325 1326 head_unalign = 0; 1327 } 1328 1329 if (_mapped_len != NULL) { 1330 *_mapped_len = sgl.total_size; 1331 } 1332 1333 return iovcnt - sgl.iovcnt; 1334 } 1335 1336 static int 1337 dif_set_md_interleave_iovs_split(struct iovec *iovs, int iovcnt, 1338 struct iovec *buf_iovs, int buf_iovcnt, 1339 uint32_t data_offset, uint32_t data_len, 1340 uint32_t *_mapped_len, 1341 const struct spdk_dif_ctx *ctx) 1342 { 1343 uint32_t data_block_size, head_unalign; 1344 uint32_t num_blocks, offset_blocks; 1345 struct _dif_sgl dif_sgl; 1346 struct _dif_sgl buf_sgl; 1347 uint8_t *buf; 1348 uint32_t buf_len, remaining; 1349 1350 data_block_size = ctx->block_size - ctx->md_size; 1351 num_blocks = data_len / data_block_size; 1352 1353 _dif_sgl_init(&dif_sgl, iovs, iovcnt); 1354 _dif_sgl_init(&buf_sgl, buf_iovs, buf_iovcnt); 1355 1356 if (!_dif_sgl_is_valid(&buf_sgl, num_blocks * ctx->block_size)) { 1357 SPDK_ERRLOG("Buffer overflow will occur.\n"); 1358 return -ERANGE; 1359 } 1360 1361 offset_blocks = data_offset / data_block_size; 1362 head_unalign = data_offset % data_block_size; 1363 1364 _dif_sgl_fast_forward(&buf_sgl, offset_blocks * ctx->block_size); 1365 1366 while (offset_blocks < num_blocks) { 1367 _dif_sgl_fast_forward(&buf_sgl, head_unalign); 1368 1369 remaining = data_block_size - head_unalign; 1370 while (remaining != 0) { 1371 _dif_sgl_get_buf(&buf_sgl, (void *)&buf, &buf_len); 1372 buf_len = spdk_min(buf_len, remaining); 1373 1374 if (!_dif_sgl_append(&dif_sgl, buf, buf_len)) { 1375 goto end; 1376 } 1377 _dif_sgl_advance(&buf_sgl, buf_len); 1378 remaining -= buf_len; 1379 } 1380 _dif_sgl_fast_forward(&buf_sgl, ctx->md_size); 1381 offset_blocks++; 1382 1383 head_unalign = 0; 1384 } 1385 1386 end: 1387 if (_mapped_len != NULL) { 1388 *_mapped_len = dif_sgl.total_size; 1389 } 1390 1391 return iovcnt - dif_sgl.iovcnt; 1392 } 1393 1394 int 1395 spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt, 1396 struct iovec *buf_iovs, int buf_iovcnt, 1397 uint32_t data_offset, uint32_t data_len, 1398 uint32_t *_mapped_len, 1399 const struct spdk_dif_ctx *ctx) 1400 { 1401 uint32_t data_block_size; 1402 1403 if (iovs == NULL || iovcnt == 0 || buf_iovs == NULL || buf_iovcnt == 0) { 1404 return -EINVAL; 1405 } 1406 1407 data_block_size = ctx->block_size - ctx->md_size; 1408 1409 if ((data_len % data_block_size) != 0) { 1410 SPDK_ERRLOG("Data length must be a multiple of data block size\n"); 1411 return -EINVAL; 1412 } 1413 1414 if (data_offset >= data_len) { 1415 SPDK_ERRLOG("Data offset must be smaller than data length\n"); 1416 return -ERANGE; 1417 } 1418 1419 if (buf_iovcnt == 1) { 1420 return dif_set_md_interleave_iovs(iovs, iovcnt, 1421 buf_iovs[0].iov_base, buf_iovs[0].iov_len, 1422 data_offset, data_len, _mapped_len, ctx); 1423 } else { 1424 return dif_set_md_interleave_iovs_split(iovs, iovcnt, buf_iovs, buf_iovcnt, 1425 data_offset, data_len, _mapped_len, ctx); 1426 } 1427 } 1428 1429 static int 1430 dif_generate_stream(uint8_t *buf, uint32_t buf_len, 1431 uint32_t offset, uint32_t read_len, 1432 const struct spdk_dif_ctx *ctx) 1433 { 1434 uint32_t data_block_size, offset_blocks, num_blocks, i; 1435 uint16_t guard = 0; 1436 1437 data_block_size = ctx->block_size - ctx->md_size; 1438 1439 offset_blocks = offset / data_block_size; 1440 read_len += offset % data_block_size; 1441 1442 offset = offset_blocks * ctx->block_size; 1443 num_blocks = read_len / data_block_size; 1444 1445 if (offset + num_blocks * ctx->block_size > buf_len) { 1446 return -ERANGE; 1447 } 1448 1449 buf += offset; 1450 1451 for (i = 0; i < num_blocks; i++) { 1452 if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { 1453 guard = spdk_crc16_t10dif(ctx->guard_seed, buf, ctx->guard_interval); 1454 } 1455 1456 _dif_generate(buf + ctx->guard_interval, guard, offset_blocks + i, ctx); 1457 1458 buf += ctx->block_size; 1459 } 1460 1461 return 0; 1462 } 1463 1464 static int 1465 dif_generate_stream_split(struct iovec *iovs, int iovcnt, 1466 uint32_t offset, uint32_t read_len, 1467 const struct spdk_dif_ctx *ctx) 1468 { 1469 uint32_t data_block_size, offset_blocks, num_blocks, i; 1470 struct _dif_sgl sgl; 1471 1472 data_block_size = ctx->block_size - ctx->md_size; 1473 1474 offset_blocks = offset / data_block_size; 1475 read_len += offset % data_block_size; 1476 1477 offset = offset_blocks * ctx->block_size; 1478 num_blocks = read_len / data_block_size; 1479 1480 _dif_sgl_init(&sgl, iovs, iovcnt); 1481 1482 if (!_dif_sgl_is_valid(&sgl, offset + num_blocks * ctx->block_size)) { 1483 return -ERANGE; 1484 } 1485 1486 _dif_sgl_fast_forward(&sgl, offset); 1487 1488 for (i = 0; i < num_blocks; i++) { 1489 _dif_generate_split(&sgl, offset_blocks + i, ctx); 1490 } 1491 1492 return 0; 1493 } 1494 1495 int 1496 spdk_dif_generate_stream(struct iovec *iovs, int iovcnt, 1497 uint32_t offset, uint32_t read_len, 1498 const struct spdk_dif_ctx *ctx) 1499 { 1500 if (iovs == NULL || iovcnt == 0) { 1501 return -EINVAL; 1502 } 1503 1504 if (iovcnt == 1) { 1505 return dif_generate_stream(iovs[0].iov_base, iovs[0].iov_len, 1506 offset, read_len, ctx); 1507 } else { 1508 return dif_generate_stream_split(iovs, iovcnt, offset, read_len, ctx); 1509 } 1510 } 1511