diff --git a/Makefile.am b/Makefile.am index c463ef9..1599037 100644 --- a/Makefile.am +++ b/Makefile.am @@ -255,9 +255,10 @@ bin_iscsi_test_cu_SOURCES = test-tool/iscsi-test-cu.c \ test-tool/test_readcapacity16_protection.c \ test-tool/test_readcapacity16_simple.c \ test-tool/test_readonly_sbc.c \ - test-tool/test_report_supported_opcodes_simple.c \ + test-tool/test_report_supported_opcodes_one_command.c \ test-tool/test_report_supported_opcodes_rctd.c \ test-tool/test_report_supported_opcodes_servactv.c \ + test-tool/test_report_supported_opcodes_simple.c \ test-tool/test_reserve6_simple.c \ test-tool/test_reserve6_2initiators.c \ test-tool/test_reserve6_logout.c \ diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 46cd785..ea13202 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -2801,6 +2801,49 @@ int report_supported_opcodes(struct iscsi_context *iscsi, int lun, int rctd, int return 0; } +int report_supported_opcodes_invalidfieldincdb(struct iscsi_context *iscsi, int lun, int rctd, int options, int opcode, int sa, int alloc_len, struct scsi_task **save_task) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send REPORT_SUPPORTED_OPCODE (expecting INVALID_FIELD_IN_CDB) RCTD:%d OPTIONS:%d " + "OPCODE:%d SA:%d ALLOC_LEN:%d", + rctd, options, opcode, sa, alloc_len); + + task = iscsi_report_supported_opcodes_sync(iscsi, lun, + rctd, options, opcode, sa, alloc_len); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send " + "REPORT_SUPPORTED_OPCODES 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] REPORT_SUPPORTED_OPCODES is not " + "implemented on target"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST + || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { + logging(LOG_NORMAL, "[FAILED] REPORT_SUPPORTED_OPCODES should have failed with ILLEGAL_REQUEST/INVALID_FIELD_IN_CDB. Sense:%s", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + if (save_task != NULL) { + *save_task = task; + } else { + scsi_free_scsi_task(task); + } + + logging(LOG_VERBOSE, "[OK] REPORT_SUPPORTED_OPCODES returned " + "INVALID_FIELD_IN_CDB."); + return 0; +} + int reserve6(struct iscsi_context *iscsi, int lun) { diff --git a/test-tool/iscsi-support.h b/test-tool/iscsi-support.h index 2ba770e..a267293 100644 --- a/test-tool/iscsi-support.h +++ b/test-tool/iscsi-support.h @@ -244,6 +244,7 @@ int readcapacity10_nomedium(struct iscsi_context *iscsi, int lun, uint32_t lba, int readcapacity16(struct iscsi_context *iscsi, int lun, int alloc_len); int readcapacity16_nomedium(struct iscsi_context *iscsi, int lun, int alloc_len); int report_supported_opcodes(struct iscsi_context *iscsi, int lun, int rctd, int options, int opcode, int sa, int alloc_len, struct scsi_task **save_task); +int report_supported_opcodes_invalidfieldincdb(struct iscsi_context *iscsi, int lun, int rctd, int options, int opcode, int sa, int alloc_len, struct scsi_task **save_task); 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); diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index b11a1d0..f08d726 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -223,6 +223,7 @@ static CU_TestInfo tests_readonly[] = { static CU_TestInfo tests_report_supported_opcodes[] = { { (char *)"ReportSupportedOpcodesSimple", test_report_supported_opcodes_simple }, + { (char *)"ReportSupportedOpcodesOneCommand", test_report_supported_opcodes_one_command }, { (char *)"ReportSupportedOpcodesRCTD", test_report_supported_opcodes_rctd }, { (char *)"ReportSupportedOpcodesSERVACTV", test_report_supported_opcodes_servactv }, CU_TEST_INFO_NULL diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h index 8078b51..d3e1955 100644 --- a/test-tool/iscsi-test-cu.h +++ b/test-tool/iscsi-test-cu.h @@ -138,9 +138,10 @@ void test_readcapacity16_simple(void); void test_readonly_sbc(void); -void test_report_supported_opcodes_simple(void); +void test_report_supported_opcodes_one_command(void); void test_report_supported_opcodes_rctd(void); void test_report_supported_opcodes_servactv(void); +void test_report_supported_opcodes_simple(void); void test_reserve6_simple(void); void test_reserve6_2initiators(void); diff --git a/test-tool/test_report_supported_opcodes_one_command.c b/test-tool/test_report_supported_opcodes_one_command.c new file mode 100644 index 0000000..8ada542 --- /dev/null +++ b/test-tool/test_report_supported_opcodes_one_command.c @@ -0,0 +1,111 @@ +/* + Copyright (C) 2013 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_report_supported_opcodes_one_command(void) +{ + int i, ret; + struct scsi_task *rso_task; + struct scsi_report_supported_op_codes *rsoc; + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, "Test READ_SUPPORTED_OPCODES reading one-command"); + + + logging(LOG_VERBOSE, "Fetch list of all supported opcodes"); + ret = report_supported_opcodes(iscsic, tgt_lun, + 0, SCSI_REPORT_SUPPORTING_OPS_ALL, 0, 0, + 65535, &rso_task); + if (ret == -2) { + logging(LOG_NORMAL, "[SKIPPED] READ_SUPPORTED_OPCODES is not " + "implemented."); + CU_PASS("READ_SUPPORTED_OPCODES is not implemented."); + return; + } + CU_ASSERT_EQUAL(ret, 0); + if (ret != 0) { + return; + } + + logging(LOG_VERBOSE, "Unmarshall the DATA-IN buffer"); + rsoc = scsi_datain_unmarshall(rso_task); + CU_ASSERT_NOT_EQUAL(rsoc, NULL); + + + logging(LOG_VERBOSE, "Verify read one-command for all supported " + "opcodes"); + for (i = 0; i < rsoc->num_descriptors; i++) { + logging(LOG_VERBOSE, "Check opcode:0x%02x ServiceAction:0x%02x", + rsoc->descriptors[i].opcode, + rsoc->descriptors[i].sa); + if (rsoc->descriptors[i].servactv) { + logging(LOG_VERBOSE, "This opcode has service actions. " + "Reporting Options 001b should fail"); + ret = report_supported_opcodes_invalidfieldincdb( + iscsic, tgt_lun, + 0, SCSI_REPORT_SUPPORTING_OPCODE, + rsoc->descriptors[i].opcode, + rsoc->descriptors[i].sa, + 65535, NULL); + } else { + logging(LOG_VERBOSE, "This opcode does not have " + "service actions. Reporting Options 001b " + "should work"); + ret = report_supported_opcodes( + iscsic, tgt_lun, + 0, SCSI_REPORT_SUPPORTING_OPCODE, + rsoc->descriptors[i].opcode, + rsoc->descriptors[i].sa, + 65535, NULL); + } + CU_ASSERT_EQUAL(ret, 0); + + if (rsoc->descriptors[i].servactv) { + logging(LOG_VERBOSE, "This opcode has service actions. " + "Reporting Options 002b should work"); + ret = report_supported_opcodes( + iscsic, tgt_lun, + 0, SCSI_REPORT_SUPPORTING_SERVICEACTION, + rsoc->descriptors[i].opcode, + rsoc->descriptors[i].sa, + 65535, NULL); + } else { + logging(LOG_VERBOSE, "This opcode does not have " + "service actions. Reporting Options 002b " + "should fail"); + ret = report_supported_opcodes_invalidfieldincdb( + iscsic, tgt_lun, + 0, SCSI_REPORT_SUPPORTING_SERVICEACTION, + rsoc->descriptors[i].opcode, + rsoc->descriptors[i].sa, + 65535, NULL); + } + CU_ASSERT_EQUAL(ret, 0); + } + + scsi_free_scsi_task(rso_task); +}