diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index a7144f1..adb1be1 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -945,6 +945,22 @@ struct scsi_persistent_reserve_in_read_reservation { unsigned char pr_type; }; +enum scsi_persistent_reservation_type_mask { + SCSI_PR_TYPE_MASK_EX_AC_AR = (1 << 0), + SCSI_PR_TYPE_MASK_WR_EX = (1 << 9), + SCSI_PR_TYPE_MASK_EX_AC = (1 << 11), + SCSI_PR_TYPE_MASK_WR_EX_RO = (1 << 13), + SCSI_PR_TYPE_MASK_EX_AC_RO = (1 << 14), + SCSI_PR_TYPE_MASK_WR_EX_AR = (1 << 15), + + SCSI_PR_TYPE_MASK_ALL = (SCSI_PR_TYPE_MASK_EX_AC_AR + | SCSI_PR_TYPE_MASK_WR_EX + | SCSI_PR_TYPE_MASK_EX_AC + | SCSI_PR_TYPE_MASK_WR_EX_RO + | SCSI_PR_TYPE_MASK_EX_AC_RO + | SCSI_PR_TYPE_MASK_WR_EX_AR) +}; + struct scsi_persistent_reserve_in_report_capabilities { uint16_t length; uint8_t crh; diff --git a/test-tool/Makefile.am b/test-tool/Makefile.am index 8b2e2e0..cc12803 100644 --- a/test-tool/Makefile.am +++ b/test-tool/Makefile.am @@ -69,6 +69,7 @@ iscsi_test_cu_SOURCES = iscsi-test-cu.c \ test_preventallow_2_itnexuses.c \ test_prin_read_keys_simple.c \ test_prin_serviceaction_range.c \ + test_prin_report_caps.c \ test_prout_register_simple.c \ test_prout_reserve_simple.c \ test_prout_reserve_access.c \ diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index 5646b74..826061d 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -157,6 +157,11 @@ static CU_TestInfo tests_prin_read_keys[] = { CU_TEST_INFO_NULL }; +static CU_TestInfo tests_prin_report_caps[] = { + { (char *)"Simple", test_prin_report_caps_simple }, + CU_TEST_INFO_NULL +}; + static CU_TestInfo tests_prout_register[] = { { (char *)"Simple", test_prout_register_simple }, CU_TEST_INFO_NULL @@ -482,6 +487,7 @@ static libiscsi_suite_info scsi_suites[] = { { "PreventAllow", NON_PGR_FUNCS, tests_preventallow }, { "PrinReadKeys", NON_PGR_FUNCS, tests_prin_read_keys }, { "PrinServiceactionRange", NON_PGR_FUNCS, tests_prin_serviceaction_range }, + { "PrinReportCapabilities", NON_PGR_FUNCS, tests_prin_report_caps }, { "ProutRegister", NON_PGR_FUNCS, tests_prout_register }, { "ProutReserve", NON_PGR_FUNCS, tests_prout_reserve }, { "ProutClear", NON_PGR_FUNCS, tests_prout_clear }, @@ -568,6 +574,7 @@ static libiscsi_suite_info all_suites[] = { { "PrinReadKeys", NON_PGR_FUNCS, tests_prin_read_keys }, { "PrinServiceactionRange", NON_PGR_FUNCS, tests_prin_serviceaction_range }, + { "PrinReportCapabilities", NON_PGR_FUNCS, tests_prin_report_caps }, { "ProutRegister", NON_PGR_FUNCS, tests_prout_register }, { "ProutReserve", NON_PGR_FUNCS, tests_prout_reserve }, { "ProutClear", NON_PGR_FUNCS, tests_prout_clear }, diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h index fa9a0c0..e9330dc 100644 --- a/test-tool/iscsi-test-cu.h +++ b/test-tool/iscsi-test-cu.h @@ -114,6 +114,7 @@ void test_preventallow_2_itnexuses(void); void test_prin_read_keys_simple(void); void test_prin_serviceaction_range(void); +void test_prin_report_caps_simple(void); void test_prout_register_simple(void); void test_prout_reserve_simple(void); diff --git a/test-tool/test_prin_report_caps.c b/test-tool/test_prin_report_caps.c new file mode 100644 index 0000000..688c3b2 --- /dev/null +++ b/test-tool/test_prin_report_caps.c @@ -0,0 +1,114 @@ +/* + Copyright (C) 2015 David Disseldorp + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include + +#include + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-support.h" +#include "iscsi-test-cu.h" + +static struct test_prin_report_caps_types { + enum scsi_persistent_reservation_type_mask mask; + enum scsi_persistent_out_type op; +} report_caps_types_array[] = { + { SCSI_PR_TYPE_MASK_WR_EX_AR, + SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS }, + { SCSI_PR_TYPE_MASK_EX_AC_RO, + SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY }, + { SCSI_PR_TYPE_MASK_WR_EX_RO, + SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY }, + { SCSI_PR_TYPE_MASK_EX_AC, + SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS }, + { SCSI_PR_TYPE_MASK_WR_EX, + SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE }, + { SCSI_PR_TYPE_MASK_EX_AC_AR, + SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS }, + { 0, 0 } +}; + +void +test_prin_report_caps_simple(void) +{ + int ret = 0; + const unsigned long long key = rand_key(); + struct scsi_task *tsk; + struct scsi_persistent_reserve_in_report_capabilities *rcaps; + struct test_prin_report_caps_types *type; + + CHECK_FOR_DATALOSS; + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, + "Test Persistent Reserve In REPORT CAPABILITIES works."); + + /* register our reservation key with the target */ + ret = prout_register_and_ignore(sd, key); + if (ret == -2) { + logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE OUT is not implemented."); + CU_PASS("PERSISTENT RESERVE OUT is not implemented."); + return; + } + CU_ASSERT_EQUAL(ret, 0); + + ret = prin_report_caps(sd, &tsk, &rcaps); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_VERBOSE, + "Checking PERSISTENT RESERVE IN REPORT CAPABILITIES fields."); + CU_ASSERT_EQUAL(rcaps->length, 8); + CU_ASSERT_TRUE(rcaps->allow_commands <= 5); + CU_ASSERT_EQUAL(rcaps->persistent_reservation_type_mask + & ~SCSI_PR_TYPE_MASK_ALL, 0); + + for (type = &report_caps_types_array[0]; type->mask != 0; type++) { + if (!(rcaps->persistent_reservation_type_mask & type->mask)) { + logging(LOG_NORMAL, + "PERSISTENT RESERVE op 0x%x not supported", + type->op); + continue; + } + + logging(LOG_VERBOSE, + "PERSISTENT RESERVE OUT op 0x%x supported, testing", + type->op); + + /* reserve the target */ + ret = prout_reserve(sd, key, type->op); + CU_ASSERT_EQUAL(ret, 0); + + /* verify target reservation */ + ret = prin_verify_reserved_as(sd, + pr_type_is_all_registrants(type->op) ? 0 : key, + type->op); + CU_ASSERT_EQUAL(0, ret); + + /* release the target */ + ret = prout_release(sd, key, type->op); + CU_ASSERT_EQUAL(ret, 0); + } + + scsi_free_scsi_task(tsk); + rcaps = NULL; /* freed with tsk */ + + /* drop registration */ + ret = prout_register_key(sd, 0, key); + CU_ASSERT_EQUAL(ret, 0); +}