Commit 65624bd5 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Jim Harris
Browse files

dix: Generate DIF for separate metadata payload



This patch adds APIs to generate and verify DIF for SGL
payload with separate metadata as byte alignment and granularity.

Change-Id: I4e553c9b6f8c96e576a69115002963d32379d439
Signed-off-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/434150


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent 045e77c2
Loading
Loading
Loading
Loading
+32 −2
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ struct spdk_dif_ctx {
	/** Metadata size */
	uint32_t		md_size;

	/** Interval for guard computation */
	/** Interval for guard computation for DIF */
	uint32_t		guard_interval;

	/** DIF type */
@@ -108,6 +108,8 @@ struct spdk_dif_error {
 * \param ctx DIF context.
 * \param block_size Block size in a block.
 * \param md_size Metadata size in a block.
 * \param md_interleave If true, metadata is interleaved with block data.
 * If false, metadata is separated with block data.
 * \param dif_loc DIF location. If true, DIF is set in the last 8 bytes of metadata.
 * If false, DIF is in the first 8 bytes of metadata.
 * \param dif_type Type of DIF.
@@ -120,7 +122,7 @@ struct spdk_dif_error {
 * \return 0 on success and negated errno otherwise.
 */
int spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size,
		      bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
		      bool md_interleave, bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
		      uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag);

/**
@@ -196,4 +198,32 @@ int spdk_dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_io
int spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
			  const struct spdk_dif_ctx *ctx, uint32_t inject_flags,
			  uint32_t *inject_offset);

/**
 * Generate DIF for separate metadata payload.
 *
 * \param iovs iovec array describing the LBA payload.
 * \params iovcnt Number of elements in iovs.
 * \param md_iov A contiguous buffer for metadata.
 * \param num_blocks Number of blocks of the separate metadata payload.
 * \param ctx DIF context.
 *
 * \return 0 on success and negated errno otherwise.
 */
int spdk_dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
		      uint32_t num_blocks, const struct spdk_dif_ctx *ctx);

/**
 * Verify DIF for separate metadata payload.
 *
 * \param iovs iovec array describing the LBA payload.
 * \params iovcnt Number of elements in iovs.
 * \param md_iov A contiguous buffer for metadata.
 * \param num_blocks Number of blocks of the separate metadata payload.
 * \param ctx DIF context.
 *
 * \return 0 on success and negated errno otherwise.
 */
int spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
		    uint32_t num_blocks, const struct spdk_dif_ctx *ctx);
#endif /* SPDK_DIF_H */
+250 −8
Original line number Diff line number Diff line
@@ -159,27 +159,36 @@ _dif_is_disabled(enum spdk_dif_type dif_type)
	}
}


static uint32_t
_get_dif_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc)
_get_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc, bool md_interleave)
{
	if (dif_loc) {
		/* For metadata formats with more than 8 bytes, if the DIF is
		 * contained in the last 8 bytes of metadata, then the CRC
		 * covers all metadata up to but excluding these last 8 bytes.
		 */
		if (md_interleave) {
			return block_size - sizeof(struct spdk_dif);
		} else {
			return md_size - sizeof(struct spdk_dif);
		}
	} else {
		/* For metadata formats with more than 8 bytes, if the DIF is
		 * contained in the first 8 bytes of metadata, then the CRC
		 * does not cover any metadata.
		 */
		if (md_interleave) {
			return block_size - md_size;
		} else {
			return 0;
		}
	}
}

