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 <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/446224
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-02-26 15:53:10 +09:00 committed by Changpeng Liu
parent e17851314e
commit 8697bce7af
5 changed files with 140 additions and 0 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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();