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