int
spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size,
		  bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
		  bool md_interleave, bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
		  uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
{
	if (md_size < sizeof(struct spdk_dif)) {
@@ -187,10 +196,17 @@ spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_siz
		return -EINVAL;
	}

	if (md_interleave) {
		if (block_size < md_size) {
			SPDK_ERRLOG("Block size is smaller than DIF size.\n");
			return -EINVAL;
		}
	} else {
		if (block_size == 0 || (block_size % 512) != 0) {
			SPDK_ERRLOG("Zero block size is not allowed\n");
			return -EINVAL;
		}
	}

	if (!_dif_type_is_valid(dif_type, dif_flags)) {
		SPDK_ERRLOG("DIF type is invalid.\n");
@@ -199,7 +215,7 @@ spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_siz

	ctx->block_size = block_size;
	ctx->md_size = md_size;
	ctx->guard_interval = _get_dif_guard_interval(block_size, md_size, dif_loc);
	ctx->guard_interval = _get_guard_interval(block_size, md_size, dif_loc, md_interleave);
	ctx->dif_type = dif_type;
	ctx->dif_flags = dif_flags;
	ctx->init_ref_tag = init_ref_tag;
@@ -987,3 +1003,229 @@ spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,

	return 0;
}

static void
dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
	     uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
{
	struct _iov_iter data_iter, md_iter;
	uint32_t offset_blocks;
	uint16_t guard;
	void *data_buf, *md_buf;

	offset_blocks = 0;
	_iov_iter_init(&data_iter, iovs, iovcnt);
	_iov_iter_init(&md_iter, md_iov, 1);

	while (offset_blocks < num_blocks &&
	       _iov_iter_cont(&data_iter) && _iov_iter_cont(&md_iter)) {

		_iov_iter_get_buf(&data_iter, &data_buf, NULL);
		_iov_iter_get_buf(&md_iter, &md_buf, NULL);

		guard = 0;
		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
			guard = spdk_crc16_t10dif(0, data_buf, ctx->block_size);
			guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval);
		}

		_dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);

		_iov_iter_advance(&data_iter, ctx->block_size);
		_iov_iter_advance(&md_iter, ctx->md_size);
		offset_blocks++;
	}
}

static void
_dix_generate_split(struct _iov_iter *data_iter, struct _iov_iter *md_iter,
		    uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
{
	uint32_t offset_in_block, data_buf_len;
	uint16_t guard;
	void *data_buf, *md_buf;

	_iov_iter_get_buf(md_iter, &md_buf, NULL);

	guard = 0;
	if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
		guard = spdk_crc16_t10dif(0, md_buf, ctx->guard_interval);
	}

	offset_in_block = 0;

	while (offset_in_block < ctx->block_size && _iov_iter_cont(data_iter)) {
		_iov_iter_get_buf(data_iter, &data_buf, &data_buf_len);
		data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);

		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
			guard = spdk_crc16_t10dif(guard, data_buf, data_buf_len);
		}

		_iov_iter_advance(data_iter, data_buf_len);
		offset_in_block += data_buf_len;
	}

	_iov_iter_advance(md_iter, ctx->md_size);

	_dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
}

static void
dix_generate_split(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
		   uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
{
	struct _iov_iter data_iter, md_iter;
	uint32_t offset_blocks;

	offset_blocks = 0;
	_iov_iter_init(&data_iter, iovs, iovcnt);
	_iov_iter_init(&md_iter, md_iov, 1);

	while (offset_blocks < num_blocks &&
	       _iov_iter_cont(&data_iter) && _iov_iter_cont(&md_iter)) {
		_dix_generate_split(&data_iter, &md_iter, offset_blocks, ctx);
		offset_blocks++;
	}
}

int
spdk_dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
		  uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
{
	if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks) ||
	    !_are_iovs_valid(md_iov, 1, ctx->md_size * num_blocks)) {
		SPDK_ERRLOG("Size of iovec array is not valid.\n");
		return -EINVAL;
	}

	if (_dif_is_disabled(ctx->dif_type)) {
		return 0;
	}

	if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
		dix_generate(iovs, iovcnt, md_iov, num_blocks, ctx);
	} else {
		dix_generate_split(iovs, iovcnt, md_iov, num_blocks, ctx);
	}

	return 0;
}

