diff --git a/Makefile.am b/Makefile.am index 4f569c8..3572e01 100644 --- a/Makefile.am +++ b/Makefile.am @@ -245,6 +245,8 @@ bin_iscsi_test_cu_SOURCES = test-tool/iscsi-test-cu.c \ test-tool/test_readcapacity16_simple.c \ test-tool/test_readcapacity16_alloclen.c \ test-tool/test_readonly_sbc.c \ + test-tool/test_reserve6_simple.c \ + test-tool/test_reserve6_2initiators.c \ test-tool/test_startstopunit_simple.c \ test-tool/test_startstopunit_pwrcnd.c \ test-tool/test_startstopunit_noloej.c \ diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 04911d7..1c091a2 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -2533,6 +2533,95 @@ readcapacity16_nomedium(struct iscsi_context *iscsi, int lun, int alloc_len) return 0; } +int +release6(struct iscsi_context *iscsi, int lun) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send RELEASE6"); + + task = iscsi_release6_sync(iscsi, lun); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send RELEASE6 command: %s", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + logging(LOG_NORMAL, "[FAILED] RELEASE6 command: " + "failed with sense. %s", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] RELEASE6 returned SUCCESS."); + return 0; +} + +int +reserve6(struct iscsi_context *iscsi, int lun) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send RESERVE6"); + + task = iscsi_reserve6_sync(iscsi, lun); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send RESERVE6 command: %s", + iscsi_get_error(iscsi)); + return -1; + } + 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] RESERVE6 is not implemented on target"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_GOOD) { + logging(LOG_NORMAL, "[FAILED] RESERVE6 command: " + "failed with sense. %s", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] RESERVE6 returned SUCCESS."); + return 0; +} + +int +reserve6_conflict(struct iscsi_context *iscsi, int lun) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send RESERVE6 (Expecting RESERVATION_CONFLICT)"); + + task = iscsi_reserve6_sync(iscsi, lun); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send RESERVE6 command: %s", + iscsi_get_error(iscsi)); + return -1; + } + 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] RESERVE6 is not implemented on target"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_RESERVATION_CONFLICT) { + logging(LOG_NORMAL, "[FAILED] RESERVE6 command: " + "should have failed with RESERVATION_CONFLICT"); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] RESERVE6 returned RESERVATION_CONFLICT."); + return 0; +} + int unmap(struct iscsi_context *iscsi, int lun, int anchor, struct unmap_list *list, int list_len) { diff --git a/test-tool/iscsi-support.h b/test-tool/iscsi-support.h index ca55b35..64fce3a 100644 --- a/test-tool/iscsi-support.h +++ b/test-tool/iscsi-support.h @@ -245,6 +245,9 @@ int readcapacity10(struct iscsi_context *iscsi, int lun, uint32_t lba, int pmi); int readcapacity10_nomedium(struct iscsi_context *iscsi, int lun, uint32_t lba, int pmi); int readcapacity16(struct iscsi_context *iscsi, int lun, int alloc_len); int readcapacity16_nomedium(struct iscsi_context *iscsi, int lun, int alloc_len); +int release6(struct iscsi_context *iscsi, int lun); +int reserve6(struct iscsi_context *iscsi, int lun); +int reserve6_conflict(struct iscsi_context *iscsi, int lun); int startstopunit(struct iscsi_context *iscsi, int lun, int immed, int pcm, int pc, int no_flush, int loej, int start); int startstopunit_preventremoval(struct iscsi_context *iscsi, int lun, int immed, int pcm, int pc, int no_flush, int loej, int start); int synchronizecache10(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int sync_nv, int immed); diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index 2d8640c..8bfb294 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -214,6 +214,12 @@ static CU_TestInfo tests_readonly[] = { CU_TEST_INFO_NULL }; +static CU_TestInfo tests_reserve6[] = { + { (char *)"testReserve6Simple", test_reserve6_simple }, + { (char *)"testReserve6_2Initiators", test_reserve6_2initiators }, + CU_TEST_INFO_NULL +}; + static CU_TestInfo tests_testunitready[] = { { (char *)"testTurSimple", test_testunitready_simple }, CU_TEST_INFO_NULL @@ -378,6 +384,8 @@ static CU_SuiteInfo suites[] = { tests_readcapacity16 }, { (char *)"TestReadOnly", test_setup, test_teardown, tests_readonly }, + { (char *)"TestReserve6", test_setup, test_teardown, + tests_reserve6 }, { (char *)"TestStartStopUnit", test_setup, test_teardown, tests_startstopunit }, { (char *)"TestTestUnitReady", test_setup, test_teardown, diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h index e0c62d6..8ef2761 100644 --- a/test-tool/iscsi-test-cu.h +++ b/test-tool/iscsi-test-cu.h @@ -127,6 +127,9 @@ void test_readcapacity16_alloclen(void); void test_readonly_sbc(void); +void test_reserve6_simple(void); +void test_reserve6_2initiators(void); + void test_startstopunit_simple(void); void test_startstopunit_pwrcnd(void); void test_startstopunit_noloej(void); diff --git a/test-tool/test_read6_simple.c b/test-tool/test_read6_simple.c index 8961ba8..008176f 100644 --- a/test-tool/test_read6_simple.c +++ b/test-tool/test_read6_simple.c @@ -1,4 +1,3 @@ - /* Copyright (C) 2013 Ronnie Sahlberg diff --git a/test-tool/test_reserve6_2initiators.c b/test-tool/test_reserve6_2initiators.c new file mode 100644 index 0000000..244c6ef --- /dev/null +++ b/test-tool/test_reserve6_2initiators.c @@ -0,0 +1,94 @@ +/* + Copyright (C) 2013 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 "scsi-lowlevel.h" +#include "iscsi-support.h" +#include "iscsi-test-cu.h" + + +void +test_reserve6_2initiators(void) +{ + int ret; + + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, "Test RESERVE6/RELEASE6 across two initiators"); + + + logging(LOG_NORMAL, "Take out a RESERVE6 from the first initiator"); + ret = reserve6(iscsic, tgt_lun); + if (ret == -2) { + logging(LOG_VERBOSE, "[SKIPPED] Target does not support RESERVE6. Skipping test"); + CU_PASS("[SKIPPED] Target does not support RESERVE6. Skipping test"); + return; + } + CU_ASSERT_EQUAL(ret, 0); + + + logging(LOG_NORMAL, "Verify that the first initiator can re-RESERVE6 the same reservation"); + ret = reserve6(iscsic, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); + + + logging(LOG_VERBOSE, "Create a second connection to the target"); + iscsic2 = iscsi_context_login(initiatorname1, tgt_url, &tgt_lun); + if (iscsic2 == NULL) { + logging(LOG_VERBOSE, "Failed to login to target"); + return; + } + + logging(LOG_NORMAL, "Try to take out a RESERVE6 from the second initiator"); + ret = reserve6_conflict(iscsic2, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); + + + logging(LOG_NORMAL, "Try to RELEASE from the second initiator. Should be a nop"); + ret = release6(iscsic2, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); + + + logging(LOG_NORMAL, "Test we can still TESTUNITREADY from the first initiator"); + ret = testunitready(iscsic, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_NORMAL, "TESTUNITREADY should fail from the second initiator"); + ret = testunitready_conflict(iscsic2, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); + + + logging(LOG_NORMAL, "RESERVE6 from the second initiator should still fail"); + ret = reserve6_conflict(iscsic2, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_NORMAL, "RELEASE6 from the first initiator"); + ret = release6(iscsic, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_NORMAL, "RESERVE6 from the second initiator should work now"); + ret = reserve6(iscsic2, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_NORMAL, "RELEASE6 from the second initiator"); + ret = release6(iscsic2, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); +} diff --git a/test-tool/test_reserve6_simple.c b/test-tool/test_reserve6_simple.c new file mode 100644 index 0000000..8f5c69d --- /dev/null +++ b/test-tool/test_reserve6_simple.c @@ -0,0 +1,47 @@ +/* + Copyright (C) 2013 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 "scsi-lowlevel.h" +#include "iscsi-support.h" +#include "iscsi-test-cu.h" + + +void +test_reserve6_simple(void) +{ + int ret; + + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, "Test basic RESERVE6/RELEASE6 commands if supported"); + + ret = reserve6(iscsic, tgt_lun); + if (ret == -2) { + logging(LOG_VERBOSE, "[SKIPPED] Target does not support RESERVE6. Skipping test"); + CU_PASS("[SKIPPED] Target does not support RESERVE6. Skipping test"); + return; + } + CU_ASSERT_EQUAL(ret, 0); + + ret = release6(iscsic, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); +}