diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 1c4a0f5..4c29c83 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -37,6 +37,9 @@ extern "C" { #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif #define ISCSI_RAW_HEADER_SIZE 48 #define ISCSI_DIGEST_SIZE 4 diff --git a/test-tool/Makefile.am b/test-tool/Makefile.am index 7dfea5c..848db03 100644 --- a/test-tool/Makefile.am +++ b/test-tool/Makefile.am @@ -7,6 +7,7 @@ LDADD = ../lib/libiscsipriv.la EXTRA_DIST = README dist_noinst_HEADERS = iscsi-support.h \ + test_write_residuals.h \ iscsi-test-cu.h iscsi-multipath.h # libiscsi test tool using cunit @@ -239,9 +240,7 @@ iscsi_test_cu_SOURCES = iscsi-test-cu.c \ test_async_read.c \ test_async_write.c \ test_async_abort_simple.c \ - test_async_lu_reset_simple.c + test_async_lu_reset_simple.c \ + test_write_residuals.c endif - - - diff --git a/test-tool/test_write10_residuals.c b/test-tool/test_write10_residuals.c index a8cbf94..2c4c207 100644 --- a/test-tool/test_write10_residuals.c +++ b/test-tool/test_write10_residuals.c @@ -25,21 +25,34 @@ #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" - -static int check_status (struct scsi_task *task) { - return (task->status == SCSI_STATUS_GOOD || - (task->status == SCSI_STATUS_CHECK_CONDITION && - task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && - task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_INFORMATION_UNIT)); -} +#include "test_write_residuals.h" void test_write10_residuals(void) { - struct scsi_task *task_ret; - unsigned char buf[10000]; - struct iscsi_data data; - unsigned int i; + /* testing scenarios */ + const struct residuals_test_data write10_residuals[] = { + /* cdb_size, xfer_len, buf_len, residuals_kind, residuals_amount, check_overwrite */ + {10, 1, 0, SCSI_RESIDUAL_OVERFLOW, block_size, false, + "Try writing one block but with iSCSI expected transfer length==0"}, + + {10, 1, 10000, SCSI_RESIDUAL_UNDERFLOW, 10000 - block_size, false, + "Try writing one block but with iSCSI expected transfer length==10000"}, + + {10, 1, 200, SCSI_RESIDUAL_OVERFLOW, block_size - 200, false, + "Try writing one block but with iSCSI expected transfer length==200"}, + + {10, 2, block_size, SCSI_RESIDUAL_OVERFLOW, block_size, false, + "Try writing two blocks but iSCSI expected one block transfer length"}, + + {10, 1, 2 * block_size, SCSI_RESIDUAL_UNDERFLOW, block_size, true, + "Verify that if iSCSI EDTL > SCSI TL then we only write SCSI TL amount of data"}, + + {10, 2, block_size, SCSI_RESIDUAL_OVERFLOW, block_size, true, + "Verify that if iSCSI EDTL < SCSI TL then we only write iSCSI EDTL amount of data"}, + }; + + unsigned int i = 0; logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test WRITE10 commands with residuals"); @@ -49,337 +62,21 @@ test_write10_residuals(void) CHECK_FOR_SBC; CHECK_FOR_ISCSI(sd); - /* Try a write10 of 1 block but xferlength == 0 */ - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE10; - task->cdb[8] = 1; - task->cdb_size = 10; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 0; - /* * we don't want autoreconnect since some targets will drop the session * on this condition. */ iscsi_set_noautoreconnect(sd->iscsi_ctx, 1); - logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==0"); + for (i = 0; i < ARRAY_SIZE(write10_residuals); i++) { + logging(LOG_VERBOSE, "\n%s", write10_residuals[i].log_messages); + write_residuals_test(&write10_residuals[i]); - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_CANCELLED); /* XXX redundant? */ - - 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] WRITE10 is not implemented."); - CU_PASS("WRITE10 is not implemented."); - return; - } - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got %zu bytes of residual overflow", - block_size); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - scsi_free_scsi_task(task); - task = NULL; - - /* in case the previous test failed the session */ - iscsi_set_noautoreconnect(sd->iscsi_ctx, 0); - - - logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==10000"); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE10; - task->cdb[8] = 1; - task->cdb_size = 10; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 10000; - - memset(buf, 0xa6, sizeof(buf)); - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual underflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "underflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_UNDERFLOW); - - logging(LOG_VERBOSE, "Verify we got %zu bytes of residual underflow", - 10000 - block_size); - if (task->residual != 10000 - block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - 10000 - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, 10000 - block_size); - scsi_free_scsi_task(task); - task = NULL; - - - logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==200"); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE10; - task->cdb[8] = 1; - task->cdb_size = 10; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 200; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got %zu bytes of residual overflow", - block_size - 200); - if (task->residual != block_size - 200) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size - 200, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size - 200); - - scsi_free_scsi_task(task); - task = NULL; - - - - logging(LOG_VERBOSE, "Try writing two blocks but iSCSI expected " - "transfer length==%zu (==one block)", block_size); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE10; - task->cdb[8] = 2; - task->cdb_size = 10; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = block_size; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got one block of residual overflow"); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - - scsi_free_scsi_task(task); - task = NULL; - - - - - logging(LOG_VERBOSE, "Verify that if iSCSI EDTL > SCSI TL then we only write SCSI TL amount of data"); - - logging(LOG_VERBOSE, "Write two blocks of 'a'"); - memset(buf, 'a', 10000); - WRITE10(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Write one block of 'b' but set iSCSI EDTL to 2 blocks."); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(buf, 'b', 10000); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE10; - task->cdb[8] = 1; - task->cdb_size = 10; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 2 * block_size; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual underflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "underflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_UNDERFLOW); - - logging(LOG_VERBOSE, "Verify we got one block of residual underflow"); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - scsi_free_scsi_task(task); - task = NULL; - - logging(LOG_VERBOSE, "Read the two blocks"); - READ10(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Verify that the first block was changed to 'b'"); - for (i = 0; i < block_size; i++) { - if (buf[i] != 'b') { - logging(LOG_NORMAL, "First block did not contain expected 'b'"); - CU_FAIL("Block was not written correctly"); - break; - } - } - - logging(LOG_VERBOSE, "Verify that the second block was NOT overwritten and still contains 'a'"); - for (i = block_size; i < 2 * block_size; i++) { - if (buf[i] != 'a') { - logging(LOG_NORMAL, "Second block was overwritten and no longer contain 'a'"); - CU_FAIL("Second block was incorrectly overwritten"); - break; - } - } - - - logging(LOG_VERBOSE, "Verify that if iSCSI EDTL < SCSI TL then we only write iSCSI EDTL amount of data"); - - logging(LOG_VERBOSE, "Write two blocks of 'a'"); - memset(buf, 'a', 10000); - WRITE10(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Write two blocks of 'b' but set iSCSI EDTL to 1 blocks."); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(buf, 'b', 10000); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE10; - task->cdb[8] = 2; - task->cdb_size = 10; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = block_size; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got one block of residual overflow"); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - scsi_free_scsi_task(task); - task = NULL; - - logging(LOG_VERBOSE, "Read the two blocks"); - READ10(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Verify that the first block was changed to 'b'"); - for (i = 0; i < block_size; i++) { - if (buf[i] != 'b') { - logging(LOG_NORMAL, "First block did not contain expected 'b'"); - CU_FAIL("Block was not written correctly"); - break; - } - } - - logging(LOG_VERBOSE, "Verify that the second block was NOT overwritten and still contains 'a'"); - for (i = block_size; i < 2 * block_size; i++) { - if (buf[i] != 'a') { - logging(LOG_NORMAL, "Second block was overwritten and no longer contain 'a'"); - CU_FAIL("Second block was incorrectly overwritten"); - break; + if (!command_is_implemented) { + CU_PASS("WRITE10 is not implemented."); + return; } + /* in case the previous test failed the session */ + iscsi_set_noautoreconnect(sd->iscsi_ctx, 0); } } diff --git a/test-tool/test_write12_residuals.c b/test-tool/test_write12_residuals.c index fb27f9d..bb27808 100644 --- a/test-tool/test_write12_residuals.c +++ b/test-tool/test_write12_residuals.c @@ -25,21 +25,34 @@ #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" - -static int check_status (struct scsi_task *task) { - return (task->status == SCSI_STATUS_GOOD || - (task->status == SCSI_STATUS_CHECK_CONDITION && - task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && - task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_INFORMATION_UNIT)); -} +#include "test_write_residuals.h" void test_write12_residuals(void) { - struct scsi_task *task_ret; - unsigned char buf[10000]; - struct iscsi_data data; - unsigned int i; + /* testing scenarios */ + const struct residuals_test_data write12_residuals[] = { + /* cdb_size, xfer_len, buf_len, residuals_kind, residuals_amount, check_overwrite */ + {12, 1, 0, SCSI_RESIDUAL_OVERFLOW, block_size, false, + "Try writing one block but with iSCSI expected transfer length==0"}, + + {12, 1, 10000, SCSI_RESIDUAL_UNDERFLOW, 10000 - block_size, false, + "Try writing one block but with iSCSI expected transfer length==10000"}, + + {12, 1, 200, SCSI_RESIDUAL_OVERFLOW, block_size - 200, false, + "Try writing one block but with iSCSI expected transfer length==200"}, + + {12, 2, block_size, SCSI_RESIDUAL_OVERFLOW, block_size, false, + "Try writing two blocks but iSCSI expected one block transfer length"}, + + {12, 1, 2 * block_size, SCSI_RESIDUAL_UNDERFLOW, block_size, true, + "Verify that if iSCSI EDTL > SCSI TL then we only write SCSI TL amount of data"}, + + {12, 2, block_size, SCSI_RESIDUAL_OVERFLOW, block_size, true, + "Verify that if iSCSI EDTL < SCSI TL then we only write iSCSI EDTL amount of data"}, + }; + + unsigned int i = 0; logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test WRITE12 commands with residuals"); @@ -49,336 +62,21 @@ test_write12_residuals(void) CHECK_FOR_SBC; CHECK_FOR_ISCSI(sd); - /* Try a write12 of 1 block but xferlength == 0 */ - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE12; - task->cdb[9] = 1; - task->cdb_size = 12; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 0; - /* * we don't want autoreconnect since some targets will drop the session * on this condition. */ iscsi_set_noautoreconnect(sd->iscsi_ctx, 1); - logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==0"); + for (i = 0; i < ARRAY_SIZE(write12_residuals); i++) { + logging(LOG_VERBOSE, "\n%s", write12_residuals[i].log_messages); + write_residuals_test(&write12_residuals[i]); - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_CANCELLED); /* XXX redundant? */ - - 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] WRITE12 is not implemented."); - CU_PASS("WRITE12 is not implemented."); - return; - } - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got %zu bytes of residual overflow", - block_size); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - scsi_free_scsi_task(task); - task = NULL; - - /* in case the previous test failed the session */ - iscsi_set_noautoreconnect(sd->iscsi_ctx, 0); - - - logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==10000"); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE12; - task->cdb[9] = 1; - task->cdb_size = 12; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 10000; - - memset(buf, 0xa6, sizeof(buf)); - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual underflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "underflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_UNDERFLOW); - - logging(LOG_VERBOSE, "Verify we got %zu bytes of residual underflow", - 10000 - block_size); - if (task->residual != 10000 - block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - 10000 - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, 10000 - block_size); - scsi_free_scsi_task(task); - task = NULL; - - - logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==200"); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE12; - task->cdb[9] = 1; - task->cdb_size = 12; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 200; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got %zu bytes of residual overflow", - block_size - 200); - if (task->residual != block_size - 200) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size - 200, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size - 200); - - scsi_free_scsi_task(task); - task = NULL; - - - - logging(LOG_VERBOSE, "Try writing two blocks but iSCSI expected " - "transfer length==%zu (==one block)", block_size); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE12; - task->cdb[9] = 2; - task->cdb_size = 12; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = block_size; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got one block of residual overflow"); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - - scsi_free_scsi_task(task); - task = NULL; - - - - logging(LOG_VERBOSE, "Verify that if iSCSI EDTL > SCSI TL then we only write SCSI TL amount of data"); - - logging(LOG_VERBOSE, "Write two blocks of 'a'"); - memset(buf, 'a', 10000); - WRITE12(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Write one block of 'b' but set iSCSI EDTL to 2 blocks."); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(buf, 'b', 10000); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE12; - task->cdb[9] = 1; - task->cdb_size = 12; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 2 * block_size; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual underflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "underflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_UNDERFLOW); - - logging(LOG_VERBOSE, "Verify we got one block of residual underflow"); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - scsi_free_scsi_task(task); - task = NULL; - - logging(LOG_VERBOSE, "Read the two blocks"); - READ12(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Verify that the first block was changed to 'b'"); - for (i = 0; i < block_size; i++) { - if (buf[i] != 'b') { - logging(LOG_NORMAL, "First block did not contain expected 'b'"); - CU_FAIL("Block was not written correctly"); - break; - } - } - - logging(LOG_VERBOSE, "Verify that the second block was NOT overwritten and still contains 'a'"); - for (i = block_size; i < 2 * block_size; i++) { - if (buf[i] != 'a') { - logging(LOG_NORMAL, "Second block was overwritten and no longer contain 'a'"); - CU_FAIL("Second block was incorrectly overwritten"); - break; - } - } - - - logging(LOG_VERBOSE, "Verify that if iSCSI EDTL < SCSI TL then we only write iSCSI EDTL amount of data"); - - logging(LOG_VERBOSE, "Write two blocks of 'a'"); - memset(buf, 'a', 10000); - WRITE12(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Write two blocks of 'b' but set iSCSI EDTL to 1 blocks."); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(buf, 'b', 10000); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE12; - task->cdb[9] = 2; - task->cdb_size = 12; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = block_size; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got one block of residual overflow"); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - scsi_free_scsi_task(task); - task = NULL; - - logging(LOG_VERBOSE, "Read the two blocks"); - READ12(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Verify that the first block was changed to 'b'"); - for (i = 0; i < block_size; i++) { - if (buf[i] != 'b') { - logging(LOG_NORMAL, "First block did not contain expected 'b'"); - CU_FAIL("Block was not written correctly"); - break; - } - } - - logging(LOG_VERBOSE, "Verify that the second block was NOT overwritten and still contains 'a'"); - for (i = block_size; i < 2 * block_size; i++) { - if (buf[i] != 'a') { - logging(LOG_NORMAL, "Second block was overwritten and no longer contain 'a'"); - CU_FAIL("Second block was incorrectly overwritten"); - break; + if (!command_is_implemented) { + CU_PASS("WRITE12 is not implemented."); + return; } + /* in case the previous test failed the session */ + iscsi_set_noautoreconnect(sd->iscsi_ctx, 0); } } diff --git a/test-tool/test_write16_residuals.c b/test-tool/test_write16_residuals.c index 3e48d85..c4a7139 100644 --- a/test-tool/test_write16_residuals.c +++ b/test-tool/test_write16_residuals.c @@ -25,21 +25,34 @@ #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" - -static int check_status (struct scsi_task *task) { - return (task->status == SCSI_STATUS_GOOD || - (task->status == SCSI_STATUS_CHECK_CONDITION && - task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && - task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_INFORMATION_UNIT)); -} +#include "test_write_residuals.h" void test_write16_residuals(void) { - struct scsi_task *task_ret; - unsigned char buf[10000]; - struct iscsi_data data; - unsigned int i; + /* testing scenarios */ + const struct residuals_test_data write16_residuals[] = { + /* cdb_size, xfer_len, buf_len, residuals_kind, residuals_amount, check_overwrite */ + {16, 1, 0, SCSI_RESIDUAL_OVERFLOW, block_size, false, + "Try writing one block but with iSCSI expected transfer length==0"}, + + {16, 1, 10000, SCSI_RESIDUAL_UNDERFLOW, 10000 - block_size, false, + "Try writing one block but with iSCSI expected transfer length==10000"}, + + {16, 1, 200, SCSI_RESIDUAL_OVERFLOW, block_size - 200, false, + "Try writing one block but with iSCSI expected transfer length==200"}, + + {16, 2, block_size, SCSI_RESIDUAL_OVERFLOW, block_size, false, + "Try writing two blocks but iSCSI expected one block transfer length"}, + + {16, 1, 2 * block_size, SCSI_RESIDUAL_UNDERFLOW, block_size, true, + "Verify that if iSCSI EDTL > SCSI TL then we only write SCSI TL amount of data"}, + + {16, 2, block_size, SCSI_RESIDUAL_OVERFLOW, block_size, true, + "Verify that if iSCSI EDTL < SCSI TL then we only write iSCSI EDTL amount of data"}, + }; + + unsigned int i = 0; logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test WRITE16 commands with residuals"); @@ -49,336 +62,21 @@ test_write16_residuals(void) CHECK_FOR_SBC; CHECK_FOR_ISCSI(sd); - /* Try a write16 of 1 block but xferlength == 0 */ - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE16; - task->cdb[13] = 1; - task->cdb_size = 16; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 0; - /* * we don't want autoreconnect since some targets will drop the session * on this condition. */ iscsi_set_noautoreconnect(sd->iscsi_ctx, 1); - logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==0"); + for (i = 0; i < ARRAY_SIZE(write16_residuals); i++) { + logging(LOG_VERBOSE, "\n%s", write16_residuals[i].log_messages); + write_residuals_test(&write16_residuals[i]); - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_CANCELLED); /* XXX redundant? */ - - 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] WRITE16 is not implemented."); - CU_PASS("WRITE16 is not implemented."); - return; - } - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got %zu bytes of residual overflow", - block_size); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - scsi_free_scsi_task(task); - task = NULL; - - /* in case the previous test failed the session */ - iscsi_set_noautoreconnect(sd->iscsi_ctx, 0); - - - logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==10000"); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE16; - task->cdb[13] = 1; - task->cdb_size = 16; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 10000; - - memset(buf, 0xa6, sizeof(buf)); - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual underflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "underflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_UNDERFLOW); - - logging(LOG_VERBOSE, "Verify we got %zu bytes of residual underflow", - 10000 - block_size); - if (task->residual != 10000 - block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - 10000 - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, 10000 - block_size); - scsi_free_scsi_task(task); - task = NULL; - - - logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==200"); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE16; - task->cdb[13] = 1; - task->cdb_size = 16; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 200; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got %zu bytes of residual overflow", - block_size - 200); - if (task->residual != block_size - 200) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size - 200, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size - 200); - - scsi_free_scsi_task(task); - task = NULL; - - - - logging(LOG_VERBOSE, "Try writing two blocks but iSCSI expected " - "transfer length==%zu (==one block)", block_size); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE16; - task->cdb[13] = 2; - task->cdb_size = 16; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = block_size; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got one block of residual overflow"); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - - scsi_free_scsi_task(task); - task = NULL; - - - - logging(LOG_VERBOSE, "Verify that if iSCSI EDTL > SCSI TL then we only write SCSI TL amount of data"); - - logging(LOG_VERBOSE, "Write two blocks of 'a'"); - memset(buf, 'a', 10000); - WRITE16(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Write one block of 'b' but set iSCSI EDTL to 2 blocks."); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(buf, 'b', 10000); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE16; - task->cdb[13] = 1; - task->cdb_size = 16; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = 2 * block_size; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual underflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "underflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_UNDERFLOW); - - logging(LOG_VERBOSE, "Verify we got one block of residual underflow"); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - scsi_free_scsi_task(task); - task = NULL; - - logging(LOG_VERBOSE, "Read the two blocks"); - READ16(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Verify that the first block was changed to 'b'"); - for (i = 0; i < block_size; i++) { - if (buf[i] != 'b') { - logging(LOG_NORMAL, "First block did not contain expected 'b'"); - CU_FAIL("Block was not written correctly"); - break; - } - } - - logging(LOG_VERBOSE, "Verify that the second block was NOT overwritten and still contains 'a'"); - for (i = block_size; i < 2 * block_size; i++) { - if (buf[i] != 'a') { - logging(LOG_NORMAL, "Second block was overwritten and no longer contain 'a'"); - CU_FAIL("Second block was incorrectly overwritten"); - break; - } - } - - - logging(LOG_VERBOSE, "Verify that if iSCSI EDTL < SCSI TL then we only write iSCSI EDTL amount of data"); - - logging(LOG_VERBOSE, "Write two blocks of 'a'"); - memset(buf, 'a', 10000); - WRITE16(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Write two blocks of 'b' but set iSCSI EDTL to 1 blocks."); - task = malloc(sizeof(struct scsi_task)); - CU_ASSERT_PTR_NOT_NULL_FATAL(task); - - memset(buf, 'b', 10000); - - memset(task, 0, sizeof(struct scsi_task)); - task->cdb[0] = SCSI_OPCODE_WRITE16; - task->cdb[13] = 2; - task->cdb_size = 16; - task->xfer_dir = SCSI_XFER_WRITE; - task->expxferlen = block_size; - - data.size = task->expxferlen; - data.data = &buf[0]; - task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); - CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); - - logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); - if (!check_status(task)) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT(check_status(task)); - - logging(LOG_VERBOSE, "Verify residual overflow flag is set"); - if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { - logging(LOG_VERBOSE, "[FAILED] Target did not set residual " - "overflow flag"); - } - CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); - - logging(LOG_VERBOSE, "Verify we got one block of residual overflow"); - if (task->residual != block_size) { - logging(LOG_VERBOSE, "[FAILED] Target did not set correct " - "amount of residual. Expected %zu but got %zu.", - block_size, task->residual); - } - CU_ASSERT_EQUAL(task->residual, block_size); - scsi_free_scsi_task(task); - task = NULL; - - logging(LOG_VERBOSE, "Read the two blocks"); - READ16(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, buf, - EXPECT_STATUS_GOOD); - - logging(LOG_VERBOSE, "Verify that the first block was changed to 'b'"); - for (i = 0; i < block_size; i++) { - if (buf[i] != 'b') { - logging(LOG_NORMAL, "First block did not contain expected 'b'"); - CU_FAIL("Block was not written correctly"); - break; - } - } - - logging(LOG_VERBOSE, "Verify that the second block was NOT overwritten and still contains 'a'"); - for (i = block_size; i < 2 * block_size; i++) { - if (buf[i] != 'a') { - logging(LOG_NORMAL, "Second block was overwritten and no longer contain 'a'"); - CU_FAIL("Second block was incorrectly overwritten"); - break; + if (!command_is_implemented) { + CU_PASS("WRITE16 is not implemented."); + return; } + /* in case the previous test failed the session */ + iscsi_set_noautoreconnect(sd->iscsi_ctx, 0); } } diff --git a/test-tool/test_write_residuals.c b/test-tool/test_write_residuals.c new file mode 100644 index 0000000..ea72478 --- /dev/null +++ b/test-tool/test_write_residuals.c @@ -0,0 +1,182 @@ +/* + Copyright (C) 2013 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include + +#include + +#include "iscsi.h" +#include "iscsi-private.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" +#include "test_write_residuals.h" + +bool command_is_implemented = true; + +void +write_residuals_test(const struct residuals_test_data *tdata) +{ + struct iscsi_data data; + struct scsi_task *task_ret; + int ok; + unsigned int xfer_len_byte = 8; + unsigned int i; + unsigned int scsi_opcode_write = SCSI_OPCODE_WRITE10; + const char *residual = tdata->residuals_kind == SCSI_RESIDUAL_OVERFLOW ? "overflow" : "underflow"; + + switch (tdata->cdb_size) { + case 10: + scsi_opcode_write = SCSI_OPCODE_WRITE10; + xfer_len_byte = 8; + break; + case 12: + scsi_opcode_write = SCSI_OPCODE_WRITE12; + xfer_len_byte = 9; + break; + case 16: + scsi_opcode_write = SCSI_OPCODE_WRITE16; + xfer_len_byte = 13; + break; + } + + if (tdata->check_overwrite) { + logging(LOG_VERBOSE, "Write two blocks of 'a'"); + memset(scratch, 'a', (2 * block_size)); + + switch (tdata->cdb_size) { + case 10: + WRITE10(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, scratch, EXPECT_STATUS_GOOD); + break; + case 12: + WRITE12(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, scratch, EXPECT_STATUS_GOOD); + break; + case 16: + WRITE16(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, scratch, EXPECT_STATUS_GOOD); + break; + } + + logging(LOG_VERBOSE, "Write %u block(s) of 'b' but set iSCSI EDTL to %u block(s).", + tdata->xfer_len, + tdata->xfer_len % 2 + 1); + } + + task = malloc(sizeof(*task)); + CU_ASSERT_PTR_NOT_NULL_FATAL(task); + memset(task, 0, sizeof(*task)); + + if (tdata->check_overwrite) { + memset(scratch, 'b', tdata->buf_len); + } else { + memset(scratch, 0xa6, tdata->buf_len); + } + + task->cdb[0] = scsi_opcode_write; + task->cdb[xfer_len_byte] = tdata->xfer_len; + task->cdb_size = tdata->cdb_size; + task->xfer_dir = SCSI_XFER_WRITE; + task->expxferlen = tdata->buf_len; + data.size = task->expxferlen; + data.data = &scratch[0]; + + task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, + task, tdata->buf_len == 0 ? NULL : &data); + CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_CANCELLED); + + 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] WRITE%zu is not implemented.", tdata->cdb_size); + command_is_implemented = false; + return; + } + + logging(LOG_VERBOSE, "Verify that target returns SUCCESS or INVALID " + "FIELD IN INFORMATION UNIT"); + ok = task->status == SCSI_STATUS_GOOD || + (task->status == SCSI_STATUS_CHECK_CONDITION && + task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && + task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_INFORMATION_UNIT); + if (!ok) { + logging(LOG_VERBOSE, "[FAILED] Target returned error %s", + iscsi_get_error(sd->iscsi_ctx)); + } + CU_ASSERT(ok); + + logging(LOG_VERBOSE, "Verify residual %s flag is set", residual); + if (task->residual_status != tdata->residuals_kind) { + logging(LOG_VERBOSE, "[FAILED] Target did not set residual " + "%s flag", residual); + } + CU_ASSERT_EQUAL(task->residual_status, tdata->residuals_kind); + + logging(LOG_VERBOSE, "Verify we got %zu bytes of residual %s", + tdata->residuals_amount, residual); + if (task->residual != tdata->residuals_amount) { + logging(LOG_VERBOSE, "[FAILED] Target did not set correct " + "amount of residual. Expected %zu but got %zu.", + tdata->residuals_amount, task->residual); + } + CU_ASSERT_EQUAL(task->residual, tdata->residuals_amount); + scsi_free_scsi_task(task); + task = NULL; + + if (!tdata->check_overwrite) { + return; + } + + logging(LOG_VERBOSE, "Read the two blocks"); + switch (tdata->cdb_size) { + case 10: + READ10(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, + scratch, EXPECT_STATUS_GOOD); + break; + case 12: + READ12(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, + scratch, EXPECT_STATUS_GOOD); + break; + case 16: + READ16(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, + scratch, EXPECT_STATUS_GOOD); + break; + } + + logging(LOG_VERBOSE, "Verify that the first block was changed to 'b'"); + for (i = 0; i < block_size; i++) { + if (scratch[i] != 'b') { + logging(LOG_NORMAL, "First block did not contain " + "expected 'b'"); + CU_FAIL("Block was not written correctly"); + break; + } + } + + logging(LOG_VERBOSE, "Verify that the second block was NOT " + "overwritten and still contains 'a'"); + for (i = block_size; i < 2 * block_size; i++) { + if (scratch[i] != 'a') { + logging(LOG_NORMAL, "Second block was overwritten " + "and no longer contain 'a'"); + CU_FAIL("Second block was incorrectly overwritten"); + break; + } + } + return; +} diff --git a/test-tool/test_write_residuals.h b/test-tool/test_write_residuals.h new file mode 100644 index 0000000..3c38140 --- /dev/null +++ b/test-tool/test_write_residuals.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2013 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef _ISCSI_TESTS_WRITE_RESIDUALS_H_ +#define _ISCSI_TESTS_WRITE_RESIDUALS_H_ + +#include +#include + +struct residuals_test_data { + size_t cdb_size; /* The size of CDB in bytes */ + + unsigned int xfer_len; /* The number of logical blocks of + data that shall be transferred */ + + unsigned int buf_len; /* Expected Data Transfer Length */ + + unsigned int residuals_kind; /* Overflow or Underflow as in + enum scsi_residual */ + + size_t residuals_amount; /* The amount of residual data in bytes */ + + bool check_overwrite; /* Whether the test checks for overwrite or not */ + + const char *log_messages; /* Test case description */ +}; + +extern bool command_is_implemented; +extern void write_residuals_test (const struct residuals_test_data *tdata); + +#endif /* _ISCSI_TESTS_WRITE_RESIDUALS_H_ */