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