diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 1c4a0f5..f93b801 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -37,6 +37,12 @@ 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 +#ifndef DIV_ROUND_UP +#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) +#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 911c39c..67ea3ff 100644 --- a/test-tool/test_write10_residuals.c +++ b/test-tool/test_write10_residuals.c @@ -25,16 +25,31 @@ #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" - +#include "test_write_residuals.h" void test_write10_residuals(void) { - struct scsi_task *task_ret; - unsigned char buf[10000]; - struct iscsi_data data; - int ok; - unsigned int i; + /* testing scenarios */ + const struct residuals_test_data write10_residuals[] = { + /* cdb_size, xfer_len, buf_len, residuals_kind, residuals_amount */ + {10, 1, 0, SCSI_RESIDUAL_OVERFLOW, block_size, + "Try writing one block but with iSCSI expected transfer length==0"}, + + {10, 1, 2 * block_size, SCSI_RESIDUAL_UNDERFLOW, block_size, + "Try writing one block but set iSCSI EDTL to 2 blocks"}, + + {10, 2, block_size, SCSI_RESIDUAL_OVERFLOW, block_size, + "Try writing two blocks but set iSCSI EDTL to 1 block"}, + + {10, 1, 10000, SCSI_RESIDUAL_UNDERFLOW, 10000 - block_size, + "Try writing one block but with iSCSI expected transfer length==10000"}, + + {10, 1, 200, SCSI_RESIDUAL_OVERFLOW, block_size - 200, + "Try writing one block but with iSCSI expected transfer length==200"}, + }; + + unsigned int i = 0; logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test WRITE10 commands with residuals"); @@ -44,341 +59,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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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"); - 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 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 02819ba..23ae0c9 100644 --- a/test-tool/test_write12_residuals.c +++ b/test-tool/test_write12_residuals.c @@ -25,16 +25,31 @@ #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" - +#include "test_write_residuals.h" void test_write12_residuals(void) { - struct scsi_task *task_ret; - unsigned char buf[10000]; - struct iscsi_data data; - int ok; - unsigned int i; + /* testing scenarios */ + const struct residuals_test_data write12_residuals[] = { + /* cdb_size, xfer_len, buf_len, residuals_kind, residuals_amount */ + {12, 1, 0, SCSI_RESIDUAL_OVERFLOW, block_size, + "Try writing one block but with iSCSI expected transfer length==0"}, + + {12, 1, 2 * block_size, SCSI_RESIDUAL_UNDERFLOW, block_size, + "Try writing one block but set iSCSI EDTL to 2 blocks"}, + + {12, 2, block_size, SCSI_RESIDUAL_OVERFLOW, block_size, + "Try writing two blocks but set iSCSI EDTL to 1 block"}, + + {12, 1, 10000, SCSI_RESIDUAL_UNDERFLOW, 10000 - block_size, + "Try writing one block but with iSCSI expected transfer length==10000"}, + + {12, 1, 200, SCSI_RESIDUAL_OVERFLOW, block_size - 200, + "Try writing one block but with iSCSI expected transfer length==200"}, + }; + + unsigned int i = 0; logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test WRITE12 commands with residuals"); @@ -44,340 +59,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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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"); - 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 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 7088cac..b3f6979 100644 --- a/test-tool/test_write16_residuals.c +++ b/test-tool/test_write16_residuals.c @@ -25,16 +25,31 @@ #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" - +#include "test_write_residuals.h" void test_write16_residuals(void) { - struct scsi_task *task_ret; - unsigned char buf[10000]; - struct iscsi_data data; - int ok; - unsigned int i; + /* testing scenarios */ + const struct residuals_test_data write16_residuals[] = { + /* cdb_size, xfer_len, buf_len, residuals_kind, residuals_amount */ + {16, 1, 0, SCSI_RESIDUAL_OVERFLOW, block_size, + "Try writing one block but with iSCSI expected transfer length==0"}, + + {16, 1, 2 * block_size, SCSI_RESIDUAL_UNDERFLOW, block_size, + "Try writing one block but set iSCSI EDTL to 2 blocks"}, + + {16, 2, block_size, SCSI_RESIDUAL_OVERFLOW, block_size, + "Try writing two blocks but set iSCSI EDTL to 1 block"}, + + {16, 1, 10000, SCSI_RESIDUAL_UNDERFLOW, 10000 - block_size, + "Try writing one block but with iSCSI expected transfer length==10000"}, + + {16, 1, 200, SCSI_RESIDUAL_OVERFLOW, block_size - 200, + "Try writing one block but with iSCSI expected transfer length==200"}, + }; + + unsigned int i = 0; logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test WRITE16 commands with residuals"); @@ -44,340 +59,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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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"); - 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 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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 (task->status != SCSI_STATUS_GOOD) { - logging(LOG_VERBOSE, "[FAILED] Target returned error %s", - iscsi_get_error(sd->iscsi_ctx)); - } - CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); - - 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..cdfa031 --- /dev/null +++ b/test-tool/test_write_residuals.c @@ -0,0 +1,246 @@ +/* + 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; + struct task_status status; + int ok; + unsigned int expected_write_size; + unsigned int max_len; + unsigned int xfer_len_byte = 8; + unsigned int i; + unsigned int transfer_length; + 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->xfer_len * block_size > tdata->buf_len) /* SPDTL > EDTL */ { + /* Transfer has to be truncated up to EDTL */ + expected_write_size = tdata->buf_len; + max_len = (tdata->xfer_len * block_size); + } else /* SPDTL <= EDTL */ { + /* Transfer has to be truncated up to SPDTL */ + expected_write_size = (tdata->xfer_len * block_size); + max_len = tdata->buf_len; + } + transfer_length = DIV_ROUND_UP(max_len, block_size) * block_size; + + logging(LOG_VERBOSE, "Write %ld block(s) of 'a'", transfer_length / block_size); + memset(scratch, 'a', transfer_length); + + switch (tdata->cdb_size) { + case 10: + WRITE10(sd, 0, transfer_length, block_size, 0, 0, 0, 0, 0, + scratch, EXPECT_STATUS_GOOD); + break; + case 12: + WRITE12(sd, 0, transfer_length, block_size, 0, 0, 0, 0, 0, + scratch, EXPECT_STATUS_GOOD); + break; + case 16: + WRITE16(sd, 0, transfer_length, block_size, 0, 0, 0, 0, 0, + scratch, EXPECT_STATUS_GOOD); + break; + } + + task = malloc(sizeof(*task)); + CU_ASSERT_PTR_NOT_NULL_FATAL(task); + memset(task, 0, sizeof(*task)); + + logging(LOG_VERBOSE, "Write 'b' with the transfer length " + "being set to %d block(s)", tdata->xfer_len); + memset(scratch, 'b', 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; + scsi_free_scsi_task(task); + task = NULL; + return; + } + + logging(LOG_VERBOSE, "Verify that target returns SUCCESS or INVALID " + "FIELD IN INFORMATION UNIT"); + + status.status = task->status; + status.sense.key = task->sense.key; + status.sense.ascq = task->sense.ascq; + + 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; + + logging(LOG_VERBOSE, "Read %ld block(s)", transfer_length / block_size); + switch (tdata->cdb_size) { + case 10: + READ10(sd, NULL, 0, transfer_length, block_size, + 0, 0, 0, 0, 0, scratch, EXPECT_STATUS_GOOD); + break; + case 12: + READ12(sd, NULL, 0, transfer_length, block_size, + 0, 0, 0, 0, 0, scratch, EXPECT_STATUS_GOOD); + break; + case 16: + READ16(sd, NULL, 0, transfer_length, block_size, + 0, 0, 0, 0, 0, scratch, EXPECT_STATUS_GOOD); + break; + } + + /* According to FCP-4: + If the command requested that data beyond the length specified by + the FCP_DL field be transferred, then the device server shall set + the FCP_RESID_OVER bit (see 9.5.8) to one in the FCP_RSP IU and: + + a) process the command normally except that data beyond the FCP_DL + count shall not be requested or transferred; */ + + if (status.status == SCSI_STATUS_GOOD) { + + switch (tdata->residuals_kind) { + case SCSI_RESIDUAL_OVERFLOW: + logging(LOG_VERBOSE, "Verify that if iSCSI EDTL < SCSI TL " + "then we only write iSCSI EDTL amount of data"); + break; + case SCSI_RESIDUAL_UNDERFLOW: + logging(LOG_VERBOSE, "Verify that if iSCSI EDTL > SCSI TL " + "then we only write SCSI TL amount of data"); + break; + } + + logging(LOG_VERBOSE, "Verify that the first %d bytes were " + "changed to 'b'", expected_write_size); + for (i = 0; i < expected_write_size; i++) { + if (scratch[i] != 'b') { + logging(LOG_NORMAL, "Blocks did not contain " + "expected 'b'"); + CU_FAIL("Blocks was not written correctly"); + break; + } + } + + /* b) transfer no data and return CHECK CONDITION status with the sense + key set to ILLEGAL REQUEST and the additional sense code set to + INVALID FIELD IN COMMAND INFORMATION UNIT; */ + + } else if (status.status == SCSI_STATUS_CHECK_CONDITION && + status.sense.key == SCSI_SENSE_ILLEGAL_REQUEST && + status.sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_INFORMATION_UNIT) { + + logging(LOG_VERBOSE, "Verify that first %d bytes were NOT " + "overwritten and still contain 'a'", expected_write_size); + for (i = 0; i < expected_write_size; i++) { + if (scratch[i] != 'a') { + logging(LOG_NORMAL, "Blocks were overwritten " + "and no longer contain 'a'"); + CU_FAIL("Blocks were incorrectly overwritten"); + break; + } + } + } + + /* c) may transfer data and return CHECK CONDITION status with the + sense key set to ABORTED COMMAND and the additional sense code + set to INVALID FIELD IN COMMAND INFORMATION UNIT. + + (not implemented yet) */ + + /* Regardless of the executed target scenario, data beyond expected + truncation point should not be overwritten */ + + logging(LOG_VERBOSE, "Verify that the last %ld bytes were NOT " + "overwritten and still contain 'a'", tdata->residuals_amount); + for (i = expected_write_size; i < max_len; i++) { + if (scratch[i] != 'a') { + logging(LOG_NORMAL, "Data was overwritten " + "and no longer contain 'a'"); + CU_FAIL("Data 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..96c8736 --- /dev/null +++ b/test-tool/test_write_residuals.h @@ -0,0 +1,48 @@ +/* + 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 */ + + const char *log_messages; /* Test case description */ +}; + +struct task_status { + int status; + struct scsi_sense sense; +}; + +extern bool command_is_implemented; +extern void write_residuals_test (const struct residuals_test_data *tdata); + +#endif /* _ISCSI_TESTS_WRITE_RESIDUALS_H_ */