static int
dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
	   uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
{
	struct _iov_iter data_iter, md_iter;
	uint32_t offset_blocks;
	uint16_t guard;
	void *data_buf, *md_buf;
	int rc;

	offset_blocks = 0;
	_iov_iter_init(&data_iter, iovs, iovcnt);
	_iov_iter_init(&md_iter, md_iov, 1);

	while (offset_blocks < num_blocks &&
	       _iov_iter_cont(&data_iter) && _iov_iter_cont(&md_iter)) {

		_iov_iter_get_buf(&data_iter, &data_buf, NULL);
		_iov_iter_get_buf(&md_iter, &md_buf, NULL);

		guard = 0;
		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
			guard = spdk_crc16_t10dif(0, data_buf, ctx->block_size);
			guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval);
		}

		rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, NULL);
		if (rc != 0) {
			return rc;
		}

		_iov_iter_advance(&data_iter, ctx->block_size);
		_iov_iter_advance(&md_iter, ctx->md_size);
		offset_blocks++;
	}

	return 0;
}

static int
_dix_verify_split(struct _iov_iter *data_iter, struct _iov_iter *md_iter,
		  uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
{
	uint32_t offset_in_block, data_buf_len;
	uint16_t guard;
	void *data_buf, *md_buf;

	_iov_iter_get_buf(md_iter, &md_buf, NULL);

	guard = 0;
	if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
		guard = spdk_crc16_t10dif(0, md_buf, ctx->guard_interval);
	}

	offset_in_block = 0;

	while (offset_in_block < ctx->block_size && _iov_iter_cont(data_iter)) {
		_iov_iter_get_buf(data_iter, &data_buf, &data_buf_len);
		data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);

		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
			guard = spdk_crc16_t10dif(guard, data_buf, data_buf_len);
		}

		_iov_iter_advance(data_iter, data_buf_len);
		offset_in_block += data_buf_len;
	}

	_iov_iter_advance(md_iter, ctx->md_size);

	return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, NULL);
}

static int
dix_verify_split(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
		 uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
{
	struct _iov_iter data_iter, md_iter;
	uint32_t offset_blocks;
	int rc;

	offset_blocks = 0;
	_iov_iter_init(&data_iter, iovs, iovcnt);
	_iov_iter_init(&md_iter, md_iov, 1);

	while (offset_blocks < num_blocks &&
	       _iov_iter_cont(&data_iter) && _iov_iter_cont(&md_iter)) {
		rc = _dix_verify_split(&data_iter, &md_iter, offset_blocks, ctx);
		if (rc != 0) {
			return rc;
		}
		offset_blocks++;
	}

	return 0;
}

int
spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
		uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
{
	if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks) ||
	    !_are_iovs_valid(md_iov, 1, ctx->md_size * num_blocks)) {
		SPDK_ERRLOG("Size of iovec array is not valid.\n");
		return -EINVAL;
	}

	if (_dif_is_disabled(ctx->dif_type)) {
		return 0;
	}

	if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
		return dix_verify(iovs, iovcnt, md_iov, num_blocks, ctx);
	} else {
		return dix_verify_split(iovs, iovcnt, md_iov, num_blocks, ctx);
	}
}
+187 −7
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ _dif_generate_and_verify(struct iovec *iov,
	rc = ut_data_pattern_generate(iov, 1, block_size, md_size, 1);
	CU_ASSERT(rc == 0);

	guard_interval = _get_dif_guard_interval(block_size, md_size, dif_loc);
	guard_interval = _get_guard_interval(block_size, md_size, dif_loc, true);

	ctx.dif_type = dif_type;
	ctx.dif_flags = dif_flags;
@@ -270,7 +270,7 @@ dif_sec_512_md_0_error_test(void)
	int rc;

	/* Metadata size is 0. */
	rc = spdk_dif_ctx_init(&ctx, 512, 0, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
	rc = spdk_dif_ctx_init(&ctx, 512, 0, true, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
	CU_ASSERT(rc != 0);
}

@@ -286,7 +286,7 @@ dif_generate_and_verify(struct iovec *iovs, int iovcnt,
	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks);
	CU_ASSERT(rc == 0);

	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, dif_loc, dif_type, dif_flags,
	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, dif_type, dif_flags,
			       init_ref_tag, apptag_mask, app_tag);
	CU_ASSERT(rc == 0);

@@ -582,7 +582,7 @@ _dif_inject_error_and_verify(struct iovec *iovs, int iovcnt,
	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks);
	CU_ASSERT(rc == 0);

	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, dif_loc,
	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc,
			       SPDK_DIF_TYPE1, dif_flags, 88, 0xFFFF, 0x88);
	CU_ASSERT(rc == 0);

