diff --git a/Makefile.am b/Makefile.am index ca19d65..53c24ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -255,6 +255,8 @@ 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_rctd.c \ test-tool/test_reserve6_simple.c \ test-tool/test_reserve6_2initiators.c \ test-tool/test_reserve6_logout.c \ diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index 5693129..acdc936 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -739,24 +739,24 @@ struct scsi_get_lba_status { struct scsi_op_timeout_descriptor { uint16_t descriptor_length; - uint8_t reserved; uint8_t command_specific; uint32_t nominal_processing_timeout; uint32_t recommended_timeout; }; struct scsi_command_descriptor { - uint8_t op_code; - uint8_t reserved1; - uint16_t service_action; - uint8_t reserved2; - uint8_t reserved3; - uint16_t cdb_length; - struct scsi_op_timeout_descriptor to[0]; + uint8_t opcode; + uint16_t sa; + uint8_t ctdp; + uint8_t servactv; + uint16_t cdb_len; + + /* only present if CTDP==1 */ + struct scsi_op_timeout_descriptor to; }; struct scsi_report_supported_op_codes { - uint32_t num_descriptors; + int num_descriptors; struct scsi_command_descriptor descriptors[0]; }; @@ -911,39 +911,37 @@ EXTERN void *scsi_cdb_unmarshall(struct scsi_task *task, enum scsi_opcode opcode unsigned char *scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count); unsigned char *scsi_task_get_data_out_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count); +EXTERN struct scsi_task *scsi_cdb_compareandwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); +EXTERN struct scsi_task *scsi_cdb_get_lba_status(uint64_t starting_lba, uint32_t alloc_len); +EXTERN struct scsi_task *scsi_cdb_orwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); +EXTERN struct scsi_task *scsi_cdb_persistent_reserve_in(enum scsi_persistent_in_sa sa, uint16_t xferlen); +EXTERN struct scsi_task *scsi_cdb_persistent_reserve_out(enum scsi_persistent_out_sa sa, enum scsi_persistent_out_scope scope, enum scsi_persistent_out_type type, void *params); +EXTERN struct scsi_task *scsi_cdb_prefetch10(uint32_t lba, int num_blocks, int immed, int group); +EXTERN struct scsi_task *scsi_cdb_prefetch16(uint64_t lba, int num_blocks, int immed, int group); +EXTERN struct scsi_task *scsi_cdb_preventallow(int prevent); EXTERN struct scsi_task *scsi_cdb_read6(uint32_t lba, uint32_t xferlen, int blocksize); EXTERN struct scsi_task *scsi_cdb_read10(uint32_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_read12(uint32_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_read16(uint64_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); -EXTERN struct scsi_task *scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); -EXTERN struct scsi_task *scsi_cdb_write12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); -EXTERN struct scsi_task *scsi_cdb_write16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); +EXTERN struct scsi_task *scsi_cdb_readcapacity16(void); +EXTERN struct scsi_task *scsi_cdb_report_supported_opcodes(int rctd, int options, enum scsi_opcode opcode, int sa, uint32_t alloc_len); +EXTERN struct scsi_task *scsi_cdb_serviceactionin16(enum scsi_service_action_in sa, uint32_t xferlen); EXTERN struct scsi_task *scsi_cdb_startstopunit(int immed, int pcm, int pc, int no_flush, int loej, int start); -EXTERN struct scsi_task *scsi_cdb_preventallow(int prevent); -EXTERN struct scsi_task *scsi_cdb_orwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); -EXTERN struct scsi_task *scsi_cdb_compareandwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); -EXTERN struct scsi_task *scsi_cdb_writeverify10(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number); -EXTERN struct scsi_task *scsi_cdb_writeverify12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number); -EXTERN struct scsi_task *scsi_cdb_writeverify16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number); +EXTERN struct scsi_task *scsi_cdb_synchronizecache10(int lba, int num_blocks, int syncnv, int immed); +EXTERN struct scsi_task *scsi_cdb_synchronizecache16(uint64_t lba, uint32_t num_blocks, int syncnv, int immed); +EXTERN struct scsi_task *scsi_cdb_unmap(int anchor, int group, uint16_t xferlen); EXTERN struct scsi_task *scsi_cdb_verify10(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize); EXTERN struct scsi_task *scsi_cdb_verify12(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize); EXTERN struct scsi_task *scsi_cdb_verify16(uint64_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize); - -EXTERN struct scsi_task *scsi_cdb_synchronizecache10(int lba, int num_blocks, - int syncnv, int immed); -EXTERN struct scsi_task *scsi_cdb_synchronizecache16(uint64_t lba, uint32_t num_blocks, - int syncnv, int immed); -EXTERN struct scsi_task *scsi_cdb_serviceactionin16(enum scsi_service_action_in sa, uint32_t xferlen); -EXTERN struct scsi_task *scsi_cdb_readcapacity16(void); -EXTERN struct scsi_task *scsi_cdb_get_lba_status(uint64_t starting_lba, uint32_t alloc_len); -EXTERN struct scsi_task *scsi_cdb_unmap(int anchor, int group, uint16_t xferlen); -EXTERN struct scsi_task *scsi_cdb_persistent_reserve_in(enum scsi_persistent_in_sa sa, uint16_t xferlen); -EXTERN struct scsi_task *scsi_cdb_persistent_reserve_out(enum scsi_persistent_out_sa sa, enum scsi_persistent_out_scope scope, enum scsi_persistent_out_type type, void *params); +EXTERN struct scsi_task *scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); +EXTERN struct scsi_task *scsi_cdb_write12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); +EXTERN struct scsi_task *scsi_cdb_write16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_writesame10(int wrprotect, int anchor, int unmap, uint32_t lba, int group, uint16_t num_blocks); EXTERN struct scsi_task *scsi_cdb_writesame16(int wrprotect, int anchor, int unmap, uint64_t lba, int group, uint32_t num_blocks); -EXTERN struct scsi_task *scsi_cdb_prefetch10(uint32_t lba, int num_blocks, int immed, int group); -EXTERN struct scsi_task *scsi_cdb_prefetch16(uint64_t lba, int num_blocks, int immed, int group); -EXTERN struct scsi_task *scsi_cdb_report_supported_opcodes(int rctd, int options, enum scsi_opcode opcode, int sa, uint32_t alloc_len); +EXTERN struct scsi_task *scsi_cdb_writeverify10(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number); +EXTERN struct scsi_task *scsi_cdb_writeverify12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number); +EXTERN struct scsi_task *scsi_cdb_writeverify16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number); + void *scsi_malloc(struct scsi_task *task, size_t size); diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 3c02ace..c091539 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -806,12 +806,6 @@ scsi_persistentreservein_datain_unmarshall(struct scsi_task *task) } } -static inline int -scsi_maintenancein_return_timeouts(const struct scsi_task *task) -{ - return task->cdb[2] & 0x80; -} - static inline uint8_t scsi_maintenancein_sa(const struct scsi_task *task) { @@ -841,9 +835,7 @@ static void * scsi_maintenancein_datain_unmarshall(struct scsi_task *task) { struct scsi_report_supported_op_codes *rsoc; - struct scsi_command_descriptor *desc, *datain; - uint32_t len, i; - int return_timeouts, desc_size; + int len, i; switch (scsi_maintenancein_sa(task)) { case SCSI_REPORT_SUPPORTED_OP_CODES: @@ -852,37 +844,52 @@ scsi_maintenancein_datain_unmarshall(struct scsi_task *task) } len = task_get_uint32(task, 0); - rsoc = scsi_malloc(task, sizeof(struct scsi_report_supported_op_codes) + len); + /* len / 8 is not always correct since if CTDP==1 then the + * descriptor is 20 bytes in size intead of 8. + * It doesnt matter here though since it just means we would + * allocate more descriptors at the end of the structure than + * we strictly need. This avoids having to traverse the + * datain buffer twice. + */ + rsoc = scsi_malloc(task, + offsetof(struct scsi_report_supported_op_codes, + descriptors) + + len / 8 * sizeof(struct scsi_command_descriptor)); if (rsoc == NULL) { return NULL; } - /* Does the descriptor include command timeout info? */ - return_timeouts = scsi_maintenancein_return_timeouts(task); - /* Size of descriptor depends on whether timeout included. */ - desc_size = sizeof (struct scsi_command_descriptor); - if (return_timeouts) { - desc_size += sizeof (struct scsi_op_timeout_descriptor); - } - rsoc->num_descriptors = len / desc_size; + rsoc->num_descriptors = 0; + i = 4; + while (len >= 8) { + struct scsi_command_descriptor *desc; + + desc = &rsoc->descriptors[rsoc->num_descriptors++]; + desc->opcode = task_get_uint8(task, i); + desc->sa = task_get_uint16(task, i + 2); + desc->ctdp = !!(task_get_uint8(task, i + 5) & 0x02); + desc->servactv = !!(task_get_uint8(task, i + 5) & 0x01); + desc->cdb_len = task_get_uint16(task, i + 6); - desc = &rsoc->descriptors[0]; - datain = (struct scsi_command_descriptor *)&task->datain.data[4]; + len -= 8; + i += 8; - for (i=0; i < rsoc->num_descriptors; i++) { - desc->op_code = datain->op_code; - desc->service_action = ntohs(datain->service_action); - desc->cdb_length = ntohs(datain->cdb_length); - if (return_timeouts) { - desc->to[0].descriptor_length = ntohs(datain->to[0].descriptor_length); - desc->to[0].command_specific = datain->to[0].command_specific; - desc->to[0].nominal_processing_timeout - = ntohl(datain->to[0].nominal_processing_timeout); - desc->to[0].recommended_timeout - = ntohl(datain->to[0].recommended_timeout); + /* No tiemout description */ + if (!desc->ctdp) { + continue; } - desc = (struct scsi_command_descriptor *)((char *)desc + desc_size); - datain = (struct scsi_command_descriptor *)((char *)datain + desc_size); + + desc->to.descriptor_length = + task_get_uint16(task, i); + desc->to.command_specific = + task_get_uint8(task, i + 3); + desc->to.nominal_processing_timeout = + task_get_uint32(task, i + 4); + desc->to.recommended_timeout = + task_get_uint32(task, i + 8); + + len -= desc->to.descriptor_length + 2; + i += desc->to.descriptor_length + 2; } return rsoc; diff --git a/test-tool/0430_report_all_supported_ops.c b/test-tool/0430_report_all_supported_ops.c index e91b450..563b645 100644 --- a/test-tool/0430_report_all_supported_ops.c +++ b/test-tool/0430_report_all_supported_ops.c @@ -31,7 +31,7 @@ int T0430_report_all_supported_ops(const char *initiator, const char *url) struct scsi_command_descriptor *desc; int ret, lun; int full_size, desc_size; - unsigned i; + int i; printf("0430_report_all_supported_ops:\n"); printf("===================\n"); @@ -108,9 +108,9 @@ int T0430_report_all_supported_ops(const char *initiator, const char *url) printf("=======================\n"); for (i = 0; i < rsoc->num_descriptors; i++) { printf("op:%x\tsa:%x\tcdb length:%d\n", - rsoc->descriptors[i].op_code, - rsoc->descriptors[i].service_action, - rsoc->descriptors[i].cdb_length); + rsoc->descriptors[i].opcode, + rsoc->descriptors[i].sa, + rsoc->descriptors[i].cdb_len); } printf("\n[OK]\n"); @@ -179,13 +179,13 @@ int T0430_report_all_supported_ops(const char *initiator, const char *url) desc = &rsoc->descriptors[0]; for (i = 0; i < rsoc->num_descriptors; i++) { printf("op:%x\tsa:%x\tcdb_length:%d\ttimeout info: length:%d\tcommand specific:%x\tnominal processing%d\trecommended%d\n", - desc->op_code, - desc->service_action, - desc->cdb_length, - desc->to[0].descriptor_length, - desc->to[0].command_specific, - desc->to[0].nominal_processing_timeout, - desc->to[0].recommended_timeout); + desc->opcode, + desc->sa, + desc->cdb_len, + desc->to.descriptor_length, + desc->to.command_specific, + desc->to.nominal_processing_timeout, + desc->to.recommended_timeout); desc = (struct scsi_command_descriptor *)((char *)desc + desc_size); } diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 6e645ce..46cd785 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -2759,6 +2759,48 @@ release6(struct iscsi_context *iscsi, int lun) return 0; } +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) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send REPORT_SUPPORTED_OPCODE 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_GOOD) { + logging(LOG_NORMAL, "[FAILED] REPORT_SUPPORTED_OPCODES " + "command: failed with 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 SUCCESS."); + 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 f83e9c3..2ba770e 100644 --- a/test-tool/iscsi-support.h +++ b/test-tool/iscsi-support.h @@ -243,6 +243,7 @@ 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 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 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 02c3aa0..68074c7 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -221,6 +221,12 @@ static CU_TestInfo tests_readonly[] = { CU_TEST_INFO_NULL }; +static CU_TestInfo tests_report_supported_opcodes[] = { + { (char *)"ReportSupportedOpcodesSimple", test_report_supported_opcodes_simple }, + { (char *)"ReportSupportedOpcodesRCTD", test_report_supported_opcodes_rctd }, + CU_TEST_INFO_NULL +}; + static CU_TestInfo tests_reserve6[] = { { (char *)"Reserve6Simple", test_reserve6_simple }, { (char *)"Reserve6_2Initiators", test_reserve6_2initiators }, @@ -403,6 +409,8 @@ static CU_SuiteInfo scsi_suites[] = { tests_readcapacity16 }, { (char *)"ReadOnly", test_setup, test_teardown, tests_readonly }, + { (char *)"ReportSupportedOpcodes", test_setup, test_teardown, + tests_report_supported_opcodes }, { (char *)"Reserve6", test_setup, test_teardown, tests_reserve6 }, { (char *)"StartStopUnit", test_setup, test_teardown, @@ -505,6 +513,8 @@ static CU_SuiteInfo all_suites[] = { tests_readcapacity16 }, { (char *)"ReadOnly", test_setup, test_teardown, tests_readonly }, + { (char *)"ReportSupportedOpcodes", test_setup, test_teardown, + tests_report_supported_opcodes }, { (char *)"Reserve6", test_setup, test_teardown, tests_reserve6 }, { (char *)"StartStopUnit", test_setup, test_teardown, @@ -577,6 +587,8 @@ static CU_SuiteInfo scsi_usb_sbc_suites[] = { tests_readcapacity16 }, { (char *)"ReadOnly", test_setup, test_teardown, tests_readonly }, + { (char *)"ReportSupportedOpcodes", test_setup, test_teardown, + tests_report_supported_opcodes }, { (char *)"Reserve6", test_setup, test_teardown, tests_reserve6 }, { (char *)"TestUnitReady", test_setup, test_teardown, diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h index afb3b6b..2dd69a8 100644 --- a/test-tool/iscsi-test-cu.h +++ b/test-tool/iscsi-test-cu.h @@ -138,6 +138,9 @@ void test_readcapacity16_simple(void); void test_readonly_sbc(void); +void test_report_supported_opcodes_simple(void); +void test_report_supported_opcodes_rctd(void); + void test_reserve6_simple(void); void test_reserve6_2initiators(void); void test_reserve6_logout(void); diff --git a/test-tool/test_report_supported_opcodes_rctd.c b/test-tool/test_report_supported_opcodes_rctd.c new file mode 100644 index 0000000..33d0e97 --- /dev/null +++ b/test-tool/test_report_supported_opcodes_rctd.c @@ -0,0 +1,99 @@ +/* + 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_rctd(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 RCTD flag"); + + + logging(LOG_VERBOSE, "Test READ_SUPPORTED_OPCODES report ALL opcodes " + "without timeout descriptors"); + 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 that all returned command descriptors " + "lack timeout description"); + for (i = 0; i < rsoc->num_descriptors; i++) { + if (rsoc->descriptors[i].ctdp) { + logging(LOG_NORMAL, "[FAILED] Command descriptor with " + "CTDP set"); + CU_FAIL("[FAILED] Command descriptor with " + "CTDP set"); + } + } + scsi_free_scsi_task(rso_task); + + + logging(LOG_VERBOSE, "Test READ_SUPPORTED_OPCODES report ALL opcodes " + "with timeout descriptors"); + ret = report_supported_opcodes(iscsic, tgt_lun, + 1, SCSI_REPORT_SUPPORTING_OPS_ALL, 0, 0, + 65535, &rso_task); + 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 that all returned command descriptors " + "have a timeout description"); + for (i = 0; i < rsoc->num_descriptors; i++) { + if (!rsoc->descriptors[i].ctdp) { + logging(LOG_NORMAL, "[FAILED] Command descriptor " + "without CTDP set"); + CU_FAIL("[FAILED] Command descriptor without " + "CTDP set"); + } + } + + scsi_free_scsi_task(rso_task); +} diff --git a/test-tool/test_report_supported_opcodes_simple.c b/test-tool/test_report_supported_opcodes_simple.c new file mode 100644 index 0000000..f2435e6 --- /dev/null +++ b/test-tool/test_report_supported_opcodes_simple.c @@ -0,0 +1,46 @@ +/* + 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_simple(void) +{ + int ret; + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, "Test basic READ_SUPPORTED_OPCODES"); + + ret = report_supported_opcodes(iscsic, tgt_lun, + 0, SCSI_REPORT_SUPPORTING_OPS_ALL, 0, 0, + 1024, NULL); + 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); +}