From 879f542ebfa6d2685fdb0889143b47870ff1f394 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 5 Mar 2014 18:47:24 -0800 Subject: [PATCH] TESTS: CompareAndWrite are bounded by the max block setting in BlockLimits Make sure that we check that a target returns an error if we try to compare and write too much. --- test-tool/iscsi-support.c | 52 +++++++++++++++++++++ test-tool/iscsi-support.h | 1 + test-tool/test_compareandwrite_miscompare.c | 36 ++++++++++++++ test-tool/test_compareandwrite_simple.c | 41 +++++++++++++++- 4 files changed, 129 insertions(+), 1 deletion(-) diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index bbc2bbd..21d26b0 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -1812,6 +1812,58 @@ int compareandwrite_miscompare(struct iscsi_context *iscsi, int lun, return 0; } +int compareandwrite_invalidfieldincdb(struct iscsi_context *iscsi, int lun, + uint64_t lba, unsigned char *data, + uint32_t len, int blocksize, + int wrprotect, int dpo, + int fua, int group_number) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send COMPARE_AND_WRITE LBA:%" PRIu64 + " LEN:%d WRPROTECT:%d (expecting INVALID_FIELD_IN_CDB)", + lba, len, wrprotect); + + task = iscsi_compareandwrite_sync(iscsi, lun, lba, + data, len, blocksize, + wrprotect, dpo, fua, 0, group_number); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send COMPARE_AND_WRITE " + "command: %s", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status == SCSI_STATUS_CHECK_CONDITION + && task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST + && task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) { + logging(LOG_NORMAL, "[SKIPPED] COMPARE_AND_WRITE is not " + "implemented on target"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + logging(LOG_NORMAL, "[FAILED] COMPARE_AND_WRITE successful " + "but should have failed with MISCOMPARE."); + scsi_free_scsi_task(task); + return -1; + } + + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_MISCOMPARE + || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { + logging(LOG_NORMAL, "[FAILED] COMPARE_AND_WRITE failed with " + "the wrong sense code. Should have failed with " + "INVALID_FIELD_IN_CDB but failed with " + "sense:%s", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] COMPARE_AND_WRITE returned INVALID_FIELD_IN_CDB."); + return 0; +} + struct scsi_task *get_lba_status_task(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t len) { struct scsi_task *task; diff --git a/test-tool/iscsi-support.h b/test-tool/iscsi-support.h index ec88220..d2bd6f8 100644 --- a/test-tool/iscsi-support.h +++ b/test-tool/iscsi-support.h @@ -227,6 +227,7 @@ int inquiry(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int m int inquiry_invalidfieldincdb(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize); struct scsi_task *get_lba_status_task(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t len); int compareandwrite(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t len, int blocksize, int wrprotect, int dpo, int fua, int group_number); +int compareandwrite_invalidfieldincdb(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t len, int blocksize, int wrprotect, int dpo, int fua, int group_number); int compareandwrite_miscompare(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t len, int blocksize, int wrprotect, int dpo, int fua, int group_number); int get_lba_status(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t len); int get_lba_status_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t len); diff --git a/test-tool/test_compareandwrite_miscompare.c b/test-tool/test_compareandwrite_miscompare.c index f73ee56..cf88110 100644 --- a/test-tool/test_compareandwrite_miscompare.c +++ b/test-tool/test_compareandwrite_miscompare.c @@ -33,10 +33,17 @@ test_compareandwrite_miscompare(void) int i, ret; unsigned j; unsigned char *buf = alloca(2 * 256 * block_size); + int maxbl; CHECK_FOR_DATALOSS; CHECK_FOR_SBC; + if (inq_bl && inq_bl->max_cmp) { + maxbl = inq_bl->max_cmp; + } else { + /* Assume we are not limited */ + maxbl = 256; + } logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test COMPARE_AND_WRITE of 1-256 blocks at the " "start of the LUN. One Byte miscompare in the final block."); @@ -59,6 +66,23 @@ test_compareandwrite_miscompare(void) logging(LOG_VERBOSE, "Change byte 27 from the end to 'C' so that it does not match."); buf[i * block_size - 27] = 'C'; + if (i > maxbl) { + logging(LOG_VERBOSE, "Number of blocks %d is greater than " + "BlockLimits.MaximumCompareAndWriteLength(%d). " + "Command should fail with INVALID_FIELD_IN_CDB", + i, maxbl); + ret = compareandwrite_invalidfieldincdb(iscsic, tgt_lun, 0, + buf, 2 * i * block_size, block_size, + 0, 0, 0, 0); + if (ret == -2) { + CU_PASS("[SKIPPED] Target does not support " + "COMPARE_AND_WRITE. Skipping test"); + return; + } + CU_ASSERT_EQUAL(ret, 0); + + continue; + } memset(buf + i * block_size, 'B', i * block_size); @@ -107,6 +131,18 @@ test_compareandwrite_miscompare(void) buf[i * block_size - 27] = 'C'; + if (i > maxbl) { + logging(LOG_VERBOSE, "Number of blocks %d is greater than " + "BlockLimits.MaximumCompareAndWriteLength(%d). " + "Command should fail with INVALID_FIELD_IN_CDB", + i, maxbl); + ret = compareandwrite_invalidfieldincdb(iscsic, tgt_lun, 0, + buf, 2 * i * block_size, block_size, + 0, 0, 0, 0); + CU_ASSERT_EQUAL(ret, 0); + + continue; + } memset(buf + i * block_size, 'B', i * block_size); logging(LOG_VERBOSE, "Overwrite %d blocks with 'B' " diff --git a/test-tool/test_compareandwrite_simple.c b/test-tool/test_compareandwrite_simple.c index 186fb7e..71a87cb 100644 --- a/test-tool/test_compareandwrite_simple.c +++ b/test-tool/test_compareandwrite_simple.c @@ -33,10 +33,18 @@ test_compareandwrite_simple(void) int i, ret; unsigned j; unsigned char *buf = alloca(2 * 256 * block_size); + int maxbl; CHECK_FOR_DATALOSS; CHECK_FOR_SBC; + if (inq_bl && inq_bl->max_cmp) { + maxbl = inq_bl->max_cmp; + } else { + /* Assume we are not limited */ + maxbl = 256; + } + logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test COMPARE_AND_WRITE of 1-256 blocks at the " "start of the LUN"); @@ -55,12 +63,31 @@ test_compareandwrite_simple(void) } CU_ASSERT_EQUAL(ret, 0); + if (i > maxbl) { + logging(LOG_VERBOSE, "Number of blocks %d is greater than " + "BlockLimits.MaximumCompareAndWriteLength(%d). " + "Command should fail with INVALID_FIELD_IN_CDB", + i, maxbl); + ret = compareandwrite_invalidfieldincdb(iscsic, tgt_lun, 0, + buf, 2 * i * block_size, block_size, + 0, 0, 0, 0); + if (ret == -2) { + CU_PASS("[SKIPPED] Target does not support " + "COMPARE_AND_WRITE. Skipping test"); + return; + } + CU_ASSERT_EQUAL(ret, 0); + + continue; + } + memset(buf + i * block_size, 'B', i * block_size); logging(LOG_VERBOSE, "Overwrite %d blocks with 'B' " "at LBA:0 (if they all contain 'A')", i); ret = compareandwrite(iscsic, tgt_lun, 0, - buf, 2 * i * block_size, block_size, 0, 0, 0, 0); + buf, 2 * i * block_size, block_size, + 0, 0, 0, 0); if (ret == -2) { CU_PASS("[SKIPPED] Target does not support " "COMPARE_AND_WRITE. Skipping test"); @@ -98,6 +125,18 @@ test_compareandwrite_simple(void) block_size, 0, 0, 0, 0, 0, buf); CU_ASSERT_EQUAL(ret, 0); + if (i > maxbl) { + logging(LOG_VERBOSE, "Number of blocks %d is greater than " + "BlockLimits.MaximumCompareAndWriteLength(%d). " + "Command should fail with INVALID_FIELD_IN_CDB", + i, maxbl); + ret = compareandwrite_invalidfieldincdb(iscsic, tgt_lun, 0, + buf, 2 * i * block_size, block_size, + 0, 0, 0, 0); + CU_ASSERT_EQUAL(ret, 0); + + continue; + } memset(buf + i * block_size, 'B', i * block_size); logging(LOG_VERBOSE, "Overwrite %d blocks with 'B' "