@@ -740,7 +740,7 @@ dif_copy_gen_and_verify(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov
	rc = ut_data_pattern_generate(iovs, iovcnt, block_size - md_size, 0, num_blocks);
	CU_ASSERT(rc == 0);

	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, dif_loc, dif_type, dif_flags,
	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, dif_type, dif_flags,
			       init_ref_tag, apptag_mask, app_tag);
	CU_ASSERT(rc == 0);

@@ -907,7 +907,7 @@ _dif_copy_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *
	rc = ut_data_pattern_generate(iovs, iovcnt, block_size - md_size, 0, num_blocks);
	CU_ASSERT(rc == 0);

	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, dif_loc, SPDK_DIF_TYPE1, dif_flags,
	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, SPDK_DIF_TYPE1, dif_flags,
			       88, 0xFFFF, 0x88);
	SPDK_CU_ASSERT_FATAL(rc == 0);

@@ -1007,6 +1007,175 @@ dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test(void)
	_iov_free_buf(&bounce_iov);
}

static void
dix_sec_512_md_0_error(void)
{
	struct spdk_dif_ctx ctx;
	int rc;

	rc = spdk_dif_ctx_init(&ctx, 512, 0, false, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
	CU_ASSERT(rc != 0);
}

static void
dix_generate_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
			uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
			bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
			uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
{
	struct spdk_dif_ctx ctx;
	int rc;

	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, 0, num_blocks);
	CU_ASSERT(rc == 0);

	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, dif_type, dif_flags,
			       init_ref_tag, apptag_mask, app_tag);
	CU_ASSERT(rc == 0);

	rc = spdk_dix_generate(iovs, iovcnt, md_iov, num_blocks, &ctx);
	CU_ASSERT(rc == 0);

	rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx);
	CU_ASSERT(rc == 0);

	rc = ut_data_pattern_verify(iovs, iovcnt, block_size, 0, num_blocks);
	CU_ASSERT(rc == 0);
}

static void
dix_sec_512_md_8_prchk_0_single_iov(void)
{
	struct iovec iov, md_iov;

	_iov_alloc_buf(&iov, 512 * 4);
	_iov_alloc_buf(&md_iov, 8 * 4);

	dix_generate_and_verify(&iov, 1, &md_iov, 512, 8, 4, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
	dix_generate_and_verify(&iov, 1, &md_iov, 512, 8, 4, true, SPDK_DIF_TYPE1, 0, 0, 0, 0);

	_iov_free_buf(&iov);
	_iov_free_buf(&md_iov);
}

static void
dix_sec_512_md_8_prchk_0_1_2_4_multi_iovs(void)
{
	struct iovec iovs[4], md_iov;
	int i, num_blocks;

	num_blocks = 0;

	for (i = 0; i < 4; i++) {
		_iov_alloc_buf(&iovs[i], 512 * (i + 1));
		num_blocks += i + 1;
	}
	_iov_alloc_buf(&md_iov, 8 * num_blocks);

	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
				0, 22, 0xFFFF, 0x22);

	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
				SPDK_DIF_GUARD_CHECK, 22, 0xFFFF, 0x22);

	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
				SPDK_DIF_APPTAG_CHECK, 22, 0xFFFF, 0x22);

	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
				SPDK_DIF_REFTAG_CHECK, 22, 0xFFFF, 0x22);

	for (i = 0; i < 4; i++) {
		_iov_free_buf(&iovs[i]);
	}
	_iov_free_buf(&md_iov);
}

