diff --git a/test-tool/Makefile.am b/test-tool/Makefile.am index 1918b58..d7a41c7 100644 --- a/test-tool/Makefile.am +++ b/test-tool/Makefile.am @@ -32,6 +32,7 @@ iscsi_test_cu_SOURCES = iscsi-test-cu.c \ test_iscsi_datasn_invalid.c \ test_mandatory_sbc.c \ test_modesense6_all_pages.c \ + test_modesense6_control.c \ test_modesense6_residuals.c \ test_nomedia_sbc.c \ test_orwrite_simple.c \ diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index 252cd6f..fad8bca 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -100,6 +100,7 @@ static CU_TestInfo tests_mandatory[] = { static CU_TestInfo tests_modesense6[] = { { (char *)"AllPages", test_modesense6_all_pages }, + { (char *)"Control", test_modesense6_control }, { (char *)"Residuals", test_modesense6_residuals }, CU_TEST_INFO_NULL }; diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h index 8a95e5d..512e022 100644 --- a/test-tool/iscsi-test-cu.h +++ b/test-tool/iscsi-test-cu.h @@ -72,6 +72,7 @@ void test_iscsi_datasn_invalid(void); void test_mandatory_sbc(void); void test_modesense6_all_pages(void); +void test_modesense6_control(void); void test_modesense6_residuals(void); void test_nomedia_sbc(void); diff --git a/test-tool/test_modesense6_control.c b/test-tool/test_modesense6_control.c new file mode 100644 index 0000000..8964e86 --- /dev/null +++ b/test-tool/test_modesense6_control.c @@ -0,0 +1,242 @@ +/* + Copyright (C) 2015 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 "scsi-lowlevel.h" +#include "iscsi-support.h" +#include "iscsi-test-cu.h" + +void +test_modesense6_control(void) +{ + struct scsi_mode_sense *ms; + struct scsi_mode_page *ap_page; + struct scsi_mode_page *ct_page; + struct scsi_task *ap_task = NULL; + struct scsi_task *ct_task = NULL; + int ret; + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, "Test of MODESENSE6 CONTROL page"); + + + logging(LOG_VERBOSE, "Fetch the CONTROL page via AllPages"); + logging(LOG_VERBOSE, "Send MODESENSE6 command to fetch AllPages"); + ret = modesense6(sd, &ap_task, 0, SCSI_MODESENSE_PC_CURRENT, + SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 255, + EXPECT_STATUS_GOOD); + CU_ASSERT_EQUAL(ret, 0); + logging(LOG_VERBOSE, "[SUCCESS] All Pages fetched."); + + + logging(LOG_VERBOSE, "Try to unmarshall the DATA-IN buffer."); + ms = scsi_datain_unmarshall(ap_task); + if (ms == NULL) { + logging(LOG_NORMAL, "[FAILED] failed to unmarshall mode sense " + "datain buffer"); + CU_FAIL("[FAILED] Failed to unmarshall the data-in buffer."); + goto finished; + } + logging(LOG_VERBOSE, "[SUCCESS] Unmarshalling successful."); + + + logging(LOG_VERBOSE, "Verify that mode data length is >= 3"); + if (ms->mode_data_length >= 3) { + logging(LOG_VERBOSE, "[SUCCESS] Mode data length is >= 3"); + } else { + logging(LOG_NORMAL, "[FAILED] Mode data length is < 3"); + } + CU_ASSERT_TRUE(ms->mode_data_length >= 3); + + for (ap_page = ms->pages; ap_page; ap_page = ap_page->next) { + if (ap_page->page_code == SCSI_MODEPAGE_CONTROL) { + break; + } + } + if(ap_page == NULL) { + logging(LOG_NORMAL, "[WARNING] CONTROL page was not returned " + "from AllPages. All devices SHOULD implement this " + "page."); + } + + + logging(LOG_VERBOSE, "Fetch the CONTROL page directly"); + logging(LOG_VERBOSE, "Send MODESENSE6 command to fetch CONTROL"); + ret = modesense6(sd, &ct_task, 0, SCSI_MODESENSE_PC_CURRENT, + SCSI_MODEPAGE_CONTROL, 0, 255, + EXPECT_STATUS_GOOD); + CU_ASSERT_EQUAL(ret, 0); + logging(LOG_VERBOSE, "[SUCCESS] CONTROL page fetched."); + + logging(LOG_VERBOSE, "Try to unmarshall the DATA-IN buffer."); + ms = scsi_datain_unmarshall(ct_task); + if (ms == NULL) { + logging(LOG_NORMAL, "[FAILED] failed to unmarshall mode sense " + "datain buffer"); + CU_FAIL("[FAILED] Failed to unmarshall the data-in buffer."); + goto finished; + } + logging(LOG_VERBOSE, "[SUCCESS] Unmarshalling successful."); + + logging(LOG_VERBOSE, "Verify that mode data length is >= 3"); + if (ms->mode_data_length >= 3) { + logging(LOG_VERBOSE, "[SUCCESS] Mode data length is >= 3"); + } else { + logging(LOG_NORMAL, "[FAILED] Mode data length is < 3"); + } + CU_ASSERT_TRUE(ms->mode_data_length >= 3); + + for (ct_page = ms->pages; ct_page; ct_page = ct_page->next) { + if (ct_page->page_code == SCSI_MODEPAGE_CONTROL) { + break; + } + } + if(ct_page == NULL) { + logging(LOG_NORMAL, "[WARNING] CONTROL page was not returned " + "from AllPages. All devices SHOULD implement this " + "page."); + } + + if (ap_page == NULL && ct_page != NULL) { + logging(LOG_NORMAL, "[FAILED] CONTROL page was not returned " + "from AllPages."); + CU_FAIL("[FAILED] CONTROL page is missing from AllPages"); + goto finished; + } + + if (ap_page != NULL && ct_page == NULL) { + logging(LOG_NORMAL, "[FAILED] CONTROL page is only available " + "from AllPages but not directly."); + CU_FAIL("[FAILED] CONTROL page is missing"); + goto finished; + } + + if (ct_page == NULL) { + logging(LOG_NORMAL, "[SKIPPED] CONTROL page is not " + "implemented."); + CU_PASS("CONTROL page is not implemented."); + goto finished; + } + + logging(LOG_VERBOSE, "Verify that the two pages are identical."); + + logging(LOG_VERBOSE, "Check TST field"); + CU_ASSERT_EQUAL(ct_page->control.tst, ap_page->control.tst); + logging(LOG_VERBOSE, "Check TMF_ONLY field"); + CU_ASSERT_EQUAL(ct_page->control.tmf_only, ap_page->control.tmf_only); + logging(LOG_VERBOSE, "Check dpicz field"); + CU_ASSERT_EQUAL(ct_page->control.dpicz, ap_page->control.dpicz); + logging(LOG_VERBOSE, "Check d_sense field"); + CU_ASSERT_EQUAL(ct_page->control.d_sense, ap_page->control.d_sense); + logging(LOG_VERBOSE, "Check gltsd field"); + CU_ASSERT_EQUAL(ct_page->control.gltsd, ap_page->control.gltsd); + logging(LOG_VERBOSE, "Check rlec field"); + CU_ASSERT_EQUAL(ct_page->control.rlec, ap_page->control.rlec); + logging(LOG_VERBOSE, "Check queue_algorithm_modifier field"); + CU_ASSERT_EQUAL(ct_page->control.queue_algorithm_modifier, + ap_page->control.queue_algorithm_modifier); + logging(LOG_VERBOSE, "Check nuar field"); + CU_ASSERT_EQUAL(ct_page->control.nuar, ap_page->control.nuar); + logging(LOG_VERBOSE, "Check qerr field"); + CU_ASSERT_EQUAL(ct_page->control.qerr, ap_page->control.qerr); + logging(LOG_VERBOSE, "Check vs field"); + CU_ASSERT_EQUAL(ct_page->control.vs, ap_page->control.vs); + logging(LOG_VERBOSE, "Check rac field"); + CU_ASSERT_EQUAL(ct_page->control.rac, ap_page->control.rac); + logging(LOG_VERBOSE, "Check ua_intlck_ctrl field"); + CU_ASSERT_EQUAL(ct_page->control.ua_intlck_ctrl, + ap_page->control.ua_intlck_ctrl); + logging(LOG_VERBOSE, "Check swp field"); + CU_ASSERT_EQUAL(ct_page->control.swp, ap_page->control.swp); + logging(LOG_VERBOSE, "Check ato field"); + CU_ASSERT_EQUAL(ct_page->control.ato, ap_page->control.ato); + logging(LOG_VERBOSE, "Check tas field"); + CU_ASSERT_EQUAL(ct_page->control.tas, ap_page->control.tas); + logging(LOG_VERBOSE, "Check atmpe field"); + CU_ASSERT_EQUAL(ct_page->control.atmpe, ap_page->control.atmpe); + logging(LOG_VERBOSE, "Check rwwp field"); + CU_ASSERT_EQUAL(ct_page->control.rwwp, ap_page->control.rwwp); + logging(LOG_VERBOSE, "Check autoload_mode field"); + CU_ASSERT_EQUAL(ct_page->control.autoload_mode, + ap_page->control.autoload_mode); + logging(LOG_VERBOSE, "Check busy_timeout_period field"); + CU_ASSERT_EQUAL(ct_page->control.busy_timeout_period, + ap_page->control.busy_timeout_period); + logging(LOG_VERBOSE, "Check extended_selftest_completion_time field"); + CU_ASSERT_EQUAL(ct_page->control.extended_selftest_completion_time, + ap_page->control.extended_selftest_completion_time); + + + logging(LOG_VERBOSE, "Verify that the values are sane."); + logging(LOG_VERBOSE, "Check that TST is 0 or 1."); + if (ct_page->control.tst > 1) { + logging(LOG_NORMAL, "[FAILED] TST value is invalid. Must be " + "0, 1 but was %d", ct_page->control.tst); + CU_FAIL("[FAILED] TST is invalid."); + } + logging(LOG_VERBOSE, "Check that QUEUE_ALGORITHM_MODIFIER is " + "0, 1 or >7"); + if (ct_page->control.queue_algorithm_modifier > 1 && + ct_page->control.queue_algorithm_modifier < 8) { + logging(LOG_NORMAL, "[FAILED] QUEUE_ALGORITHM_MODIFIER value " + "is invalid. Must be 0, 1 or >7 but was %d", + ct_page->control.queue_algorithm_modifier); + CU_FAIL("[FAILED] QUEUE_ALGORITHM_MODIFIER is invalid."); + } + + logging(LOG_VERBOSE, "Check that QERR is not 2"); + if (ct_page->control.qerr == 2) { + logging(LOG_NORMAL, "[FAILED] QERR value " + "is invalid. Can not be 2"); + CU_FAIL("[FAILED] QERR is invalid."); + } + + logging(LOG_VERBOSE, "Check that UA_INTLCK_CTRL is not 1"); + if (ct_page->control.ua_intlck_ctrl == 1) { + logging(LOG_NORMAL, "[FAILED] UA_INTLCK_CTRL value " + "is invalid. Can not be 1"); + CU_FAIL("[FAILED] UA_INTLCK_CTRL is invalid."); + } + + logging(LOG_VERBOSE, "Check that AUTOLOAD is 0, 1 or 2"); + if (ct_page->control.autoload_mode > 2) { + logging(LOG_NORMAL, "[FAILED] AUTOLOAD value " + "is invalid. Must be 0, 1 or 2 but was %d", + ct_page->control.autoload_mode); + CU_FAIL("[FAILED] AUTOLOAD is invalid."); + } + + logging(LOG_VERBOSE, "Check that BUSY_TIMEOUT_PERIOD is specified"); + if (ct_page->control.busy_timeout_period == 0) { + logging(LOG_NORMAL, "[WARNING] BUSY_TIMEOUT_PERIOD is " + "undefined."); + } + + + +finished: + if (ap_task != NULL) { + scsi_free_scsi_task(ap_task); + } + if (ct_task != NULL) { + scsi_free_scsi_task(ct_task); + } +}