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