diff --git a/include/spdk/crc16.h b/include/spdk/crc16.h index 382d9d62e..053fbd5e4 100644 --- a/include/spdk/crc16.h +++ b/include/spdk/crc16.h @@ -59,6 +59,18 @@ extern "C" { * \return CRC-16 value. */ uint16_t spdk_crc16_t10dif(uint16_t init_crc, const void *buf, size_t len); + +/** + * Calculate T10-DIF CRC-16 checksum and copy data. + * + * \param init_crc Initial CRC-16 value. + * \param dst Destination data buffer for copy. + * \param src Source data buffer for CRC calculation and copy. + * \param len Length of buffer in bytes. + * \return CRC-16 value. + */ +uint16_t spdk_crc16_t10dif_copy(uint16_t init_crc, uint8_t *dst, uint8_t *src, + size_t len); #ifdef __cplusplus } #endif diff --git a/lib/util/crc16.c b/lib/util/crc16.c index 5e19e6937..b38937004 100644 --- a/lib/util/crc16.c +++ b/lib/util/crc16.c @@ -53,3 +53,25 @@ spdk_crc16_t10dif(uint16_t init_crc, const void *buf, size_t len) } return (uint16_t)rem; } + +uint16_t +spdk_crc16_t10dif_copy(uint16_t init_crc, uint8_t *dst, uint8_t *src, + size_t len) +{ + uint32_t j, rem; + size_t i; + + uint16_t poly = SPDK_T10DIF_CRC16_POLYNOMIAL; + + rem = init_crc; + + for (i = 0; i < len; i++) { + rem = rem ^ (src[i] << 8); + dst[i] = src[i]; + for (j = 0; j < 8; j++) { + rem = rem << 1; + rem = (rem & 0x10000) ? rem ^ poly : rem; + } + } + return (uint16_t)rem; +} diff --git a/test/unit/lib/util/crc16.c/crc16_ut.c b/test/unit/lib/util/crc16.c/crc16_ut.c index 360299c6a..e23af34e9 100644 --- a/test/unit/lib/util/crc16.c/crc16_ut.c +++ b/test/unit/lib/util/crc16.c/crc16_ut.c @@ -59,6 +59,25 @@ test_crc16_t10dif_seed(void) CU_ASSERT(crc == 0xd0db); } +static void +test_crc16_t10dif_copy(void) +{ + uint16_t crc1 = 0, crc2; + char buf1[] = "1234"; + char buf2[] = "56789"; + char *buf3 = calloc(1, strlen(buf1) + strlen(buf2) + 1); + SPDK_CU_ASSERT_FATAL(buf3 != NULL); + + crc1 = spdk_crc16_t10dif_copy(crc1, buf3, buf1, strlen(buf1)); + crc1 = spdk_crc16_t10dif_copy(crc1, buf3 + strlen(buf1), buf2, strlen(buf2)); + CU_ASSERT(crc1 == 0xd0db); + + crc2 = spdk_crc16_t10dif(0, buf3, strlen(buf3)); + CU_ASSERT(crc2 == 0xd0db); + + free(buf3); +} + int main(int argc, char **argv) { @@ -77,7 +96,8 @@ main(int argc, char **argv) if ( CU_add_test(suite, "test_crc16_t10dif", test_crc16_t10dif) == NULL || - CU_add_test(suite, "test_crc16_t10dif_seed", test_crc16_t10dif_seed) == NULL) { + CU_add_test(suite, "test_crc16_t10dif_seed", test_crc16_t10dif_seed) == NULL || + CU_add_test(suite, "test_crc16_t10dif_copy", test_crc16_t10dif_copy) == NULL) { CU_cleanup_registry(); return CU_get_error(); }