Example #1
0
void test_iscsi_cmdsn_toolow(void)
{ 
	int ret;

	logging(LOG_VERBOSE, LOG_BLANK_LINE);
	logging(LOG_VERBOSE, "Test sending invalid iSCSI CMDSN");
	logging(LOG_VERBOSE, "CMDSN MUST be in the range EXPCMDSN and MAXCMDSN");

	logging(LOG_VERBOSE, "RFC3720:3.2.2.1 CMDSN < EXPCMDSN must be silently ignored by the target");
	logging(LOG_VERBOSE, "Send a TESTUNITREADY with CMDSN == EXPCMDSN-1. Should be ignored by the target.");

	iscsic->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO;
	iscsic->target_max_recv_data_segment_length = block_size;
	local_iscsi_queue_pdu = my_iscsi_queue_pdu;
	change_cmdsn = 1;
	/* we don't want autoreconnect since some targets will incorrectly
	 * drop the connection on this condition.
	 */
	iscsi_set_noautoreconnect(iscsic, 1);
	iscsi_set_timeout(iscsic, 3);

	ret = testunitready(iscsic, tgt_lun);
	CU_ASSERT_EQUAL(ret, -1);
	if (ret == -1) {
		logging(LOG_VERBOSE, "[SUCCESS] We did not receive a reply");
	} else {
		logging(LOG_VERBOSE, "[FAILURE] We got a response from the target but SMDSN was outside of the window.");
	}

	

	iscsi_set_noautoreconnect(iscsic, 0);
	logging(LOG_VERBOSE, "Send a TESTUNITREADY with CMDSN == EXPCMDSN. should work again");
	ret = testunitready(iscsic, tgt_lun);
	CU_ASSERT_EQUAL(ret, 0);

}
void
test_write16_residuals(void)
{
        struct scsi_task *task_ret;
        unsigned char buf[10000];
        struct iscsi_data data;
        int ok;
        unsigned int i;

        logging(LOG_VERBOSE, LOG_BLANK_LINE);
        logging(LOG_VERBOSE, "Test WRITE16 commands with residuals");
        logging(LOG_VERBOSE, "Block size is %zu", block_size);

        CHECK_FOR_DATALOSS;
        CHECK_FOR_SBC;

        if (sd->iscsi_ctx == NULL) {
                const char *err = "[SKIPPED] This WRITE16 test is only "
                        "supported for iSCSI backends";
                logging(LOG_NORMAL, "%s", err);
                CU_PASS(err);
                return;
        }

        /* 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");

        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;
                }
        }
}
Example #3
0
void
test_read10_invalid(void)
{
	struct iscsi_data data;
	char *buf = alloca(block_size);
	struct scsi_task *task_ret;

	logging(LOG_VERBOSE, LOG_BLANK_LINE);
	logging(LOG_VERBOSE, "Test invalid READ10 commands");
	logging(LOG_VERBOSE, "Block size is %zu", block_size);

	/* Try a read10 of 1 block but xferlength == 0 */
	task = malloc(sizeof(struct scsi_task));
	CU_ASSERT_PTR_NOT_NULL(task);

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 1;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = 0;

	/*
	 * we don't want autoreconnect since some targets will drop the session
	 * on this condition.
	 */
	iscsi_set_noautoreconnect(iscsic, 1);


	logging(LOG_VERBOSE, "Try reading one block but with iSCSI expected transfer length==0");

	task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL);
	CU_ASSERT_PTR_NOT_NULL(task_ret);
	CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_CANCELLED); /* XXX redundant? */

	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(iscsic));
	}
	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(iscsic, 0);


	logging(LOG_VERBOSE, "Try reading one block but with iSCSI expected transfer length==10000");
	task = malloc(sizeof(struct scsi_task));
	CU_ASSERT_PTR_NOT_NULL(task);

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 1;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = 10000;

	task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL);
	CU_ASSERT_PTR_NOT_NULL(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(iscsic));
	}
	CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD);

	logging(LOG_VERBOSE, "Verify we got a whole block back from the target");
	CU_ASSERT_EQUAL(task->datain.size, (int)block_size);

	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 reading one block but with iSCSI expected transfer length==200");
	task = malloc(sizeof(struct scsi_task));
	CU_ASSERT_PTR_NOT_NULL(task);

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 1;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = 200;

	task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL);
	CU_ASSERT_PTR_NOT_NULL(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(iscsic));
	}
	CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD);

	logging(LOG_VERBOSE, "Verify we got 200 bytes back from the target");
	CU_ASSERT_EQUAL(task->datain.size, 200);

	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 reading two blocks but iSCSI expected "
		"transfer length==%zu (==one block)", block_size);
	task = malloc(sizeof(struct scsi_task));
	CU_ASSERT_PTR_NOT_NULL(task);

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 2;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = block_size;

	task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL);
	CU_ASSERT_PTR_NOT_NULL(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(iscsic));
	}
	CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD);

	logging(LOG_VERBOSE, "Verify we got one whole block back from the target");
	CU_ASSERT_EQUAL(task->datain.size, (int)block_size);

	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, "Try READ10 for one block but flag it as a write on the iSCSI layer.");
	task = malloc(sizeof(struct scsi_task));
	CU_ASSERT_PTR_NOT_NULL(task);

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 1;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_WRITE;
	task->expxferlen = block_size;

	data.size = block_size;
	data.data = (unsigned char *)buf;

	iscsi_set_noautoreconnect(iscsic, 1);
	iscsi_set_timeout(iscsic, 3);
	task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, &data);
	iscsi_set_noautoreconnect(iscsic, 0);
	CU_ASSERT_PTR_NOT_NULL(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(iscsic));
	}
	CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD);
	scsi_free_scsi_task(task);
	task = NULL;

}
Example #4
0
void
test_read16_residuals(void)
{
	struct scsi_task *task_ret;

	logging(LOG_VERBOSE, LOG_BLANK_LINE);
	logging(LOG_VERBOSE, "Test READ16 commands with residuals");
	logging(LOG_VERBOSE, "Block size is %zu", block_size);

	if (sd->iscsi_ctx == NULL) {
		const char *err = "[SKIPPED] This READ16 test is only "
			"supported for iSCSI backends";
		logging(LOG_NORMAL, "%s", err);
		CU_PASS(err);
		return;
	}

	task = malloc(sizeof(struct scsi_task));
	CU_ASSERT_PTR_NOT_NULL(task);

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ16;
	task->cdb[13] = 1;
	task->cdb_size = 16;
	task->xfer_dir = SCSI_XFER_READ;
	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 reading one block but with iSCSI expected transfer length==0");

	task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, NULL);
	CU_ASSERT_PTR_NOT_NULL(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] READ16 is not implemented on this target and it does not claim SBC-3 support.");
		CU_PASS("READ16 is not implemented and no SBC-3 support claimed.");
		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 reading one block but with iSCSI expected transfer length==10000");
	task = malloc(sizeof(struct scsi_task));
	CU_ASSERT_PTR_NOT_NULL(task);

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ16;
	task->cdb[13] = 1;
	task->cdb_size = 16;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = 10000;

	task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, NULL);
	CU_ASSERT_PTR_NOT_NULL(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 we got one whole block back from the target");
	if (task->datain.size != (int)block_size) {
		logging(LOG_VERBOSE, "[FAILED] Target returned %u bytes "
			"of data but should have returned %zu bytes.",
			task->datain.size,block_size);
	}
	CU_ASSERT_EQUAL(task->datain.size, (int)block_size);

	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 reading one block but with iSCSI expected transfer length==200");
	task = malloc(sizeof(struct scsi_task));
	CU_ASSERT_PTR_NOT_NULL(task);

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ16;
	task->cdb[13] = 1;
	task->cdb_size = 16;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = 200;

	task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, NULL);
	CU_ASSERT_PTR_NOT_NULL(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 we got 200 bytes back from the target");
	CU_ASSERT_EQUAL(task->datain.size, 200);

	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 reading two blocks but iSCSI expected "
		"transfer length==%zu (==one block)", block_size);
	task = malloc(sizeof(struct scsi_task));
	CU_ASSERT_PTR_NOT_NULL(task);

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ16;
	task->cdb[13] = 2;
	task->cdb_size = 16;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = block_size;

	task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, NULL);
	CU_ASSERT_PTR_NOT_NULL(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 we got one whole block back from the target");
	CU_ASSERT_EQUAL(task->datain.size, (int)block_size);

	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;
}
Example #5
0
int T0105_read10_invalid(const char *initiator, const char *url)
{
	struct iscsi_context *iscsi;
	struct scsi_task *task;
	struct iscsi_data data;
	char buf[4096];
	int ret, lun;

	printf("0105_read10_invalid:\n");
	printf("=======================\n");
	if (show_info) {
		printf("Test various protocol violations.\n");
		printf("1, Read 1 block but set xferlength to 0. Should result in residual overflow of 'block_size' bytes.\n");
		printf("2, Read 1 block but set xferlength to 2*'block_size'. Should result in residual underflow of 'block_size' bytes.\n");
		printf("3, Read 1 block but set xferlength to 200. Should result in residual overflow of 'block_size'-200 bytes.\n");
		printf("4, Read 2 blocks but set xferlength to 'block_size'. Should result in residual overflow of 'block_size' bytes.\n");
		printf("5, Read 1 block but send one block as data-out write on the iSCSI level. Should result in both residual overflow and underflow of 'block_size' bytes.\n");
		printf("\n");
		return 0;
	}

	iscsi = iscsi_context_login(initiator, url, &lun);
	if (iscsi == NULL) {
		printf("Failed to login to target\n");
		return -1;
	}

	ret = 0;


	/* Try a read of 1 block but xferlength == 0 */
	printf("Read10 1 block but with iscsi ExpectedDataTransferLength==0 ... ");

	task = malloc(sizeof(struct scsi_task));
	if (task == NULL) {
		printf("Failed to allocate task structure\n");
		ret = -1;
		goto finished;
	}

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 1;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = 0;

	/* we don't want autoreconnect since some targets will drop the session
	 * on this condition.
	 */
	iscsi_set_noautoreconnect(iscsi, 1);

	if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) {
	        printf("[FAILED]\n");
		printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi));
		ret = -1;

		goto finished;
	}
	if (task->status == SCSI_STATUS_CANCELLED) {
		scsi_free_scsi_task(task);
		printf("Target dropped the session [OK]\n");
		goto finished;
	}
	if (task->status != SCSI_STATUS_GOOD) {
	        printf("[FAILED]\n");
		printf("Read10 of 1 block with iscsi ExpectedDataTransferLength==0 should not fail.\n");
		ret = -1;
		scsi_free_scsi_task(task);
		goto finished;
	}
	if (task->residual_status != SCSI_RESIDUAL_OVERFLOW ||
	    task->residual != block_size) {
	        printf("[FAILED]\n");
		printf("Read10 returned incorrect residual overflow.\n");
		ret = -1;
		scsi_free_scsi_task(task);
		goto finished;
	}
	scsi_free_scsi_task(task);
	printf("[OK]\n");


	/* in case the previous test failed the session */
	iscsi_set_noautoreconnect(iscsi, 0);

	/* Try a read of 1 block but xferlength == 1024 */
	printf("Read10 1 block but with iscsi ExpectedDataTransferLength==1024 ... ");

	task = malloc(sizeof(struct scsi_task));
	if (task == NULL) {
		printf("Failed to allocate task structure\n");
		ret = -1;
		goto finished;
	}

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 1;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = 1024;

	if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) {
	        printf("[FAILED]\n");
		printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi));
		ret = -1;

		goto finished;
	}
	if (task->status != SCSI_STATUS_GOOD) {
	        printf("[FAILED]\n");
		printf("Read10 of 1 block with iscsi ExpectedDataTransferLength==1024 should not fail.\n");
		ret = -1;
		scsi_free_scsi_task(task);
		goto finished;
	}
	if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW ||
	    task->residual != block_size) {
	        printf("[FAILED]\n");
		printf("Read10 returned incorrect residual underflow.\n");
		ret = -1;
		scsi_free_scsi_task(task);
		goto finished;
	}
	scsi_free_scsi_task(task);
	printf("[OK]\n");


	/* Try a read of 1 block but xferlength == 200 */
	printf("Read10 1 block but with iscsi ExpectedDataTransferLength==200 ... ");

	task = malloc(sizeof(struct scsi_task));
	if (task == NULL) {
		printf("Failed to allocate task structure\n");
		ret = -1;
		goto finished;
	}

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 1;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = 200;

	if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) {
	        printf("[FAILED]\n");
		printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi));
		ret = -1;

		goto finished;
	}
	if (task->status != SCSI_STATUS_GOOD) {
	        printf("[FAILED]\n");
		printf("Read10 of 1 block with iscsi ExpectedDataTransferLength==200 should not fail.\n");
		ret = -1;
		scsi_free_scsi_task(task);
		goto finished;
	}
	if (task->residual_status != SCSI_RESIDUAL_OVERFLOW ||
	    task->residual != block_size - 200) {
	        printf("[FAILED]\n");
		printf("Read10 returned incorrect residual overflow.\n");
		ret = -1;
		scsi_free_scsi_task(task);
		goto finished;
	}
	scsi_free_scsi_task(task);
	printf("[OK]\n");


	/* Try a read of 2 blocks but xferlength == 'block_size' */
	printf("Read10 2 blocks but with iscsi ExpectedDataTransferLength==%zu ... ", block_size);

	task = malloc(sizeof(struct scsi_task));
	if (task == NULL) {
		printf("Failed to allocate task structure\n");
		ret = -1;
		goto finished;
	}

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 2;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_READ;
	task->expxferlen = block_size;

	if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) {
	        printf("[FAILED]\n");
		printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi));
		ret = -1;

		goto finished;
	}
	if (task->status != SCSI_STATUS_GOOD) {
	        printf("[FAILED]\n");
		printf("Read10 of 2 blocks with iscsi ExpectedDataTransferLength==%zu should succeed.\n", block_size);
		ret = -1;
		scsi_free_scsi_task(task);
		goto finished;
	}
	if (task->residual_status != SCSI_RESIDUAL_OVERFLOW ||
	    task->residual != block_size) {
	        printf("[FAILED]\n");
		printf("Read10 returned incorrect residual overflow.\n");
		ret = -1;
		scsi_free_scsi_task(task);
		goto finished;
	}

	scsi_free_scsi_task(task);
	printf("[OK]\n");


	/* Try a read of 1 block but make it a data-out write on the iscsi layer */
	printf("Read10 of 1 block but sent as data-out write in iscsi layer ... ");

	task = malloc(sizeof(struct scsi_task));
	if (task == NULL) {
		printf("Failed to allocate task structure\n");
		ret = -1;
		goto finished;
	}

	memset(task, 0, sizeof(struct scsi_task));
	task->cdb[0] = SCSI_OPCODE_READ10;
	task->cdb[8] = 1;
	task->cdb_size = 10;
	task->xfer_dir = SCSI_XFER_WRITE;
	task->expxferlen = sizeof(buf);

	data.size = sizeof(buf);
	data.data = (unsigned char *)&buf[0];

	if (iscsi_scsi_command_sync(iscsi, lun, task, &data) == NULL) {
	        printf("[FAILED]\n");
		printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi));
		ret = -1;

		goto finished;
	}
	if (task->status == SCSI_STATUS_GOOD) {
	        printf("[FAILED]\n");
		printf("Read10 of 1 block but iscsi data-out write should fail.\n");
		ret = -1;
		scsi_free_scsi_task(task);
		goto finished;
	}
	scsi_free_scsi_task(task);
	printf("[OK]\n");

finished:
	iscsi_logout_sync(iscsi);
	iscsi_destroy_context(iscsi);
	return ret;
}