From f1d5510e9c1784cd06676fde2779402092a508d9 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sat, 1 Dec 2012 11:40:07 -0800 Subject: [PATCH] TESTS: Add test that we can talk to a target with IMMEDIATE_DATA==NO and INITIAL_R2T==NO --- Makefile.am | 3 +- .../1042_unsolicited_nonimmediate_data.c | 206 ++++++++++++++++++ test-tool/iscsi-test.c | 3 +- test-tool/iscsi-test.h | 1 + 4 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 test-tool/1042_unsolicited_nonimmediate_data.c diff --git a/Makefile.am b/Makefile.am index 7242d7a..3632e0e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -149,7 +149,8 @@ bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \ test-tool/1030_unsolicited_data_overflow.c \ test-tool/1031_unsolicited_data_out.c \ test-tool/1040_saturate_maxcmdsn.c \ - test-tool/1041_unsolicited_immediate_data.c + test-tool/1041_unsolicited_immediate_data.c \ + test-tool/1042_unsolicited_nonimmediate_data.c endif diff --git a/test-tool/1042_unsolicited_nonimmediate_data.c b/test-tool/1042_unsolicited_nonimmediate_data.c new file mode 100644 index 0000000..09559fd --- /dev/null +++ b/test-tool/1042_unsolicited_nonimmediate_data.c @@ -0,0 +1,206 @@ +/* + Copyright (C) 2012 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include +#include "iscsi.h" +#include "iscsi-private.h" +#include "scsi-lowlevel.h" +#include "iscsi-test.h" +#include + +static uint32_t block_size; +static int pdu_was_valid = 1; + +/* one block sent as immediate data. PDU should have F-bit set + * and datasegmentlength should be a single block. + */ +static int my_queue_immediate_data(struct iscsi_context *iscsi _U_, struct iscsi_pdu *pdu _U_) +{ + /* The COMMAND PDU */ + if ((pdu->outdata.data[0] & 0x3f) == ISCSI_PDU_SCSI_REQUEST) { + if (pdu->outdata.data[1] & 0x80) { + printf("SCSI-Command PDU with immediate data had the F-flag set.\n"); + pdu_was_valid = 0; + return 0; + } + if ( *(uint32_t *)&pdu->outdata.data[4] & 0x00ffffff ) { + printf("SCSI-Command PDU had non-zero datasegmentsize.\n"); + pdu_was_valid = 0; + return 0; + } + } + /* The DATA-OUT PDU */ + if ((pdu->outdata.data[0] & 0x3f) == ISCSI_PDU_DATA_OUT) { + if (!(pdu->outdata.data[1] & 0x80)) { + printf("The DATA-OUT PDU did not have the F-flag set.\n"); + pdu_was_valid = 0; + return 0; + } + if ( (*(uint32_t *)&pdu->outdata.data[4] & 0x00ffffff) != htonl(block_size)) { + printf("The DATA-OUT PDU did not carry a full block.\n"); + pdu_was_valid = 0; + return 0; + } + } + + + return 1; +} + +int T1042_unsolicited_nonimmediate_data(const char *initiator, const char *url, int data_loss, int show_info) +{ + struct iscsi_context *iscsi; + struct scsi_task *task; + struct scsi_readcapacity16 *rc16; + int ret, lun; + struct iscsi_url *iscsi_url; + unsigned char data[4096]; + + printf("1042_unsolicited_nonimmediate_data:\n"); + printf("================================\n"); + if (show_info) { + printf("Test we can send unsolicited nonimmediate data to the target\n"); + printf("1, Login to target with IMMEDIATE_DATA=NO and INITIAL_R2T=NO.\n"); + printf("2, Write one block to the target.\n"); + printf("3, Verify that the COMMAND PDU does not have the F-flag set.\n"); + printf("4, Verify that the COMMAND PDU sent has no immediate data.\n"); + printf("5, Verify that the DATA-OUT PDU has the F-flag set.\n"); + printf("6, Verify that the DATA-OUT PDU has one block of data.\n"); + printf("\n"); + return 0; + } + + iscsi = iscsi_context_login(initiator, url, &lun); + if (iscsi == NULL) { + printf("Failed to login to target\n"); + return -1; + } + + iscsi_url = iscsi_parse_full_url(iscsi, url); + if (iscsi_url == NULL) { + printf("Failed to parse iscsi url\n"); + return -1; + } + + /* find the size of the LUN */ + task = iscsi_readcapacity16_sync(iscsi, lun); + if (task == NULL) { + printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); + ret = -1; + goto finished; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + ret = -1; + scsi_free_scsi_task(task); + goto finished; + } + rc16 = scsi_datain_unmarshall(task); + if (rc16 == NULL) { + printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); + ret = -1; + scsi_free_scsi_task(task); + goto finished; + } + block_size = rc16->block_length; + + scsi_free_scsi_task(task); + + + if (!data_loss) { + printf("--dataloss flag is not set. Skipping test\n"); + ret = -2; + goto finished; + } + + + ret = 0; + + + /* This setting will allow us to send unsolicited data as + * immediate data but not as a data-out. + */ + printf("Login to target with IMMEDIATE_DATA=NO and INITIAL_R2T=NO ... "); + iscsi_destroy_context(iscsi); + iscsi = iscsi_create_context(initiator); + iscsi_set_targetname(iscsi, iscsi_url->target); + iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); + iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); + iscsi_set_immediate_data(iscsi, ISCSI_IMMEDIATE_DATA_NO); + iscsi_set_initial_r2t(iscsi, ISCSI_INITIAL_R2T_NO); + if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, lun) != 0) { + printf("[FAILED]\n"); + printf("Failed to log in to target with IMMEDIATE_DATA=NO and INITIAL_R2T=NO %s\n", iscsi_get_error(iscsi)); + ret = -1; + goto finished; + } + if (iscsi->use_immediate_data != ISCSI_IMMEDIATE_DATA_NO) { + printf("[FAILED]\n"); + printf("Failed to negotiate IMMEDIATE_DATA==NO with target\n"); + ret = -1; + goto finished; + } + + if (iscsi->use_initial_r2t != ISCSI_INITIAL_R2T_NO) { + printf("[SKIPPED]\n"); + printf("Target does not allow INITIAL_R2T==NO. Skipping test\n"); + ret = -2; + goto finished; + } + printf("[OK]\n"); + + + + printf("Write one block as unsolicited data-out ... "); + local_iscsi_queue_pdu = my_queue_immediate_data; + task = iscsi_write10_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 0, 0); + local_iscsi_queue_pdu = NULL; + /* Verify that the PDU we sent had the F-bit set and that + * datasegmentlength was one block. + */ + if (pdu_was_valid == 0) { + printf("[FAILED]\n"); + printf("PDU to send was invalid.\n"); + ret = -1; + goto finished; + } + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send write10 command: %s\n", iscsi_get_error(iscsi)); + ret = -1; + goto finished; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("Write10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + ret = -1; + scsi_free_scsi_task(task); + goto finished; + } + + scsi_free_scsi_task(task); + printf("[OK]\n"); + + + +finished: + iscsi_destroy_context(iscsi); + iscsi_destroy_url(iscsi_url); + + return ret; +} diff --git a/test-tool/iscsi-test.c b/test-tool/iscsi-test.c index d7cf9b5..9cce1dc 100644 --- a/test-tool/iscsi-test.c +++ b/test-tool/iscsi-test.c @@ -250,7 +250,8 @@ struct scsi_test tests[] = { */ { "T1040_saturate_maxcmdsn", T1040_saturate_maxcmdsn }, -{ "T1041_unsolicited__immediate_data", T1041_unsolicited_immediate_data }, +{ "T1041_unsolicited_immediate_data", T1041_unsolicited_immediate_data }, +{ "T1042_unsolicited_nonimmediate_data",T1042_unsolicited_nonimmediate_data }, { NULL, NULL } }; diff --git a/test-tool/iscsi-test.h b/test-tool/iscsi-test.h index 49a8fe5..851947c 100644 --- a/test-tool/iscsi-test.h +++ b/test-tool/iscsi-test.h @@ -184,3 +184,4 @@ int T1030_unsolicited_data_overflow(const char *initiator, const char *url, int int T1031_unsolicited_data_out(const char *initiator, const char *url, int data_loss, int show_info); int T1040_saturate_maxcmdsn(const char *initiator, const char *url, int data_loss, int show_info); int T1041_unsolicited_immediate_data(const char *initiator, const char *url, int data_loss, int show_info); +int T1042_unsolicited_nonimmediate_data(const char *initiator, const char *url, int data_loss, int show_info);