Add support and tests for ExtendedCopy and ReceiveCopyResults

From sushma.gurram@sandisk.com
Add support to libiscsi and tests for these two opcodes.

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
This commit is contained in:
Ronnie Sahlberg
2015-08-02 11:47:29 -07:00
parent 4518dfa43c
commit a6f7c06119
17 changed files with 1170 additions and 6 deletions

View File

@@ -54,6 +54,8 @@ enum scsi_opcode {
SCSI_OPCODE_MODESENSE10 = 0x5A,
SCSI_OPCODE_PERSISTENT_RESERVE_IN = 0x5E,
SCSI_OPCODE_PERSISTENT_RESERVE_OUT = 0x5F,
SCSI_OPCODE_EXTENDED_COPY = 0x83,
SCSI_OPCODE_RECEIVE_COPY_RESULTS = 0x84,
SCSI_OPCODE_READ16 = 0x88,
SCSI_OPCODE_COMPARE_AND_WRITE = 0x89,
SCSI_OPCODE_WRITE16 = 0x8A,
@@ -148,7 +150,10 @@ enum scsi_sense_key {
EXTERN const char *scsi_sense_key_str(int key);
/* ascq */
#define SCSI_SENSE_ASCQ_NO_ADDL_SENSE 0x0000
#define SCSI_SENSE_ASCQ_SANITIZE_IN_PROGRESS 0x041b
#define SCSI_SENSE_ASCQ_UNREACHABLE_COPY_TARGET 0x0804
#define SCSI_SENSE_ASCQ_COPY_TARGET_DEVICE_NOT_REACHABLE 0x0d02
#define SCSI_SENSE_ASCQ_WRITE_AFTER_SANITIZE_REQUIRED 0x1115
#define SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR 0x1a00
#define SCSI_SENSE_ASCQ_MISCOMPARE_DURING_VERIFY 0x1d00
@@ -158,6 +163,10 @@ EXTERN const char *scsi_sense_key_str(int key);
#define SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB 0x2400
#define SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED 0x2500
#define SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST 0x2600
#define SCSI_SENSE_ASCQ_TOO_MANY_TARGET_DESCRIPTORS 0x2606
#define SCSI_SENSE_ASCQ_UNSUPPORTED_TARGET_DESCRIPTOR_TYPE_CODE 0x2607
#define SCSI_SENSE_ASCQ_TOO_MANY_SEGMENT_DESCRIPTORS 0x2608
#define SCSI_SENSE_ASCQ_UNSUPPORTED_SEGMENT_DESCRIPTOR_TYPE_CODE 0x2609
#define SCSI_SENSE_ASCQ_WRITE_PROTECTED 0x2700
#define SCSI_SENSE_ASCQ_HARDWARE_WRITE_PROTECTED 0x2701
#define SCSI_SENSE_ASCQ_SOFTWARE_WRITE_PROTECTED 0x2702
@@ -348,7 +357,6 @@ EXTERN struct scsi_task *scsi_cdb_testunitready(void);
EXTERN struct scsi_task *scsi_cdb_sanitize(int immed, int ause, int sa,
int param_len);
/*
* REPORTLUNS
*/
@@ -1095,6 +1103,78 @@ EXTERN struct scsi_task *scsi_cdb_writeverify12(uint32_t lba, uint32_t xferlen,
EXTERN struct scsi_task *scsi_cdb_writeverify16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number);
/*
* EXTENDED COPY
*/
#define XCOPY_DESC_OFFSET 16
#define SEG_DESC_SRC_INDEX_OFFSET 4
enum list_id_usage {
LIST_ID_USAGE_HOLD = 0,
LIST_ID_USAGE_DISCARD = 2,
LIST_ID_USAGE_DISABLE = 3
};
enum ec_descr_type_code {
/* Segment descriptors : 0x00 to 0xBF */
BLK_TO_STRM_SEG_DESCR = 0x00,
STRM_TO_BLK_SEG_DESCR = 0x01,
BLK_TO_BLK_SEG_DESCR = 0x02,
STRM_TO_STRM_SEG_DESCR = 0x03,
/* Target descriptors : 0xEO to 0xFE */
IDENT_DESCR_TGT_DESCR = 0xE4,
IPV4_TGT_DESCR = 0xE5,
IPV6_TGT_DESCR = 0xEA,
IP_COPY_SVC_TGT_DESCR = 0xEB
};
enum lu_id_type {
LU_ID_TYPE_LUN = 0x00,
LU_ID_TYPE_PROXY_TOKEN = 0x01,
LU_ID_TYPE_RSVD = 0x02,
LU_ID_TYPE_RSVD1 = 0x03
};
EXTERN struct scsi_task *scsi_cdb_extended_copy(int immed);
/*
* RECEIVE COPY RESULTS
*/
enum scsi_copy_results_sa {
SCSI_COPY_RESULTS_COPY_STATUS = 0,
SCSI_COPY_RESULTS_RECEIVE_DATA = 1,
SCSI_COPY_RESULTS_OP_PARAMS = 3,
SCSI_COPY_RESULTS_FAILED_SEGMENT = 4,
};
EXTERN struct scsi_task *scsi_cdb_receive_copy_results(enum scsi_copy_results_sa sa, int list_id, int xferlen);
struct scsi_copy_results_copy_status {
uint32_t available_data;
uint8_t copy_manager_status;
uint8_t hdd;
uint16_t segments_processed;
uint8_t transfer_count_units;
uint32_t transfer_count;
};
struct scsi_copy_results_op_params {
uint32_t available_data;
uint16_t max_target_desc_count;
uint16_t max_segment_desc_count;
uint32_t max_desc_list_length;
uint32_t max_segment_length;
uint32_t max_inline_data_length;
uint32_t held_data_limit;
uint32_t max_stream_device_transfer_size;
uint16_t total_concurrent_copies;
uint8_t max_concurrent_copies;
uint8_t data_segment_granularity;
uint8_t inline_data_granularity;
uint8_t held_data_granularity;
uint8_t impl_desc_list_length;
uint8_t imp_desc_type_codes[0];
};
void *scsi_malloc(struct scsi_task *task, size_t size);
uint64_t scsi_get_uint64(const unsigned char *c);

View File

@@ -159,6 +159,7 @@ iscsi_writesame16_sync
iscsi_writesame16_task
scsi_association_to_str
scsi_cdb_compareandwrite
scsi_cdb_extended_copy
scsi_cdb_inquiry
scsi_cdb_get_lba_status
scsi_cdb_modeselect6
@@ -177,6 +178,7 @@ scsi_cdb_read6
scsi_cdb_readcapacity10
scsi_cdb_readcapacity16
scsi_cdb_readtoc
scsi_cdb_receive_copy_results
scsi_cdb_reserve6
scsi_cdb_release6
scsi_cdb_report_supported_opcodes

View File

@@ -157,6 +157,7 @@ iscsi_writesame16_sync
iscsi_writesame16_task
scsi_association_to_str
scsi_cdb_compareandwrite
scsi_cdb_extended_copy
scsi_cdb_inquiry
scsi_cdb_get_lba_status
scsi_cdb_modeselect6
@@ -175,6 +176,7 @@ scsi_cdb_read6
scsi_cdb_readcapacity10
scsi_cdb_readcapacity16
scsi_cdb_readtoc
scsi_cdb_receive_copy_results
scsi_cdb_reserve6
scsi_cdb_release6
scsi_cdb_report_supported_opcodes

View File

@@ -834,6 +834,61 @@ scsi_persistentreservein_datain_getfullsize(struct scsi_task *task)
}
}
static void *
scsi_receivecopyresults_datain_unmarshall(struct scsi_task *task)
{
int sa = task->cdb[1] & 0x1f;
int len, i;
struct scsi_copy_results_copy_status *cs;
struct scsi_copy_results_op_params *op;
switch (sa) {
case SCSI_COPY_RESULTS_COPY_STATUS:
len = task_get_uint32(task, 0);
cs = scsi_malloc(task, len+4);
if (cs == NULL) {
return NULL;
}
cs->available_data = len;
cs->copy_manager_status = task_get_uint8(task, 4) & 0x7F;
cs->hdd = (task_get_uint8(task, 4) & 0x80) >> 7;
cs->segments_processed = task_get_uint16(task, 5);
cs->transfer_count_units = task_get_uint8(task, 7);
cs->transfer_count = task_get_uint32(task, 8);
return cs;
case SCSI_COPY_RESULTS_OP_PARAMS:
len = task_get_uint32(task, 0);
op = scsi_malloc(task, len+4);
if (op == NULL) {
return NULL;
}
op->available_data = len;
op->max_target_desc_count = task_get_uint16(task, 8);
op->max_segment_desc_count = task_get_uint16(task, 10);
op->max_desc_list_length = task_get_uint32(task, 12);
op->max_segment_length = task_get_uint32(task, 16);
op->max_inline_data_length = task_get_uint32(task, 20);
op->held_data_limit = task_get_uint32(task, 24);
op->max_stream_device_transfer_size = task_get_uint32(task, 28);
op->total_concurrent_copies = task_get_uint16(task, 34);
op->max_concurrent_copies = task_get_uint8(task, 36);
op->data_segment_granularity = task_get_uint8(task, 37);
op->inline_data_granularity = task_get_uint8(task, 38);
op->held_data_granularity = task_get_uint8(task, 39);
op->impl_desc_list_length = task_get_uint8(task, 43);
for (i = 0; i < (int)op->impl_desc_list_length; i++) {
op->imp_desc_type_codes[i] = task_get_uint8(task, 44+i);
}
return op;
default:
return NULL;
}
}
static void *
scsi_persistentreservein_datain_unmarshall(struct scsi_task *task)
{
@@ -3230,6 +3285,63 @@ scsi_cdb_writeverify16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprot
return task;
}
/*
* EXTENDED COPY
*/
struct scsi_task *
scsi_cdb_extended_copy(int param_len)
{
struct scsi_task *task;
task = malloc(sizeof(struct scsi_task));
if (task == NULL)
return NULL;
memset(task, 0, sizeof(struct scsi_task));
task->cdb[0] = SCSI_OPCODE_EXTENDED_COPY;
task->cdb[10] = (param_len >> 24) & 0xFF;
task->cdb[11] = (param_len >> 16) & 0xFF;
task->cdb[12] = (param_len >> 8) & 0xFF;
task->cdb[13] = param_len & 0xFF;
/* Inititalize other fields in CDB */
task->cdb_size = 16;
task->xfer_dir = SCSI_XFER_WRITE;
task->expxferlen = param_len;
return task;
}
/*
* RECEIVE COPY RESULTS
*/
struct scsi_task *
scsi_cdb_receive_copy_results(enum scsi_copy_results_sa sa, int list_id, int xferlen)
{
struct scsi_task *task;
task = malloc(sizeof(struct scsi_task));
if (task == NULL) {
return NULL;
}
memset(task, 0, sizeof(struct scsi_task));
task->cdb[0] = SCSI_OPCODE_RECEIVE_COPY_RESULTS;
task->cdb[1] |= sa & 0x1f;
task->cdb[2] = list_id & 0xFF;
scsi_set_uint32(&task->cdb[10], xferlen);
task->cdb_size = 16;
if (xferlen != 0) {
task->xfer_dir = SCSI_XFER_READ;
} else {
task->xfer_dir = SCSI_XFER_NONE;
}
task->expxferlen = xferlen;
return task;
}
int
scsi_datain_getfullsize(struct scsi_task *task)
{
@@ -3281,6 +3393,8 @@ scsi_datain_unmarshall(struct scsi_task *task)
return scsi_persistentreservein_datain_unmarshall(task);
case SCSI_OPCODE_MAINTENANCE_IN:
return scsi_maintenancein_datain_unmarshall(task);
case SCSI_OPCODE_RECEIVE_COPY_RESULTS:
return scsi_receivecopyresults_datain_unmarshall(task);
}
return NULL;
}

