From 8697bce7af00b827c72283bc09d889e408bba36d Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Tue, 26 Feb 2019 15:53:10 +0900 Subject: [PATCH] scsi: Add an API to return DIF context of bdev and CDB This patch adds an API spdk_scsi_bdev_get_dif_ctx(). spdk_scsi_bdev_get_dif_ctx() decodes opcode in CDB, and if opcode is read or write block commands, it gets LBA and use the lower 32bits of LBA as Reference Tag. It gets DIF information from specified bdev next. Then it sets all to DIF context and return. spdk_scsi_bdev_get_dif_ctx() is exported to iSCSI through spdk_scsi_lun_get_dif_ctx(). Change-Id: Id8aac164c48e9e9d4ff7cfc9fa81bb5090f3e187 Signed-off-by: Shuhei Matsumoto Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/446224 Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Changpeng Liu --- include/spdk/scsi.h | 12 ++++ lib/scsi/lun.c | 7 +++ lib/scsi/scsi_bdev.c | 55 ++++++++++++++++ lib/scsi/scsi_internal.h | 4 ++ test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut.c | 62 +++++++++++++++++++ 5 files changed, 140 insertions(+) diff --git a/include/spdk/scsi.h b/include/spdk/scsi.h index 9fa7ad6b55..6fafd5d0f1 100644 --- a/include/spdk/scsi.h +++ b/include/spdk/scsi.h @@ -518,6 +518,18 @@ int spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_desc *desc); */ void spdk_scsi_lun_free_io_channel(struct spdk_scsi_desc *desc); +/** + * Get DIF context for SCSI LUN and SCSI command. + * + * \param lun Logical unit. + * \param cdb SCSI CDB. + * \param offset Offset in the payload. + * \param dif_ctx Output parameter which will contain initialized DIF context. + * + * \return true on success or false otherwise. + */ +bool spdk_scsi_lun_get_dif_ctx(struct spdk_scsi_lun *lun, uint8_t *cdb, uint32_t offset, + struct spdk_dif_ctx *dif_ctx); /** * Set iSCSI Initiator port TransportID diff --git a/lib/scsi/lun.c b/lib/scsi/lun.c index c15eabd267..6318461a80 100644 --- a/lib/scsi/lun.c +++ b/lib/scsi/lun.c @@ -494,3 +494,10 @@ spdk_scsi_lun_is_removing(const struct spdk_scsi_lun *lun) { return lun->removed; } + +bool +spdk_scsi_lun_get_dif_ctx(struct spdk_scsi_lun *lun, uint8_t *cdb, + uint32_t offset, struct spdk_dif_ctx *dif_ctx) +{ + return spdk_scsi_bdev_get_dif_ctx(lun->bdev, cdb, offset, dif_ctx); +} diff --git a/lib/scsi/scsi_bdev.c b/lib/scsi/scsi_bdev.c index b21fd42857..a939cb439b 100644 --- a/lib/scsi/scsi_bdev.c +++ b/lib/scsi/scsi_bdev.c @@ -2093,3 +2093,58 @@ spdk_bdev_scsi_reset(struct spdk_scsi_task *task) spdk_bdev_scsi_queue_io(task, spdk_bdev_scsi_reset_resubmit, task); } } + +bool +spdk_scsi_bdev_get_dif_ctx(struct spdk_bdev *bdev, uint8_t *cdb, uint32_t offset, + struct spdk_dif_ctx *dif_ctx) +{ + uint32_t ref_tag = 0, dif_check_flags = 0; + int rc; + + if (spdk_likely(spdk_bdev_get_md_size(bdev) == 0)) { + return false; + } + + /* We use lower 32 bits of LBA as Reference. Tag */ + switch (cdb[0]) { + case SPDK_SBC_READ_6: + case SPDK_SBC_WRITE_6: + ref_tag = (uint32_t)cdb[1] << 16; + ref_tag |= (uint32_t)cdb[2] << 8; + ref_tag |= (uint32_t)cdb[3]; + break; + case SPDK_SBC_READ_10: + case SPDK_SBC_WRITE_10: + case SPDK_SBC_READ_12: + case SPDK_SBC_WRITE_12: + ref_tag = from_be32(&cdb[2]); + break; + case SPDK_SBC_READ_16: + case SPDK_SBC_WRITE_16: + ref_tag = (uint32_t)from_be64(&cdb[2]); + break; + default: + return false; + } + + ref_tag += offset / spdk_bdev_get_data_block_size(bdev); + + if (spdk_bdev_is_dif_check_enabled(bdev, SPDK_DIF_CHECK_TYPE_REFTAG)) { + dif_check_flags |= SPDK_DIF_FLAGS_REFTAG_CHECK; + } + + if (spdk_bdev_is_dif_check_enabled(bdev, SPDK_DIF_CHECK_TYPE_GUARD)) { + dif_check_flags |= SPDK_DIF_FLAGS_GUARD_CHECK; + } + + rc = spdk_dif_ctx_init(dif_ctx, + spdk_bdev_get_block_size(bdev), + spdk_bdev_get_md_size(bdev), + spdk_bdev_is_md_interleaved(bdev), + spdk_bdev_is_dif_head_of_md(bdev), + spdk_bdev_get_dif_type(bdev), + dif_check_flags, + ref_tag, 0, 0, 0); + + return (rc == 0) ? true : false; +} diff --git a/lib/scsi/scsi_internal.h b/lib/scsi/scsi_internal.h index 5a7839eaf0..04b28f28c1 100644 --- a/lib/scsi/scsi_internal.h +++ b/lib/scsi/scsi_internal.h @@ -41,6 +41,7 @@ #include "spdk/scsi.h" #include "spdk/scsi_spec.h" #include "spdk/trace.h" +#include "spdk/dif.h" #include "spdk_internal/log.h" @@ -168,6 +169,9 @@ void spdk_scsi_port_destruct(struct spdk_scsi_port *port); int spdk_bdev_scsi_execute(struct spdk_scsi_task *task); void spdk_bdev_scsi_reset(struct spdk_scsi_task *task); +bool spdk_scsi_bdev_get_dif_ctx(struct spdk_bdev *bdev, uint8_t *cdb, uint32_t offset, + struct spdk_dif_ctx *dif_ctx); + struct spdk_scsi_globals { pthread_mutex_t mutex; }; diff --git a/test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut.c b/test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut.c index 5d44910de5..fbd097d8bf 100644 --- a/test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut.c +++ b/test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut.c @@ -72,6 +72,12 @@ DEFINE_STUB(spdk_bdev_get_name, const char *, DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, (const struct spdk_bdev *bdev), 512); +DEFINE_STUB(spdk_bdev_get_md_size, uint32_t, + (const struct spdk_bdev *bdev), 8); + +DEFINE_STUB(spdk_bdev_is_md_interleaved, bool, + (const struct spdk_bdev *bdev), false); + DEFINE_STUB(spdk_bdev_get_data_block_size, uint32_t, (const struct spdk_bdev *bdev), 512); @@ -87,6 +93,15 @@ DEFINE_STUB(spdk_bdev_get_product_name, const char *, DEFINE_STUB(spdk_bdev_has_write_cache, bool, (const struct spdk_bdev *bdev), false); +DEFINE_STUB(spdk_bdev_get_dif_type, enum spdk_dif_type, + (const struct spdk_bdev *bdev), SPDK_DIF_DISABLE); + +DEFINE_STUB(spdk_bdev_is_dif_head_of_md, bool, + (const struct spdk_bdev *bdev), false); + +DEFINE_STUB(spdk_bdev_is_dif_check_enabled, bool, + (const struct spdk_bdev *bdev, enum spdk_dif_check_type check_type), false); + void spdk_scsi_lun_complete_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) { @@ -245,6 +260,16 @@ spdk_bdev_queue_io_wait(struct spdk_bdev *bdev, struct spdk_io_channel *ch, return 0; } +int +spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size, + 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, + uint16_t guard_seed) +{ + ctx->init_ref_tag = init_ref_tag; + return 0; +} + /* * This test specifically tests a mode select 6 command from the * Windows SCSI compliance test that caused SPDK to crash. @@ -929,6 +954,42 @@ xfer_test(void) _xfer_test(true); } +static void +get_dif_ctx_test(void) +{ + struct spdk_bdev bdev = {}; + struct spdk_dif_ctx dif_ctx = {}; + uint8_t cdb[16]; + uint32_t offset; + bool ret; + + cdb[0] = SPDK_SBC_READ_6; + cdb[1] = 0x12; + cdb[2] = 0x34; + cdb[3] = 0x50; + offset = 0x6 * 512; + + ret = spdk_scsi_bdev_get_dif_ctx(&bdev, cdb, offset, &dif_ctx); + CU_ASSERT(ret == true); + CU_ASSERT(dif_ctx.init_ref_tag == 0x123456); + + cdb[0] = SPDK_SBC_WRITE_12; + to_be32(&cdb[2], 0x12345670); + offset = 0x8 * 512; + + ret = spdk_scsi_bdev_get_dif_ctx(&bdev, cdb, offset, &dif_ctx); + CU_ASSERT(ret == true); + CU_ASSERT(dif_ctx.init_ref_tag == 0x12345678); + + cdb[0] = SPDK_SBC_WRITE_16; + to_be64(&cdb[2], 0x0000000012345670); + offset = 0x8 * 512; + + ret = spdk_scsi_bdev_get_dif_ctx(&bdev, cdb, offset, &dif_ctx); + CU_ASSERT(ret == true); + CU_ASSERT(dif_ctx.init_ref_tag == 0x12345678); +} + int main(int argc, char **argv) { @@ -961,6 +1022,7 @@ main(int argc, char **argv) || CU_add_test(suite, "transfer length test", xfer_len_test) == NULL || CU_add_test(suite, "transfer test", xfer_test) == NULL || CU_add_test(suite, "scsi name padding test", scsi_name_padding_test) == NULL + || CU_add_test(suite, "get dif context test", get_dif_ctx_test) == NULL ) { CU_cleanup_registry(); return CU_get_error();