TESTS: Add some REPORT SUPPORTED OPCODES tests

Add a simple test that it works or is not implemented.

Add a RCTD test to verify that with this flag clear we get command descriptors without CTDP set  and with it set we get command descriptors with CTDP set and a timeout descriptor
This commit is contained in:
Ronnie Sahlberg
2013-05-18 13:56:02 -07:00
parent ce4623b2fb
commit 709410b1d7
10 changed files with 286 additions and 76 deletions

View File

@@ -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 \

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -0,0 +1,99 @@
/*
Copyright (C) 2013 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <CUnit/CUnit.h>
#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);
}

View File

@@ -0,0 +1,46 @@
/*
Copyright (C) 2013 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <CUnit/CUnit.h>
#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);
}