View File

@@ -19,6 +19,12 @@ iscsi_test_cu_SOURCES = iscsi-test-cu.c \
test_compareandwrite_simple.c \
test_compareandwrite_dpofua.c \
test_compareandwrite_miscompare.c \
test_extendedcopy_simple.c \
test_extendedcopy_param.c \
test_extendedcopy_descr_limits.c \
test_extendedcopy_descr_type.c \
test_extendedcopy_validate_tgt_descr.c \
test_extendedcopy_validate_seg_descr.c \
test_get_lba_status_simple.c \
test_get_lba_status_beyond_eol.c \
test_get_lba_status_unmap_single.c \
@@ -93,6 +99,8 @@ iscsi_test_cu_SOURCES = iscsi-test-cu.c \
test_readcapacity16_protection.c \
test_readcapacity16_simple.c \
test_readonly_sbc.c \
test_receive_copy_results_copy_status.c \
test_receive_copy_results_op_params.c \
test_report_supported_opcodes_one_command.c \
test_report_supported_opcodes_rctd.c \
test_report_supported_opcodes_servactv.c \

View File

@@ -63,8 +63,12 @@ int no_medium_ascqs[3] = {
int lba_oob_ascqs[1] = {
SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE
};
int invalid_cdb_ascqs[1] = {
SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB
int invalid_cdb_ascqs[2] = {
SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB,
SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST
};
int param_list_len_err_ascqs[1] = {
SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR
};
int write_protect_ascqs[3] = {
SCSI_SENSE_ASCQ_WRITE_PROTECTED,
@@ -80,6 +84,19 @@ int removal_ascqs[1] = {
int miscompare_ascqs[1] = {
SCSI_SENSE_ASCQ_MISCOMPARE_DURING_VERIFY
};
int too_many_desc_ascqs[2] = {
SCSI_SENSE_ASCQ_TOO_MANY_TARGET_DESCRIPTORS,
SCSI_SENSE_ASCQ_TOO_MANY_SEGMENT_DESCRIPTORS,
};
int unsupp_desc_code_ascqs[2] = {
SCSI_SENSE_ASCQ_UNSUPPORTED_TARGET_DESCRIPTOR_TYPE_CODE,
SCSI_SENSE_ASCQ_UNSUPPORTED_SEGMENT_DESCRIPTOR_TYPE_CODE
};
int copy_aborted_ascqs[3] = {
SCSI_SENSE_ASCQ_NO_ADDL_SENSE,
SCSI_SENSE_ASCQ_UNREACHABLE_COPY_TARGET,
SCSI_SENSE_ASCQ_COPY_TARGET_DEVICE_NOT_REACHABLE
};
struct scsi_inquiry_standard *inq;
struct scsi_inquiry_logical_block_provisioning *inq_lbp;
@@ -2528,3 +2545,217 @@ finished:
}
return ret;
}
/* Extended Copy */
int extendedcopy(struct scsi_device *sdev, struct iscsi_data *data, int status, enum scsi_sense_key key, int *ascq, int num_ascq)
{
struct scsi_task *task;
int ret;
logging(LOG_VERBOSE, "Send EXTENDED COPY (Expecting %s)",
scsi_status_str(status));
if (!data_loss) {
logging(LOG_NORMAL, "--dataloss flag is not set in. Skipping extendedcopy\n");
return -1;
}
task = scsi_cdb_extended_copy(data->size);
assert(task != NULL);
send_scsi_command(sdev, task, data);
ret = check_result("EXTENDEDCOPY", sdev, task, status, key, ascq, num_ascq);
scsi_free_scsi_task(task);
return ret;
}
int get_desc_len(enum ec_descr_type_code desc_type)
{
int desc_len = 0;
switch (desc_type) {
/* Segment Descriptors */
case BLK_TO_STRM_SEG_DESCR:
case STRM_TO_BLK_SEG_DESCR:
desc_len = 0x18;
break;
case BLK_TO_BLK_SEG_DESCR:
desc_len = 0x1C;
break;
case STRM_TO_STRM_SEG_DESCR:
desc_len = 0x14;
break;
/* Target Descriptors */
case IPV6_TGT_DESCR:
case IP_COPY_SVC_TGT_DESCR:
desc_len = 64;
break;
case IDENT_DESCR_TGT_DESCR:
default:
if (desc_type >= 0xE0 && desc_type <= 0xE9)
desc_len = 32;
}
return desc_len;
}
void populate_ident_tgt_desc(unsigned char *buf, struct scsi_device *dev)
{
int ret;
struct scsi_task *inq_di_task = NULL;
struct scsi_inquiry_device_identification *inq_di = NULL;
struct scsi_inquiry_device_designator *desig, *tgt_desig = NULL;
enum scsi_designator_type prev_type = 0;
ret = inquiry(dev, &inq_di_task, 1, SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION, 255, EXPECT_STATUS_GOOD);
if (ret < 0 || inq_di_task == NULL) {
logging(LOG_NORMAL, "Failed to read Device Identification page");
goto finished;
} else {
inq_di = scsi_datain_unmarshall(inq_di_task);
if (inq_di == NULL) {
logging(LOG_NORMAL, "Failed to unmarshall inquiry datain blob");
goto finished;
}
}
for (desig = inq_di->designators; desig; desig = desig->next) {
switch (desig->designator_type) {
case SCSI_DESIGNATOR_TYPE_VENDOR_SPECIFIC:
case SCSI_DESIGNATOR_TYPE_T10_VENDORT_ID:
case SCSI_DESIGNATOR_TYPE_EUI_64:
case SCSI_DESIGNATOR_TYPE_NAA:
if (prev_type <= desig->designator_type) {
tgt_desig = desig;
prev_type = desig->designator_type;
}
default:
continue;
}
}
if (tgt_desig == NULL) {
logging(LOG_NORMAL, "No suitalble target descriptor format found");
goto finished;
}
buf[0] = tgt_desig->code_set;
buf[1] = (tgt_desig->designator_type & 0xF) | ((tgt_desig->association & 3) << 4);
buf[3] = tgt_desig->designator_length;
memcpy(buf + 4, tgt_desig->designator, tgt_desig->designator_length);
finished:
scsi_free_scsi_task(inq_di_task);
}
int populate_tgt_desc(unsigned char *desc, enum ec_descr_type_code desc_type, int luid_type, int nul, int peripheral_type, int rel_init_port_id, int pad, struct scsi_device *dev)
{
desc[0] = desc_type;
desc[1] = (luid_type << 6) | (nul << 5) | peripheral_type;
desc[2] = (rel_init_port_id >> 8) & 0xFF;
desc[3] = rel_init_port_id & 0xFF;
if (desc_type == IDENT_DESCR_TGT_DESCR)
populate_ident_tgt_desc(desc+4, dev);
if (peripheral_type == 0) {
// Issue readcapacity for each sd if testing with different LUs
// If single LU, use block_size from prior readcapacity involcation
desc[28] = pad << 2;
desc[29] = (block_size >> 16) & 0xFF;
desc[30] = (block_size >> 8) & 0xFF;
desc[31] = block_size & 0xFF;
}
return get_desc_len(desc_type);
}
int populate_seg_desc_hdr(unsigned char *hdr, enum ec_descr_type_code desc_type, int dc, int cat, int src_index, int dst_index)
{
int desc_len = get_desc_len(desc_type);
hdr[0] = desc_type;
hdr[1] = ((dc << 1) | cat) & 0xFF;
hdr[2] = (desc_len >> 8) & 0xFF;
hdr[3] = (desc_len - SEG_DESC_SRC_INDEX_OFFSET) & 0xFF; /* don't account for the first 4 bytes in descriptor header*/
hdr[4] = (src_index >> 8) & 0xFF;
hdr[5] = src_index & 0xFF;
hdr[6] = (dst_index >> 8) & 0xFF;
hdr[7] = dst_index & 0xFF;
return desc_len;
}
int populate_seg_desc_b2b(unsigned char *desc, int dc, int cat, int src_index, int dst_index, int num_blks, uint64_t src_lba, uint64_t dst_lba)
{
int desc_len = populate_seg_desc_hdr(desc, BLK_TO_BLK_SEG_DESCR, dc, cat, src_index, dst_index);
desc[10] = (num_blks >> 8) & 0xFF;
desc[11] = num_blks & 0xFF;
desc[12] = (src_lba >> 56) & 0xFF;
desc[13] = (src_lba >> 48) & 0xFF;
desc[14] = (src_lba >> 40) & 0xFF;
desc[15] = (src_lba >> 32) & 0xFF;
desc[16] = (src_lba >> 24) & 0xFF;
desc[17] = (src_lba >> 16) & 0xFF;
desc[18] = (src_lba >> 8) & 0xFF;
desc[19] = src_lba & 0xFF;
desc[20] = (dst_lba >> 56) & 0xFF;
desc[21] = (dst_lba >> 48) & 0xFF;
desc[22] = (dst_lba >> 40) & 0xFF;
desc[23] = (dst_lba >> 32) & 0xFF;
desc[24] = (dst_lba >> 24) & 0xFF;
desc[25] = (dst_lba >> 16) & 0xFF;
desc[26] = (dst_lba >> 8) & 0xFF;
desc[27] = dst_lba & 0xFF;
return desc_len;
}
void populate_param_header(unsigned char *buf, int list_id, int str, int list_id_usage, int prio, int tgt_desc_len, int seg_desc_len, int inline_data_len)
{
buf[0] = list_id;
buf[1] = ((str & 1) << 5) | ((list_id_usage & 3) << 3) | (prio & 7);
buf[2] = (tgt_desc_len >> 8) & 0xFF;
buf[3] = tgt_desc_len & 0xFF;
buf[8] = (seg_desc_len >> 24) & 0xFF;
buf[9] = (seg_desc_len >> 16) & 0xFF;
buf[10] = (seg_desc_len >> 8) & 0xFF;
buf[11] = seg_desc_len & 0xFF;
buf[12] = (inline_data_len >> 24) & 0xFF;
buf[13] = (inline_data_len >> 16) & 0xFF;
buf[14] = (inline_data_len >> 8) & 0xFF;
buf[15] = inline_data_len & 0xFF;
}
int receive_copy_results(struct scsi_device *sdev, enum scsi_copy_results_sa sa, int list_id, void **datap, int status, enum scsi_sense_key key, int *ascq, int num_ascq)
{
int ret;
struct scsi_task *task;
logging(LOG_VERBOSE, "Send RECEIVE COPY RESULTS");
task = scsi_cdb_receive_copy_results(sa, list_id, 1024);
assert(task != NULL);
task = send_scsi_command(sdev, task, NULL);
ret = check_result("RECEIVECOPYRESULT", sdev, task, status, key, ascq, num_ascq);
if (task->status == SCSI_STATUS_GOOD && datap != NULL) {
*datap = scsi_datain_unmarshall(task);
if (*datap == NULL) {
logging(LOG_NORMAL,
"[FAIL] failed to unmarshall RECEIVE COPY RESULTS data. %s",
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
}
ret = check_result("RECEIVECOPYRESULT", sdev, task, status, key, ascq, num_ascq);
if (task)
scsi_free_scsi_task(task);
return ret;
}

View File

@@ -37,20 +37,28 @@ extern const char *initiatorname2;
#define EXPECT_STATUS_GOOD SCSI_STATUS_GOOD, SCSI_SENSE_NO_SENSE, NULL, 0
#define EXPECT_NO_MEDIUM SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_NOT_READY, no_medium_ascqs, 3
#define EXPECT_LBA_OOB SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ILLEGAL_REQUEST, lba_oob_ascqs, 1
#define EXPECT_INVALID_FIELD_IN_CDB SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ILLEGAL_REQUEST, invalid_cdb_ascqs, 1
#define EXPECT_INVALID_FIELD_IN_CDB SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ILLEGAL_REQUEST, invalid_cdb_ascqs,2
#define EXPECT_PARAM_LIST_LEN_ERR SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ILLEGAL_REQUEST, param_list_len_err_ascqs, 1
#define EXPECT_TOO_MANY_DESCR SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ILLEGAL_REQUEST, too_many_desc_ascqs, 2
#define EXPECT_UNSUPP_DESCR_CODE SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ILLEGAL_REQUEST, unsupp_desc_code_ascqs, 2
#define EXPECT_MISCOMPARE SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_MISCOMPARE, miscompare_ascqs, 1
#define EXPECT_WRITE_PROTECTED SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_DATA_PROTECTION, write_protect_ascqs, 3
#define EXPECT_SANITIZE SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_NOT_READY, sanitize_ascqs, 1
#define EXPECT_REMOVAL_PREVENTED SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_ILLEGAL_REQUEST, removal_ascqs, 1
#define EXPECT_RESERVATION_CONFLICT SCSI_STATUS_RESERVATION_CONFLICT, 0, NULL, 0
#define EXPECT_COPY_ABORTED SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_COPY_ABORTED, copy_aborted_ascqs, 3
int no_medium_ascqs[3];
int lba_oob_ascqs[1];
int invalid_cdb_ascqs[1];
int invalid_cdb_ascqs[2];
int param_list_len_err_ascqs[1];
int too_many_desc_ascqs[2];
int unsupp_desc_code_ascqs[2];
int write_protect_ascqs[3];
int sanitize_ascqs[1];
int removal_ascqs[1];
int miscompare_ascqs[1];
int copy_aborted_ascqs[3];
extern int loglevel;
#define LOG_SILENT 0
@@ -314,5 +322,11 @@ int writeverify16(struct scsi_device *sdev, uint64_t lba, uint32_t datalen, int
int set_swp(struct scsi_device *sdev);
int clear_swp(struct scsi_device *sdev);
int extendedcopy(struct scsi_device *sdev, struct iscsi_data *data, int status, enum scsi_sense_key key, int *ascq, int num_ascq);
int get_desc_len(enum ec_descr_type_code desc_type);
int populate_tgt_desc(unsigned char *desc, enum ec_descr_type_code desc_type, int luid_type, int nul, int peripheral_type, int rel_init_port_id, int pad, struct scsi_device *dev);
int populate_seg_desc_hdr(unsigned char *hdr, enum ec_descr_type_code desc_type, int dc, int cat, int src_index, int dst_index);
int populate_seg_desc_b2b(unsigned char *desc, int dc, int cat, int src_index, int dst_index, int num_blks, uint64_t src_lba, uint64_t dst_lba);
void populate_param_header(unsigned char *buf, int list_id, int str, int list_id_usage, int prio, int tgt_desc_len, int seg_desc_len, int inline_data_len);
int receive_copy_results(struct scsi_device *sdev, enum scsi_copy_results_sa sa, int list_id, void **datap, int status, enum scsi_sense_key key, int *ascq, int num_ascq);
#endif /* _ISCSI_SUPPORT_H_ */

View File

@@ -262,6 +262,22 @@ static CU_TestInfo tests_sanitize[] = {
CU_TEST_INFO_NULL
};
static CU_TestInfo tests_extended_copy[] = {
{ (char *)"Simple", test_extendedcopy_simple },
{ (char *)"ParamHdr", test_extendedcopy_param },
{ (char *)"DescrLimits", test_extendedcopy_descr_limits },
{ (char *)"DescrType", test_extendedcopy_descr_type },
{ (char *)"ValidTgtDescr", test_extendedcopy_validate_tgt_descr },
{ (char *)"ValidSegDescr", test_extendedcopy_validate_seg_descr },
CU_TEST_INFO_NULL
};
static CU_TestInfo tests_receive_copy_results[] = {
{ (char *)"CopyStatus", test_receive_copy_results_copy_status },
{ (char *)"OpParams", test_receive_copy_results_op_params },
CU_TEST_INFO_NULL
};
static CU_TestInfo tests_report_supported_opcodes[] = {
{ (char *)"Simple", test_report_supported_opcodes_simple },
{ (char *)"OneCommand", test_report_supported_opcodes_one_command },
@@ -436,6 +452,7 @@ typedef struct libiscsi_suite_info {
/* SCSI protocol tests */
static libiscsi_suite_info scsi_suites[] = {
{ "CompareAndWrite", NON_PGR_FUNCS, tests_compareandwrite },
{ "ExtendedCopy", NON_PGR_FUNCS, tests_extended_copy },
{ "GetLBAStatus", NON_PGR_FUNCS, tests_get_lba_status },
{ "Inquiry", NON_PGR_FUNCS, tests_inquiry },
{ "Mandatory", NON_PGR_FUNCS, tests_mandatory },
@@ -456,6 +473,7 @@ static libiscsi_suite_info scsi_suites[] = {
{ "ReadCapacity10", NON_PGR_FUNCS, tests_readcapacity10 },
{ "ReadCapacity16", NON_PGR_FUNCS, tests_readcapacity16 },
{ "ReadOnly", NON_PGR_FUNCS, tests_readonly },
{ "ReceiveCopyResults", NON_PGR_FUNCS, tests_receive_copy_results },
{ "ReportSupportedOpcodes", NON_PGR_FUNCS,
tests_report_supported_opcodes },
{ "Reserve6", NON_PGR_FUNCS, tests_reserve6 },
@@ -517,6 +535,7 @@ static libiscsi_suite_info iscsi_suites[] = {
/* All tests */
static libiscsi_suite_info all_suites[] = {
{ "CompareAndWrite", NON_PGR_FUNCS, tests_compareandwrite },
{ "ExtendedCopy", NON_PGR_FUNCS, tests_extended_copy },
{ "GetLBAStatus", NON_PGR_FUNCS, tests_get_lba_status },
{ "Inquiry", NON_PGR_FUNCS, tests_inquiry },
{ "Mandatory", NON_PGR_FUNCS, tests_mandatory },
@@ -538,6 +557,7 @@ static libiscsi_suite_info all_suites[] = {
{ "ReadCapacity10", NON_PGR_FUNCS, tests_readcapacity10 },
{ "ReadCapacity16", NON_PGR_FUNCS, tests_readcapacity16 },
{ "ReadOnly", NON_PGR_FUNCS, tests_readonly },
{ "ReceiveCopyResults", NON_PGR_FUNCS, tests_receive_copy_results },
{ "ReportSupportedOpcodes", NON_PGR_FUNCS,
tests_report_supported_opcodes },
{ "Reserve6", NON_PGR_FUNCS, tests_reserve6 },

View File

@@ -52,6 +52,13 @@ void test_compareandwrite_simple(void);
void test_compareandwrite_dpofua(void);
void test_compareandwrite_miscompare(void);
void test_extendedcopy_simple(void);
void test_extendedcopy_param(void);
void test_extendedcopy_descr_limits(void);
void test_extendedcopy_descr_type(void);
void test_extendedcopy_validate_tgt_descr(void);
void test_extendedcopy_validate_seg_descr(void);
void test_get_lba_status_simple(void);
void test_get_lba_status_beyond_eol(void);
void test_get_lba_status_unmap_single(void);
@@ -158,6 +165,9 @@ void test_readcapacity16_simple(void);
void test_readonly_sbc(void);
void test_receive_copy_results_copy_status(void);
void test_receive_copy_results_op_params(void);
void test_report_supported_opcodes_one_command(void);
void test_report_supported_opcodes_rctd(void);
void test_report_supported_opcodes_servactv(void);

View File

@@ -0,0 +1,120 @@
/*
Copyright (c) 2015 SanDisk Corp.
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 <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <CUnit/CUnit.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test-cu.h"
int init_xcopy_descr(unsigned char *buf, int offset, int num_tgt_desc,
int num_seg_desc, int *tgt_desc_len, int *seg_desc_len)
{
int i;
/* Initialize target descriptor list with num_tgt_desc
* target descriptor */
for (i = 0; i < num_tgt_desc; i++)
offset += populate_tgt_desc(buf+offset, IDENT_DESCR_TGT_DESCR,
LU_ID_TYPE_LUN, 0, 0, 0, 0, sd);
*tgt_desc_len = offset - XCOPY_DESC_OFFSET;
/* Iniitialize segment descriptor list with num_seg_desc
* segment descriptor */
for (i = 0; i < num_seg_desc; i++)
offset += populate_seg_desc_b2b(buf+offset, 0, 0, 0, 0,
2048, 0, num_blocks - 2048);
*seg_desc_len = offset - XCOPY_DESC_OFFSET - *tgt_desc_len;
return offset;
}
void
test_extendedcopy_descr_limits(void)
{
int ret;
struct iscsi_data data;
unsigned char *xcopybuf;
struct scsi_copy_results_op_params *opp;
int tgt_desc_len = 0, seg_desc_len = 0;
unsigned int alloc_len;
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE, "Test EXTENDED COPY descriptor limits");
CHECK_FOR_DATALOSS;
logging(LOG_VERBOSE, "Issue RECEIVE COPY RESULTS (OPERATING PARAMS)");
ret = receive_copy_results(sd, SCSI_COPY_RESULTS_OP_PARAMS, 0,
(void **)&opp, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
/* Allocate buffer to accommodate (MAX+1) target and
* segment descriptors */
alloc_len = XCOPY_DESC_OFFSET +
(opp->max_target_desc_count+1) *
get_desc_len(IDENT_DESCR_TGT_DESCR) +
(opp->max_segment_desc_count+1) *
get_desc_len(BLK_TO_BLK_SEG_DESCR);
data.data = alloca(alloc_len);
xcopybuf = data.data;
logging(LOG_VERBOSE,
"Test sending more than supported target descriptors");
data.size = init_xcopy_descr(xcopybuf, XCOPY_DESC_OFFSET,
(opp->max_target_desc_count+1), 1,
&tgt_desc_len, &seg_desc_len);
populate_param_header(xcopybuf, 1, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_TOO_MANY_DESCR);
if (ret == -2) {
CU_PASS("[SKIPPED] Target does not support "
"EXTENDED_COPY. Skipping test");
return;
}
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_VERBOSE,
"Test sending more than supported segment descriptors");
memset(xcopybuf, 0, alloc_len);
data.size = init_xcopy_descr(xcopybuf, XCOPY_DESC_OFFSET, 1,
(opp->max_segment_desc_count+1),
&tgt_desc_len, &seg_desc_len);
populate_param_header(xcopybuf, 2, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_TOO_MANY_DESCR);
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_VERBOSE,
"Test sending descriptors > Maximum Descriptor List Length");
memset(xcopybuf, 0, alloc_len);
if (opp->max_desc_list_length < alloc_len) {
data.size = init_xcopy_descr(xcopybuf, XCOPY_DESC_OFFSET,
(opp->max_target_desc_count+1),
(opp->max_segment_desc_count+1),
&tgt_desc_len, &seg_desc_len);
populate_param_header(xcopybuf, 3, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_PARAM_LIST_LEN_ERR);
CU_ASSERT_EQUAL(ret, 0);
}
}

View File

@@ -0,0 +1,93 @@
/*
Copyright (c) 2015 SanDisk Corp.
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 <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <CUnit/CUnit.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test-cu.h"
int init_xcopybuf(unsigned char *buf, int tgt_desc_type, int seg_desc_type,
int *tgt_desc_len, int *seg_desc_len)
{
int offset = XCOPY_DESC_OFFSET;
offset += populate_tgt_desc(buf+offset, tgt_desc_type, LU_ID_TYPE_LUN,
0, 0, 0, 0, sd);
*tgt_desc_len = offset - XCOPY_DESC_OFFSET;
if (seg_desc_type == BLK_TO_BLK_SEG_DESCR)
offset += populate_seg_desc_b2b(buf+offset, 0, 0, 0, 0, 2048, 0,
num_blocks - 2048);
else
offset += populate_seg_desc_hdr(buf+offset, seg_desc_type,
0, 0, 0, 0);
*seg_desc_len = offset - XCOPY_DESC_OFFSET - *tgt_desc_len;
return offset;
}
void
test_extendedcopy_descr_type(void)
{
int ret;
int tgt_desc_len = 0, seg_desc_len = 0, alloc_len;
struct iscsi_data data;
unsigned char *xcopybuf;
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE,
"Test EXTENDED COPY unsupported descriptor types");
CHECK_FOR_DATALOSS;
alloc_len = XCOPY_DESC_OFFSET +
get_desc_len(IDENT_DESCR_TGT_DESCR) +
get_desc_len(BLK_TO_BLK_SEG_DESCR);
data.data = alloca(alloc_len);
xcopybuf = data.data;
logging(LOG_VERBOSE,
"Send Fibre Channel N_Port_Name target descriptor");
data.size = init_xcopybuf(xcopybuf, 0xE0, BLK_TO_BLK_SEG_DESCR,
&tgt_desc_len, &seg_desc_len);
populate_param_header(xcopybuf, 1, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_UNSUPP_DESCR_CODE);
if (ret == -2) {
CU_PASS("[SKIPPED] Target does not support "
"EXTENDED_COPY. Skipping test");
return;
}
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_VERBOSE, "Send Stream-to-Stream Copy segment descriptor");
memset(xcopybuf, 0, alloc_len);
data.size = init_xcopybuf(xcopybuf, IDENT_DESCR_TGT_DESCR,
STRM_TO_STRM_SEG_DESCR,
&tgt_desc_len, &seg_desc_len);
populate_param_header(xcopybuf, 1, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_UNSUPP_DESCR_CODE);
CU_ASSERT_EQUAL(ret, 0);
}

View File

@@ -0,0 +1,83 @@
/*
Copyright (c) 2015 SanDisk Corp.
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 <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <CUnit/CUnit.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test-cu.h"
void
test_extendedcopy_param(void)
{
int ret;
int tgt_desc_len = 0, seg_desc_len = 0, offset = XCOPY_DESC_OFFSET;
struct iscsi_data data;
unsigned char *xcopybuf;
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE, "Test EXTENDED COPY parameter list length");
CHECK_FOR_DATALOSS;
data.size = XCOPY_DESC_OFFSET +
get_desc_len(IDENT_DESCR_TGT_DESCR) +
get_desc_len(BLK_TO_BLK_SEG_DESCR);
data.data = alloca(data.size);
xcopybuf = data.data;
offset += populate_tgt_desc(xcopybuf+offset, IDENT_DESCR_TGT_DESCR,
LU_ID_TYPE_LUN, 0, 0, 0, 0, sd);
tgt_desc_len = offset - XCOPY_DESC_OFFSET;
offset += populate_seg_desc_b2b(xcopybuf+offset, 0, 0, 0, 0,
2048, 0, num_blocks - 2048);
seg_desc_len = offset - XCOPY_DESC_OFFSET - tgt_desc_len;
populate_param_header(xcopybuf, 1, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
logging(LOG_VERBOSE,
"Test parameter list length truncating target descriptor");
data.size = XCOPY_DESC_OFFSET +
get_desc_len(IDENT_DESCR_TGT_DESCR) - 1;
ret = extendedcopy(sd, &data, EXPECT_PARAM_LIST_LEN_ERR);
if (ret == -2) {
CU_PASS("[SKIPPED] Target does not support "
"EXTENDED_COPY. Skipping test");
return;
}
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_VERBOSE,
"Test parameter list length truncating segment descriptor");
data.size = XCOPY_DESC_OFFSET +
get_desc_len(IDENT_DESCR_TGT_DESCR) +
get_desc_len(BLK_TO_BLK_SEG_DESCR) - 1;
ret = extendedcopy(sd, &data, EXPECT_PARAM_LIST_LEN_ERR);
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_VERBOSE, "Test parameter list length = 0");
data.size = 0;
ret = extendedcopy(sd, &data, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
}

View File

@@ -0,0 +1,93 @@
/*
Copyright (c) 2015 SanDisk Corp.
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 <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <CUnit/CUnit.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test-cu.h"
void
test_extendedcopy_simple(void)
{
int ret;
int tgt_desc_len = 0, seg_desc_len = 0, offset = XCOPY_DESC_OFFSET;
struct iscsi_data data;
unsigned char *xcopybuf;
unsigned char *buf1 = alloca(2048*block_size);
unsigned char *buf2 = alloca(2048*block_size);
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE,
"Test EXTENDED COPY of 2048 blocks from start of LUN to end of LUN");
CHECK_FOR_DATALOSS;
logging(LOG_VERBOSE, "Write 2048 blocks of 'A' at LBA:0");
memset(buf1, 'A', 2048*block_size);
ret = write16(sd, 0, 2048*block_size, block_size, 0, 0, 0, 0, 0,
buf1, EXPECT_STATUS_GOOD);
if (ret == -2) {
logging(LOG_NORMAL, "[SKIPPED] WRITE16 is not implemented.");
CU_PASS("WRITE16 is not implemented.");
return;
}
CU_ASSERT_EQUAL(ret, 0);
data.size = XCOPY_DESC_OFFSET +
get_desc_len(IDENT_DESCR_TGT_DESCR) +
get_desc_len(BLK_TO_BLK_SEG_DESCR);
data.data = alloca(data.size);
xcopybuf = data.data;
/* Initialize target descriptor list with one target descriptor */
offset += populate_tgt_desc(xcopybuf+offset, IDENT_DESCR_TGT_DESCR,
LU_ID_TYPE_LUN, 0, 0, 0, 0, sd);
tgt_desc_len = offset - XCOPY_DESC_OFFSET;
/* Iniitialize segment descriptor list with one segment descriptor */
offset += populate_seg_desc_b2b(xcopybuf+offset, 0, 0, 0, 0,
2048, 0, num_blocks - 2048);
seg_desc_len = offset - XCOPY_DESC_OFFSET - tgt_desc_len;
/* Initialize the parameter list header */
populate_param_header(xcopybuf, 1, 0, LIST_ID_USAGE_DISCARD, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_STATUS_GOOD);
if (ret == -2) {
CU_PASS("[SKIPPED] Target does not support "
"EXTENDED_COPY. Skipping test");
return;
}
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_VERBOSE, "Read 2048 blocks from end of the LUN");
ret = read16(sd, NULL, num_blocks - 2048, 2048*block_size,
block_size, 0, 0, 0, 0, 0, buf2,
EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
ret = memcmp(buf1, buf2, 2048);
if (ret != 0)
CU_FAIL("Blocks were not copied correctly");
}

View File

@@ -0,0 +1,83 @@
/*
Copyright (c) 2015 SanDisk Corp.
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 <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <CUnit/CUnit.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test-cu.h"
void
test_extendedcopy_validate_seg_descr(void)
{
int ret;
int tgt_desc_len = 0, seg_desc_len = 0, offset = XCOPY_DESC_OFFSET;
struct iscsi_data data;
unsigned char *xcopybuf;
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE, "Test EXTENDED COPY segment descriptor fields");
CHECK_FOR_DATALOSS;
data.size = XCOPY_DESC_OFFSET +
get_desc_len(IDENT_DESCR_TGT_DESCR) +
get_desc_len(BLK_TO_BLK_SEG_DESCR);
data.data = alloca(data.size);
xcopybuf = data.data;
logging(LOG_VERBOSE, "Send invalid target descriptor index");
offset += populate_tgt_desc(xcopybuf+offset, IDENT_DESCR_TGT_DESCR,
LU_ID_TYPE_LUN, 0, 0, 0, 0, sd);
tgt_desc_len = offset - XCOPY_DESC_OFFSET;
/* Inaccessible DESTINATION TARGET DESCRIPTOR INDEX */
offset += populate_seg_desc_b2b(xcopybuf+offset, 0, 0, 0, 1,
2048, 0, num_blocks - 2048);
seg_desc_len = offset - XCOPY_DESC_OFFSET - tgt_desc_len;
populate_param_header(xcopybuf, 1, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_COPY_ABORTED);
if (ret == -2) {
CU_PASS("[SKIPPED] Target does not support "
"EXTENDED_COPY. Skipping test");
return;
}
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_VERBOSE,
"Number of copy blocks beyond destination block device capacity");
memset(xcopybuf, 0, data.size);
offset = XCOPY_DESC_OFFSET;
offset += populate_tgt_desc(xcopybuf+offset, IDENT_DESCR_TGT_DESCR,
LU_ID_TYPE_LUN, 0, 0, 0, 0, sd);
tgt_desc_len = offset - XCOPY_DESC_OFFSET;
/* Beyond EOL */
offset += populate_seg_desc_b2b(xcopybuf+offset, 0, 0, 0, 0,
2048, 0, num_blocks - 1);
seg_desc_len = offset - XCOPY_DESC_OFFSET - tgt_desc_len;
populate_param_header(xcopybuf, 1, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_COPY_ABORTED);
CU_ASSERT_EQUAL(ret, 0);
}

View File

@@ -0,0 +1,82 @@
/*
Copyright (c) 2015 SanDisk Corp.
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 <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <CUnit/CUnit.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test-cu.h"
void
test_extendedcopy_validate_tgt_descr(void)
{
int ret;
int tgt_desc_len = 0, seg_desc_len = 0, offset = XCOPY_DESC_OFFSET;
struct iscsi_data data;
unsigned char *xcopybuf;
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE, "Test EXTENDED COPY target descriptor fields");
CHECK_FOR_DATALOSS;
data.size = XCOPY_DESC_OFFSET +
get_desc_len(IDENT_DESCR_TGT_DESCR) +
get_desc_len(BLK_TO_BLK_SEG_DESCR);
data.data = alloca(data.size);
xcopybuf = data.data;
logging(LOG_VERBOSE, "Unsupported LU_ID TYPE");
/* Unsupported LU ID TYPE */
offset += populate_tgt_desc(xcopybuf+offset, IDENT_DESCR_TGT_DESCR,
LU_ID_TYPE_RSVD, 0, 0, 0, 0, sd);
tgt_desc_len = offset - XCOPY_DESC_OFFSET;
offset += populate_seg_desc_b2b(xcopybuf+offset, 0, 0, 0, 0,
2048, 0, num_blocks - 2048);
seg_desc_len = offset - XCOPY_DESC_OFFSET - tgt_desc_len;
populate_param_header(xcopybuf, 1, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_INVALID_FIELD_IN_CDB);
if (ret == -2) {
CU_PASS("[SKIPPED] Target does not support "
"EXTENDED_COPY. Skipping test");
return;
}
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_VERBOSE, "Test NUL bit in target descriptor");
/* NUL bit */
memset(xcopybuf, 0, data.size);
offset = XCOPY_DESC_OFFSET;
offset += populate_tgt_desc(xcopybuf+offset, IDENT_DESCR_TGT_DESCR,
LU_ID_TYPE_LUN, 1, 0, 0, 0, sd);
tgt_desc_len = offset - XCOPY_DESC_OFFSET;
offset += populate_seg_desc_b2b(xcopybuf+offset, 0, 0, 0, 0,
2048, 0, num_blocks - 2048);
seg_desc_len = offset - XCOPY_DESC_OFFSET - tgt_desc_len;
populate_param_header(xcopybuf, 1, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_COPY_ABORTED);
CU_ASSERT_EQUAL(ret, 0);
}

View File

@@ -0,0 +1,83 @@
/*
Copyright (c) 2015 SanDisk Corp.
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 <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <CUnit/CUnit.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test-cu.h"
void
test_receive_copy_results_copy_status(void)
{
int ret;
struct scsi_copy_results_copy_status *csp;
int tgt_desc_len = 0, seg_desc_len = 0;
int offset = XCOPY_DESC_OFFSET, list_id = 1;
struct iscsi_data data;
unsigned char *xcopybuf;
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE, "Test RECEIVE COPY RESULTS, COPY STATUS");
logging(LOG_VERBOSE, "No copy in progress");
ret = receive_copy_results(sd, SCSI_COPY_RESULTS_COPY_STATUS,
list_id, NULL, EXPECT_INVALID_FIELD_IN_CDB);
CU_ASSERT_EQUAL(ret, 0);
CHECK_FOR_DATALOSS;
logging(LOG_VERBOSE, "Issue Extended Copy");
data.size = XCOPY_DESC_OFFSET +
get_desc_len(IDENT_DESCR_TGT_DESCR) +
get_desc_len(BLK_TO_BLK_SEG_DESCR);
data.data = alloca(data.size);
xcopybuf = data.data;
/* Initialize target descriptor list with one target descriptor */
offset += populate_tgt_desc(xcopybuf+offset, IDENT_DESCR_TGT_DESCR,
LU_ID_TYPE_LUN, 0, 0, 0, 0, sd);
tgt_desc_len = offset - XCOPY_DESC_OFFSET;
/* Iniitialize segment descriptor list with one segment descriptor */
offset += populate_seg_desc_b2b(xcopybuf+offset, 0, 0, 0, 0,
2048, 0, num_blocks - 2048);
seg_desc_len = offset - XCOPY_DESC_OFFSET - tgt_desc_len;
/* Initialize the parameter list header */
populate_param_header(xcopybuf, list_id, 0, 0, 0,
tgt_desc_len, seg_desc_len, 0);
ret = extendedcopy(sd, &data, EXPECT_STATUS_GOOD);
if (ret == -2) {
CU_PASS("[SKIPPED] Target does not support "
"EXTENDED_COPY. Skipping test");
return;
}
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_VERBOSE,
"Copy Status for the above Extended Copy command");
ret = receive_copy_results(sd, SCSI_COPY_RESULTS_COPY_STATUS,
list_id, (void **)&csp, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
}

View File

@@ -0,0 +1,46 @@
/*
Copyright (c) 2015 SanDisk Corp.
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 <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <CUnit/CUnit.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test-cu.h"
void
test_receive_copy_results_op_params(void)
{
int ret;
struct scsi_copy_results_op_params *opp;
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE, "Test RECEIVE COPY RESULTS, OPERATING PARAMS");
ret = receive_copy_results(sd, SCSI_COPY_RESULTS_OP_PARAMS, 0,
(void **)&opp, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
logging(LOG_NORMAL,
"max_target_desc=%d, max_seg_desc=%d",
opp->max_target_desc_count,
opp->max_segment_desc_count);
}