static void
dix_sec_4096_md_128_prchk_7_multi_iovs(void)
{
	struct iovec iovs[4], md_iov;
	uint32_t dif_flags;
	int i, num_blocks;

	dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK;

	num_blocks = 0;

	for (i = 0; i < 4; i++) {
		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
		num_blocks += i + 1;
	}
	_iov_alloc_buf(&md_iov, 128 * num_blocks);

	dix_generate_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, false, SPDK_DIF_TYPE1,
				dif_flags, 22, 0xFFFF, 0x22);
	dix_generate_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, true, SPDK_DIF_TYPE1,
				dif_flags, 22, 0xFFFF, 0x22);

	for (i = 0; i < 4; i++) {
		_iov_free_buf(&iovs[i]);
	}
	_iov_free_buf(&md_iov);
}

static void
dix_sec_512_md_8_prchk_7_multi_iovs_split_data(void)
{
	struct iovec iovs[2], md_iov;
	uint32_t dif_flags;

	dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK;

	_iov_alloc_buf(&iovs[0], 256);
	_iov_alloc_buf(&iovs[1], 256);
	_iov_alloc_buf(&md_iov, 8);

	dix_generate_and_verify(iovs, 2, &md_iov, 512, 8, 1, false, SPDK_DIF_TYPE1,
				dif_flags, 22, 0xFFFF, 0x22);

	_iov_free_buf(&iovs[0]);
	_iov_free_buf(&iovs[1]);
	_iov_free_buf(&md_iov);
}

static void
dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits(void)
{
	struct iovec iovs[6], md_iov;
	uint32_t dif_flags;
	int i;

	dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK;

	/* data[0][255:0] */
	_iov_alloc_buf(&iovs[0], 256);

	/* data[0][511:256], data[1][255:0] */
	_iov_alloc_buf(&iovs[1], 256 + 256);

	/* data[1][382:256] */
	_iov_alloc_buf(&iovs[2], 128);

	/* data[1][383] */
	_iov_alloc_buf(&iovs[3], 1);

	/* data[1][510:384] */
	_iov_alloc_buf(&iovs[4], 126);

	/* data[1][511], data[2][511:0], data[3][511:0] */
	_iov_alloc_buf(&iovs[5], 1 + 512 * 2);

	_iov_alloc_buf(&md_iov, 8 * 4);

	dix_generate_and_verify(iovs, 6, &md_iov, 512, 8, 4, false, SPDK_DIF_TYPE1,
				dif_flags, 22, 0xFFFF, 0x22);

	for (i = 0; i < 6; i++) {
		_iov_free_buf(&iovs[i]);
	}
	_iov_free_buf(&md_iov);
}

int
main(int argc, char **argv)
{
@@ -1074,7 +1243,18 @@ main(int argc, char **argv)
		CU_add_test(suite, "dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test",
			    dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test) == NULL ||
		CU_add_test(suite, "dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test",
			    dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test) == NULL
			    dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test) == NULL ||
		CU_add_test(suite, "dix_sec_512_md_0_error", dix_sec_512_md_0_error) == NULL ||
		CU_add_test(suite, "dix_sec_512_md_8_prchk_0_single_iov",
			    dix_sec_512_md_8_prchk_0_single_iov) == NULL ||
		CU_add_test(suite, "dix_sec_512_md_8_prchk_0_1_2_4_multi_iovs",
			    dix_sec_512_md_8_prchk_0_1_2_4_multi_iovs) == NULL ||
		CU_add_test(suite, "dix_sec_4096_md_128_prchk_7_multi_iovs",
			    dix_sec_4096_md_128_prchk_7_multi_iovs) == NULL ||
		CU_add_test(suite, "dix_sec_512_md_8_prchk_7_multi_iovs_split_data",
			    dix_sec_512_md_8_prchk_7_multi_iovs_split_data) == NULL ||
		CU_add_test(suite, "dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits",
			    dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits) == NULL
	) {
		CU_cleanup_registry();
		return CU_get_error();