scsi_bdev: add Maximum Transfer Length check

We report SPDK_WORK_BLOCK_SIZE (1 MiB) as the Maximum Transfer Length in
the Block Limits VPD.  The initiator should not submit a request larger
than this; if it does, fail the request.

Change-Id: I39575cdca4555ac1f78e055a48569be3f47e4781
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/373162
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Daniel Verkamp 2017-05-12 13:24:15 -07:00 committed by Jim Harris
parent 2b7b41ee5d
commit 0b1bbb4532
2 changed files with 61 additions and 0 deletions

View File

@ -1443,6 +1443,8 @@ spdk_bdev_scsi_readwrite(struct spdk_bdev *bdev,
struct spdk_scsi_task *task,
uint64_t lba, uint32_t xfer_len, bool is_read)
{
uint32_t max_xfer_len;
if (task->dxfer_dir != SPDK_SCSI_DIR_NONE &&
task->dxfer_dir != (is_read ? SPDK_SCSI_DIR_FROM_DEV : SPDK_SCSI_DIR_TO_DEV)) {
SPDK_ERRLOG("Incorrect data direction\n");
@ -1459,6 +1461,18 @@ spdk_bdev_scsi_readwrite(struct spdk_bdev *bdev,
return SPDK_SCSI_TASK_COMPLETE;
}
/* Transfer Length is limited to the Block Limits VPD page Maximum Transfer Length */
max_xfer_len = SPDK_WORK_BLOCK_SIZE / spdk_bdev_get_block_size(bdev);
if (xfer_len > max_xfer_len) {
SPDK_ERRLOG("xfer_len %" PRIu32 " > maximum transfer length %" PRIu32 "\n",
xfer_len, max_xfer_len);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
}
if (is_read) {
return spdk_bdev_scsi_read(bdev, task, lba, xfer_len);
} else {

View File

@ -629,6 +629,52 @@ lba_range_test(void)
spdk_put_task(&task);
}
static void
xfer_len_test(void)
{
struct spdk_bdev bdev;
struct spdk_scsi_task task;
uint8_t cdb[16];
int rc;
spdk_init_task(&task);
task.cdb = cdb;
memset(cdb, 0, sizeof(cdb));
cdb[0] = 0x88; /* READ (16) */
/* Test block device size of 512 MiB */
g_test_bdev_num_blocks = 512 * 1024 * 1024;
/* 1 block */
to_be64(&cdb[2], 0); /* LBA */
to_be32(&cdb[10], 1); /* transfer length */
task.transfer_len = 1 * 512;
rc = spdk_bdev_scsi_execute(&bdev, &task);
CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING);
CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD);
/* max transfer length (as reported in block limits VPD page) */
to_be64(&cdb[2], 0); /* LBA */
to_be32(&cdb[10], SPDK_WORK_BLOCK_SIZE / 512); /* transfer length */
task.transfer_len = SPDK_WORK_BLOCK_SIZE;
rc = spdk_bdev_scsi_execute(&bdev, &task);
CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING);
CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD);
/* max transfer length plus one block (invalid) */
to_be64(&cdb[2], 0); /* LBA */
to_be32(&cdb[10], SPDK_WORK_BLOCK_SIZE / 512 + 1); /* transfer length */
task.transfer_len = SPDK_WORK_BLOCK_SIZE + 512;
rc = spdk_bdev_scsi_execute(&bdev, &task);
CU_ASSERT(rc == SPDK_SCSI_TASK_COMPLETE);
CU_ASSERT(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION);
CU_ASSERT((task.sense_data[2] & 0xf) == SPDK_SCSI_SENSE_ILLEGAL_REQUEST);
CU_ASSERT(task.sense_data[12] == SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB);
spdk_put_task(&task);
}
int
main(int argc, char **argv)
{
@ -655,6 +701,7 @@ main(int argc, char **argv)
|| CU_add_test(suite, "inquiry overflow test", inquiry_overflow_test) == NULL
|| CU_add_test(suite, "task complete test", task_complete_test) == NULL
|| CU_add_test(suite, "LBA range test", lba_range_test) == NULL
|| CU_add_test(suite, "transfer length test", xfer_len_test) == NULL
) {
CU_cleanup_registry();
return CU_get_error();