4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include "spdk/stdinc.h"
38 #include "spdk/assert.h"
40 #define SPDK_DIF_FLAGS_REFTAG_CHECK (1U << 26)
41 #define SPDK_DIF_FLAGS_APPTAG_CHECK (1U << 27)
42 #define SPDK_DIF_FLAGS_GUARD_CHECK (1U << 28)
44 #define SPDK_DIF_REFTAG_ERROR 0x1
45 #define SPDK_DIF_APPTAG_ERROR 0x2
46 #define SPDK_DIF_GUARD_ERROR 0x4
47 #define SPDK_DIF_DATA_ERROR 0x8
56 enum spdk_dif_check_type
{
57 SPDK_DIF_CHECK_TYPE_REFTAG
= 1,
58 SPDK_DIF_CHECK_TYPE_APPTAG
= 2,
59 SPDK_DIF_CHECK_TYPE_GUARD
= 3,
67 SPDK_STATIC_ASSERT(sizeof(struct spdk_dif
) == 8, "Incorrect size");
69 /** DIF context information */
77 /** Metadata location */
80 /** Interval for guard computation for DIF */
81 uint32_t guard_interval
;
84 enum spdk_dif_type dif_type
;
86 /* Flags to specify the DIF action */
89 /* Initial reference tag */
90 uint32_t init_ref_tag
;
92 /** Application tag */
95 /* Application tag mask */
98 /* Byte offset from the start of the whole data buffer. */
101 /* Offset to initial reference tag */
102 uint32_t ref_tag_offset
;
104 /** Guard value of the last data block.
106 * Interim guard value is set if the last data block is partial, or
107 * seed value is set otherwise.
111 /* Seed value for guard computation */
114 /* Remapped initial reference tag. */
115 uint32_t remapped_init_ref_tag
;
118 /** DIF error information */
119 struct spdk_dif_error
{
123 /** Expected value */
129 /** Offset the error occurred at, block based */
134 * Initialize DIF context.
136 * \param ctx DIF context.
137 * \param block_size Block size in a block.
138 * \param md_size Metadata size in a block.
139 * \param md_interleave If true, metadata is interleaved with block data.
140 * If false, metadata is separated with block data.
141 * \param dif_loc DIF location. If true, DIF is set in the first 8 bytes of metadata.
142 * If false, DIF is in the last 8 bytes of metadata.
143 * \param dif_type Type of DIF.
144 * \param dif_flags Flag to specify the DIF action.
145 * \param init_ref_tag Initial reference tag. For type 1, this is the
146 * starting block address.
147 * \param apptag_mask Application tag mask.
148 * \param app_tag Application tag.
149 * \param data_offset Byte offset from the start of the whole data buffer.
150 * \param guard_seed Seed value for guard computation.
152 * \return 0 on success and negated errno otherwise.
154 int spdk_dif_ctx_init(struct spdk_dif_ctx
*ctx
, uint32_t block_size
, uint32_t md_size
,
155 bool md_interleave
, bool dif_loc
, enum spdk_dif_type dif_type
, uint32_t dif_flags
,
156 uint32_t init_ref_tag
, uint16_t apptag_mask
, uint16_t app_tag
,
157 uint32_t data_offset
, uint16_t guard_seed
);
160 * Update date offset of DIF context.
162 * \param ctx DIF context.
163 * \param data_offset Byte offset from the start of the whole data buffer.
165 void spdk_dif_ctx_set_data_offset(struct spdk_dif_ctx
*ctx
, uint32_t data_offset
);
168 * Set remapped initial reference tag of DIF context.
170 * \param ctx DIF context.
171 * \param remapped_init_ref_tag Remapped initial reference tag. For type 1, this is the
172 * starting block address.
174 void spdk_dif_ctx_set_remapped_init_ref_tag(struct spdk_dif_ctx
*ctx
,
175 uint32_t remapped_init_ref_tag
);
178 * Generate DIF for extended LBA payload.
180 * \param iovs iovec array describing the extended LBA payload.
181 * \param iovcnt Number of elements in the iovec array.
182 * \param num_blocks Number of blocks of the payload.
183 * \param ctx DIF context.
185 * \return 0 on success and negated errno otherwise.
187 int spdk_dif_generate(struct iovec
*iovs
, int iovcnt
, uint32_t num_blocks
,
188 const struct spdk_dif_ctx
*ctx
);
191 * Verify DIF for extended LBA payload.
193 * \param iovs iovec array describing the extended LBA payload.
194 * \param iovcnt Number of elements in the iovec array.
195 * \param num_blocks Number of blocks of the payload.
196 * \param ctx DIF context.
197 * \param err_blk Error information of the block in which DIF error is found.
199 * \return 0 on success and negated errno otherwise.
201 int spdk_dif_verify(struct iovec
*iovs
, int iovcnt
, uint32_t num_blocks
,
202 const struct spdk_dif_ctx
*ctx
, struct spdk_dif_error
*err_blk
);
205 * Calculate CRC-32C checksum for extended LBA payload.
207 * \param iovs iovec array describing the extended LBA payload.
208 * \param iovcnt Number of elements in the iovec array.
209 * \param num_blocks Number of blocks of the payload.
210 * \param crc32c Initial and updated CRC-32C value.
211 * \param ctx DIF context.
213 * \return 0 on success and negated errno otherwise.
215 int spdk_dif_update_crc32c(struct iovec
*iovs
, int iovcnt
, uint32_t num_blocks
,
216 uint32_t *crc32c
, const struct spdk_dif_ctx
*ctx
);
219 * Copy data and generate DIF for extended LBA payload.
221 * \param iovs iovec array describing the LBA payload.
222 * \param iovcnt Number of elements in the iovec array.
223 * \param bounce_iov A contiguous buffer forming extended LBA payload.
224 * \param num_blocks Number of blocks of the LBA payload.
225 * \param ctx DIF context.
227 * \return 0 on success and negated errno otherwise.
229 int spdk_dif_generate_copy(struct iovec
*iovs
, int iovcnt
, struct iovec
*bounce_iov
,
230 uint32_t num_blocks
, const struct spdk_dif_ctx
*ctx
);
233 * Verify DIF and copy data for extended LBA payload.
235 * \param iovs iovec array describing the LBA payload.
236 * \param iovcnt Number of elements in the iovec array.
237 * \param bounce_iov A contiguous buffer forming extended LBA payload.
238 * \param num_blocks Number of blocks of the LBA payload.
239 * \param ctx DIF context.
240 * \param err_blk Error information of the block in which DIF error is found.
242 * \return 0 on success and negated errno otherwise.
244 int spdk_dif_verify_copy(struct iovec
*iovs
, int iovcnt
, struct iovec
*bounce_iov
,
245 uint32_t num_blocks
, const struct spdk_dif_ctx
*ctx
,
246 struct spdk_dif_error
*err_blk
);
249 * Inject bit flip error to extended LBA payload.
251 * \param iovs iovec array describing the extended LBA payload.
252 * \param iovcnt Number of elements in the iovec array.
253 * \param num_blocks Number of blocks of the payload.
254 * \param ctx DIF context.
255 * \param inject_flags Flags to specify the action of error injection.
256 * \param inject_offset Offset, in blocks, to which error is injected.
257 * If multiple error is injected, only the last injection is stored.
259 * \return 0 on success and negated errno otherwise including no metadata.
261 int spdk_dif_inject_error(struct iovec
*iovs
, int iovcnt
, uint32_t num_blocks
,
262 const struct spdk_dif_ctx
*ctx
, uint32_t inject_flags
,
263 uint32_t *inject_offset
);
266 * Generate DIF for separate metadata payload.
268 * \param iovs iovec array describing the LBA payload.
269 * \params iovcnt Number of elements in iovs.
270 * \param md_iov A contiguous buffer for metadata.
271 * \param num_blocks Number of blocks of the separate metadata payload.
272 * \param ctx DIF context.
274 * \return 0 on success and negated errno otherwise.
276 int spdk_dix_generate(struct iovec
*iovs
, int iovcnt
, struct iovec
*md_iov
,
277 uint32_t num_blocks
, const struct spdk_dif_ctx
*ctx
);
280 * Verify DIF for separate metadata payload.
282 * \param iovs iovec array describing the LBA payload.
283 * \params iovcnt Number of elements in iovs.
284 * \param md_iov A contiguous buffer for metadata.
285 * \param num_blocks Number of blocks of the separate metadata payload.
286 * \param ctx DIF context.
287 * \param err_blk Error information of the block in which DIF error is found.
289 * \return 0 on success and negated errno otherwise.
291 int spdk_dix_verify(struct iovec
*iovs
, int iovcnt
, struct iovec
*md_iov
,
292 uint32_t num_blocks
, const struct spdk_dif_ctx
*ctx
,
293 struct spdk_dif_error
*err_blk
);
296 * Inject bit flip error to separate metadata payload.
298 * \param iovs iovec array describing the extended LBA payload.
299 * \param iovcnt Number of elements in the iovec array.
300 * \param md_iov A contiguous buffer for metadata.
301 * \param num_blocks Number of blocks of the payload.
302 * \param ctx DIF context.
303 * \param inject_flags Flag to specify the action of error injection.
304 * \param inject_offset Offset, in blocks, to which error is injected.
305 * If multiple error is injected, only the last injection is stored.
307 * \return 0 on success and negated errno otherwise including no metadata.
309 int spdk_dix_inject_error(struct iovec
*iovs
, int iovcnt
, struct iovec
*md_iov
,
310 uint32_t num_blocks
, const struct spdk_dif_ctx
*ctx
,
311 uint32_t inject_flags
, uint32_t *inject_offset
);
314 * Setup iovec array to leave a space for metadata for each block.
316 * This function is used to leave a space for metadata for each block when
317 * the network socket reads data, or to make the network socket ignore a
318 * space for metadata for each block when the network socket writes data.
319 * This function removes the necessity of data copy in the SPDK application
320 * during DIF insertion and strip.
322 * When the extended LBA payload is splitted into multiple data segments,
323 * start of each data segment is passed through the DIF context. data_offset
324 * and data_len is within a data segment.
326 * \param iovs iovec array set by this function.
327 * \param iovcnt Number of elements in the iovec array.
328 * \param buf_iovs SGL for the buffer to create extended LBA payload.
329 * \param buf_iovcnt Size of the SGL for the buffer to create extended LBA payload.
330 * \param data_offset Offset to store the next incoming data in the current data segment.
331 * \param data_len Expected length of the newly read data in the current data segment of
332 * the extended LBA payload.
333 * \param mapped_len Output parameter that will contain data length mapped by
335 * \param ctx DIF context.
337 * \return Number of used elements in the iovec array on success or negated
340 int spdk_dif_set_md_interleave_iovs(struct iovec
*iovs
, int iovcnt
,
341 struct iovec
*buf_iovs
, int buf_iovcnt
,
342 uint32_t data_offset
, uint32_t data_len
,
343 uint32_t *mapped_len
,
344 const struct spdk_dif_ctx
*ctx
);
347 * Generate and insert DIF into metadata space for newly read data block.
349 * When the extended LBA payload is splitted into multiple data segments,
350 * start of each data segment is passed through the DIF context. data_offset
351 * and data_len is within a data segment.
353 * \param iovs iovec array describing the extended LBA payload.
354 * \param iovcnt Number of elements in the iovec array.
355 * \param data_offset Offset to the newly read data in the current data segment of
356 * the extended LBA payload.
357 * \param data_len Length of the newly read data in the current data segment of
358 * the extended LBA payload.
359 * \param ctx DIF context.
361 * \return 0 on success and negated errno otherwise.
363 int spdk_dif_generate_stream(struct iovec
*iovs
, int iovcnt
,
364 uint32_t data_offset
, uint32_t data_len
,
365 struct spdk_dif_ctx
*ctx
);
368 * Verify DIF for the to-be-written block of the extended LBA payload.
370 * \param iovs iovec array describing the extended LBA payload.
371 * \param iovcnt Number of elements in the iovec array.
372 * \param data_offset Offset to the to-be-written data in the extended LBA payload.
373 * \param data_len Length of the to-be-written data in the extended LBA payload.
374 * \param ctx DIF context.
376 * \return 0 on success and negated errno otherwise.
378 int spdk_dif_verify_stream(struct iovec
*iovs
, int iovcnt
,
379 uint32_t data_offset
, uint32_t data_len
,
380 struct spdk_dif_ctx
*ctx
,
381 struct spdk_dif_error
*err_blk
);
384 * Calculate CRC-32C checksum of the specified range in the extended LBA payload.
386 * \param iovs iovec array describing the extended LBA payload.
387 * \param iovcnt Number of elements in the iovec array.
388 * \param data_offset Offset to the range
389 * \param data_len Length of the range
390 * \param crc32c Initial and updated CRC-32C value.
391 * \param ctx DIF context.
393 * \return 0 on success and negated errno otherwise.
395 int spdk_dif_update_crc32c_stream(struct iovec
*iovs
, int iovcnt
,
396 uint32_t data_offset
, uint32_t data_len
,
397 uint32_t *crc32c
, const struct spdk_dif_ctx
*ctx
);
399 * Convert offset and size from LBA based to extended LBA based.
401 * \param data_offset Data offset
402 * \param data_len Data length
403 * \param buf_offset Buffer offset converted from data offset.
404 * \param buf_len Buffer length converted from data length
405 * \param ctx DIF context.
407 void spdk_dif_get_range_with_md(uint32_t data_offset
, uint32_t data_len
,
408 uint32_t *buf_offset
, uint32_t *buf_len
,
409 const struct spdk_dif_ctx
*ctx
);
412 * Convert length from LBA based to extended LBA based.
414 * \param data_len Data length
415 * \param ctx DIF context.
417 * \return Extended LBA based data length.
419 uint32_t spdk_dif_get_length_with_md(uint32_t data_len
, const struct spdk_dif_ctx
*ctx
);
422 * Remap reference tag for extended LBA payload.
424 * When using stacked virtual bdev (e.g. split virtual bdev), block address space for I/O
425 * will be remapped during I/O processing and so reference tag will have to be remapped
426 * accordingly. This patch is for that case.
428 * \param iovs iovec array describing the extended LBA payload.
429 * \param iovcnt Number of elements in the iovec array.
430 * \param num_blocks Number of blocks of the payload.
431 * \param ctx DIF context.
432 * \param err_blk Error information of the block in which DIF error is found.
434 * \return 0 on success and negated errno otherwise.
436 int spdk_dif_remap_ref_tag(struct iovec
*iovs
, int iovcnt
, uint32_t num_blocks
,
437 const struct spdk_dif_ctx
*dif_ctx
,
438 struct spdk_dif_error
*err_blk
);
441 * Remap reference tag for separate metadata payload.
443 * When using stacked virtual bdev (e.g. split virtual bdev), block address space for I/O
444 * will be remapped during I/O processing and so reference tag will have to be remapped
445 * accordingly. This patch is for that case.
447 * \param md_iov A contiguous buffer for metadata.
448 * \param num_blocks Number of blocks of the payload.
449 * \param ctx DIF context.
450 * \param err_blk Error information of the block in which DIF error is found.
452 * \return 0 on success and negated errno otherwise.
454 int spdk_dix_remap_ref_tag(struct iovec
*md_iov
, uint32_t num_blocks
,
455 const struct spdk_dif_ctx
*dif_ctx
,
456 struct spdk_dif_error
*err_blk
);
457 #endif /* SPDK_DIF_H */