Merge pull request #345 from nastya-nizharadze/residuals-tests-fix2
Improve WriteResidual tests
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
246
test-tool/test_write_residuals.c
Normal file
246
test-tool/test_write_residuals.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
48
test-tool/test_write_residuals.h
Normal file
48
test-tool/test_write_residuals.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ISCSI_TESTS_WRITE_RESIDUALS_H_
|
||||
#define _ISCSI_TESTS_WRITE_RESIDUALS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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_ */
|
||||
Reference in New Issue
Block a user