From 2b9abd9ac8f93752d76a55c6ebe3c9d3b0889b2f Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Wed, 4 Jan 2017 18:22:43 +0100 Subject: [PATCH 1/5] examples/dd: validate block count and max in flight params Signed-off-by: David Disseldorp --- examples/iscsi-dd.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/examples/iscsi-dd.c b/examples/iscsi-dd.c index 998477e..de029b5 100644 --- a/examples/iscsi-dd.c +++ b/examples/iscsi-dd.c @@ -23,16 +23,17 @@ #include #include #include +#include #include "iscsi.h" #include "scsi-lowlevel.h" const char *initiator = "iqn.2010-11.ronnie:iscsi-inq"; -int max_in_flight = 50; -int blocks_per_io = 200; +uint32_t max_in_flight = 50; +uint32_t blocks_per_io = 200; struct client { int finished; - int in_flight; + uint32_t in_flight; struct iscsi_context *src_iscsi; int src_lun; @@ -153,7 +154,7 @@ void read_cb(struct iscsi_context *iscsi _U_, int status, void *command_data, vo void fill_read_queue(struct client *client) { - int num_blocks; + uint32_t num_blocks; while(client->in_flight < max_in_flight && client->pos < client->src_num_blocks) { struct scsi_task *task; @@ -214,6 +215,8 @@ int main(int argc, char *argv[]) while ((c = getopt_long(argc, argv, "d:s:i:m:b:p6n", long_options, &option_index)) != -1) { + char *endptr; + switch (c) { case 'd': dst_url = optarg; @@ -231,10 +234,20 @@ int main(int argc, char *argv[]) client.use_16_for_rw = 1; break; case 'm': - max_in_flight = atoi(optarg); + max_in_flight = strtoul(optarg, &endptr, 10); + if (*endptr != '\0' || max_in_flight == UINT_MAX) { + fprintf(stderr, "Invalid max in flight: %s\n", + optarg); + exit(10); + } break; case 'b': - blocks_per_io = atoi(optarg); + blocks_per_io = strtoul(optarg, &endptr, 10); + if (*endptr != '\0' || blocks_per_io == UINT_MAX) { + fprintf(stderr, "Invalid blocks per I/O: %s\n", + optarg); + exit(10); + } break; case 'n': client.ignore_errors = 1; From f475436c5abf4312779f6083e6c76dfe05fb095e Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 3 Jan 2017 19:33:01 +0100 Subject: [PATCH 2/5] Libiscsi: add support for RECEIVE COPY RESULTS Build on existing scsi_cdb_receive_copy_results() functionality. This request is most commonly used to determine target-side EXTENDED COPY operational parameters. Signed-off-by: David Disseldorp --- include/iscsi.h | 9 +++++++++ lib/iscsi-command.c | 23 +++++++++++++++++++++++ lib/libiscsi.def | 2 ++ lib/libiscsi.syms | 2 ++ lib/sync.c | 20 ++++++++++++++++++++ 5 files changed, 56 insertions(+) diff --git a/include/iscsi.h b/include/iscsi.h index 30917a0..58385de 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -1129,6 +1129,11 @@ iscsi_report_supported_opcodes_task(struct iscsi_context *iscsi, int lun, uint32_t alloc_len, iscsi_command_cb cb, void *private_data); +EXTERN struct scsi_task * +iscsi_receive_copy_results_task(struct iscsi_context *iscsi, int lun, + int sa, int list_id, int alloc_len, + iscsi_command_cb cb, void *private_data); + /* * Sync commands for SCSI */ @@ -1454,6 +1459,10 @@ iscsi_report_supported_opcodes_sync(struct iscsi_context *iscsi, int lun, int opcode, int sa, uint32_t alloc_len); +EXTERN struct scsi_task * +iscsi_receive_copy_results_sync(struct iscsi_context *iscsi, int lun, + int sa, int list_id, int alloc_len); + /* * These functions are used when the application wants to specify its own buffers to read the data * from the DATA-IN PDUs into, or write the data to DATA-OUT PDUs from. diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 9f8c0e8..3375974 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -2611,6 +2611,29 @@ iscsi_report_supported_opcodes_task(struct iscsi_context *iscsi, int lun, return task; } +struct scsi_task * +iscsi_receive_copy_results_task(struct iscsi_context *iscsi, int lun, + int sa, int list_id, int alloc_len, + iscsi_command_cb cb, void *private_data) +{ + struct scsi_task *task; + + task = scsi_cdb_receive_copy_results(sa, list_id, alloc_len); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "RECEIVE COPY RESULTS cdb."); + return NULL; + } + + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; + } + + return task; +} + struct scsi_task * iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu) { diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 81ebe60..3bf1fd8 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -83,6 +83,8 @@ iscsi_release6_sync iscsi_release6_task iscsi_report_supported_opcodes_sync iscsi_report_supported_opcodes_task +iscsi_receive_copy_results_sync +iscsi_receive_copy_results_task iscsi_reconnect iscsi_sanitize_sync iscsi_sanitize_task diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index b3f3cac..946dc2c 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -81,6 +81,8 @@ iscsi_release6_sync iscsi_release6_task iscsi_report_supported_opcodes_sync iscsi_report_supported_opcodes_task +iscsi_receive_copy_results_sync +iscsi_receive_copy_results_task iscsi_reconnect iscsi_sanitize_sync iscsi_sanitize_task diff --git a/lib/sync.c b/lib/sync.c index 9fb78e7..c5a82a6 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -1667,6 +1667,26 @@ iscsi_report_supported_opcodes_sync(struct iscsi_context *iscsi, int lun, return state.task; } +struct scsi_task * +iscsi_receive_copy_results_sync(struct iscsi_context *iscsi, int lun, + int sa, int list_id, int alloc_len) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_receive_copy_results_task(iscsi, lun, sa, list_id, alloc_len, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, "Failed to send RECEIVE COPY RESULTS" + " command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_scsi_command_sync(struct iscsi_context *iscsi, int lun, struct scsi_task *task, struct iscsi_data *data) From 4bc5f962e2f0655734d0cc9cfe327d2800b7ac79 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 3 Jan 2017 23:58:20 +0100 Subject: [PATCH 3/5] Libiscsi: add support for EXTENDED COPY Build on existing scsi_cdb_extended_copy() functionality. This operation can be used to offload inter and intra LU copies to the target. The API is rather primitive, in that the caller needs to construct the parameter buffer, including CSCD and segment descriptor lists, etc. Signed-off-by: David Disseldorp --- include/iscsi.h | 9 +++++++++ lib/iscsi-command.c | 23 +++++++++++++++++++++++ lib/libiscsi.def | 2 ++ lib/libiscsi.syms | 2 ++ lib/sync.c | 20 ++++++++++++++++++++ 5 files changed, 56 insertions(+) diff --git a/include/iscsi.h b/include/iscsi.h index 58385de..cb8a557 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -1134,6 +1134,11 @@ iscsi_receive_copy_results_task(struct iscsi_context *iscsi, int lun, int sa, int list_id, int alloc_len, iscsi_command_cb cb, void *private_data); +EXTERN struct scsi_task * +iscsi_extended_copy_task(struct iscsi_context *iscsi, int lun, + struct iscsi_data *param_data, + iscsi_command_cb cb, void *private_data); + /* * Sync commands for SCSI */ @@ -1459,6 +1464,10 @@ iscsi_report_supported_opcodes_sync(struct iscsi_context *iscsi, int lun, int opcode, int sa, uint32_t alloc_len); +EXTERN struct scsi_task * +iscsi_extended_copy_sync(struct iscsi_context *iscsi, int lun, + struct iscsi_data *param_data); + EXTERN struct scsi_task * iscsi_receive_copy_results_sync(struct iscsi_context *iscsi, int lun, int sa, int list_id, int alloc_len); diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 3375974..f9ca8e0 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -2634,6 +2634,29 @@ iscsi_receive_copy_results_task(struct iscsi_context *iscsi, int lun, return task; } +struct scsi_task * +iscsi_extended_copy_task(struct iscsi_context *iscsi, int lun, + struct iscsi_data *param_data, + iscsi_command_cb cb, void *private_data) +{ + struct scsi_task *task; + + task = scsi_cdb_extended_copy(param_data->size); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "EXTENDED COPY cdb."); + return NULL; + } + + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + param_data, private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; + } + + return task; +} + struct scsi_task * iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu) { diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 3bf1fd8..ea5c940 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -83,6 +83,8 @@ iscsi_release6_sync iscsi_release6_task iscsi_report_supported_opcodes_sync iscsi_report_supported_opcodes_task +iscsi_extended_copy_sync +iscsi_extended_copy_task iscsi_receive_copy_results_sync iscsi_receive_copy_results_task iscsi_reconnect diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index 946dc2c..5d81f44 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -81,6 +81,8 @@ iscsi_release6_sync iscsi_release6_task iscsi_report_supported_opcodes_sync iscsi_report_supported_opcodes_task +iscsi_extended_copy_sync +iscsi_extended_copy_task iscsi_receive_copy_results_sync iscsi_receive_copy_results_task iscsi_reconnect diff --git a/lib/sync.c b/lib/sync.c index c5a82a6..3b907c0 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -1687,6 +1687,26 @@ iscsi_receive_copy_results_sync(struct iscsi_context *iscsi, int lun, return state.task; } +struct scsi_task * +iscsi_extended_copy_sync(struct iscsi_context *iscsi, int lun, + struct iscsi_data *param_data) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_extended_copy_task(iscsi, lun, param_data, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, "Failed to send EXTENDED COPY" + " command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_scsi_command_sync(struct iscsi_context *iscsi, int lun, struct scsi_task *task, struct iscsi_data *data) From aaeb2dd5a5c19cadbef3a683d8a1b4e5b847442f Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Mon, 2 Jan 2017 01:15:18 +0100 Subject: [PATCH 4/5] examples/dd: add XCOPY support EXTENDED COPY can be triggered with the new --xcopy/-x parameter. When invoked, (--max) EXTENDED COPY requests are dispatched in parallel, with each request attempting to copy (--blocks) from source to destination. Signed-off-by: David Disseldorp --- examples/iscsi-dd.c | 315 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 314 insertions(+), 1 deletion(-) diff --git a/examples/iscsi-dd.c b/examples/iscsi-dd.c index de029b5..11d6e15 100644 --- a/examples/iscsi-dd.c +++ b/examples/iscsi-dd.c @@ -39,19 +39,23 @@ struct client { int src_lun; int src_blocksize; uint64_t src_num_blocks; + struct scsi_inquiry_device_designator src_tgt_desig; uint64_t pos; struct iscsi_context *dst_iscsi; int dst_lun; int dst_blocksize; uint64_t dst_num_blocks; + struct scsi_inquiry_device_designator dst_tgt_desig; int use_16_for_rw; + int use_xcopy; int progress; int ignore_errors; }; void fill_read_queue(struct client *client); +void fill_xcopy_queue(struct client *client); struct write_task { struct scsi_task *rt; @@ -186,6 +190,293 @@ void fill_read_queue(struct client *client) } } +int populate_tgt_desc(unsigned char *desc, + struct scsi_inquiry_device_designator *tgt_desig, + int rel_init_port_id, uint32_t block_size) +{ + desc[0] = IDENT_DESCR_TGT_DESCR; + desc[1] = 0; /* peripheral type */ + desc[2] = (rel_init_port_id >> 8) & 0xFF; + desc[3] = rel_init_port_id & 0xFF; + desc[4] = tgt_desig->code_set; + desc[5] = (tgt_desig->designator_type & 0xF) + | ((tgt_desig->association & 3) << 4); + desc[7] = tgt_desig->designator_length; + memcpy(desc + 8, tgt_desig->designator, tgt_desig->designator_length); + + desc[28] = 0; + desc[29] = (block_size >> 16) & 0xFF; + desc[30] = (block_size >> 8) & 0xFF; + desc[31] = block_size & 0xFF; + + return 32; +} + +int populate_seg_desc_hdr(unsigned char *hdr, int dc, int cat, int src_index, + int dst_index) +{ + int desc_len = 28; + + hdr[0] = BLK_TO_BLK_SEG_DESCR; + 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, 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; +} + +void xcopy_cb(struct iscsi_context *iscsi _U_, int status, void *command_data, void *private_data) +{ + struct client *client = (struct client *)private_data; + struct scsi_task *task = command_data; + + if (status == SCSI_STATUS_CHECK_CONDITION) { + printf("XCOPY failed with sense key:%d ascq:%04x\n", + task->sense.key, task->sense.ascq); + scsi_free_scsi_task(task); + exit(10); + } + + if (status != SCSI_STATUS_GOOD) { + printf("XCOPY failed with %s\n", iscsi_get_error(iscsi)); + if (!client->ignore_errors) { + scsi_free_scsi_task(task); + exit(10); + } + } + + client->in_flight--; + fill_xcopy_queue(client); + + if (client->progress) { + printf("\r%"PRIu64" of %"PRIu64" blocks transferred.", + client->pos, client->src_num_blocks); + } + + if ((client->in_flight == 0) && (client->pos == client->src_num_blocks)) { + client->finished = 1; + if (client->progress) { + printf("\n"); + } + } + scsi_free_scsi_task(task); +} + +void fill_xcopy_queue(struct client *client) +{ + while (client->in_flight < max_in_flight && client->pos < client->src_num_blocks) { + struct scsi_task *task; + struct iscsi_data data; + unsigned char *xcopybuf; + int offset; + uint32_t num_blocks; + int tgt_desc_len; + int seg_desc_len; + + client->in_flight++; + + num_blocks = client->src_num_blocks - client->pos; + if (num_blocks > blocks_per_io) { + num_blocks = blocks_per_io; + } + + data.size = XCOPY_DESC_OFFSET + + 32 * 2 + /* IDENT_DESCR_TGT_DESCR */ + 28; /* BLK_TO_BLK_SEG_DESCR */ + data.data = malloc(data.size); + if (data.data == NULL) { + printf("failed to alloc XCOPY buffer\n"); + exit(10); + } + + xcopybuf = data.data; + memset(xcopybuf, 0, data.size); + + /* Initialise CSCD list with one src + one dst descriptor */ + offset = XCOPY_DESC_OFFSET; + offset += populate_tgt_desc(xcopybuf + offset, + &client->src_tgt_desig, + 0, client->src_blocksize); + offset += populate_tgt_desc(xcopybuf + offset, + &client->dst_tgt_desig, + 0, client->dst_blocksize); + tgt_desc_len = offset - XCOPY_DESC_OFFSET; + + /* Initialise one segment descriptor */ + seg_desc_len = populate_seg_desc_b2b(xcopybuf + offset, 0, 0, + 0, 1, num_blocks, client->pos, client->pos); + offset += seg_desc_len; + + /* Initialise the parameter list header */ + populate_param_header(xcopybuf, 1, 0, LIST_ID_USAGE_DISCARD, 0, + tgt_desc_len, seg_desc_len, 0); + + task = iscsi_extended_copy_task(client->src_iscsi, + client->src_lun, + &data, xcopy_cb, client); + if (task == NULL) { + printf("failed to send XCOPY command\n"); + exit(10); + } + + client->pos += num_blocks; + } +} + +void cscd_ident_inq(struct iscsi_context *iscsi, + int lun, + struct scsi_inquiry_device_designator *_tgt_desig) +{ + struct scsi_task *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; + + /* check what type of lun we have */ + task = iscsi_inquiry_sync(iscsi, lun, 1, + SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION, 255); + if (task == NULL || task->status != SCSI_STATUS_GOOD) { + fprintf(stderr, "failed to send inquiry command: %s\n", + iscsi_get_error(iscsi)); + exit(10); + } + + inq_di = scsi_datain_unmarshall(task); + if (inq_di == NULL) { + fprintf(stderr, "failed to unmarshall inquiry datain blob\n"); + exit(10); + } + + 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) { + fprintf(stderr, "No suitalble target descriptor format found"); + exit(10); + } + + /* copy what's needed for XCOPY */ + _tgt_desig->code_set = tgt_desig->code_set; + _tgt_desig->association = tgt_desig->association; + _tgt_desig->designator_type = tgt_desig->designator_type; + _tgt_desig->designator_length = tgt_desig->designator_length; + _tgt_desig->designator = malloc(tgt_desig->designator_length); + memcpy(_tgt_desig->designator, tgt_desig->designator, tgt_desig->designator_length); + + scsi_free_scsi_task(task); +} + +void cscd_param_check(struct iscsi_context *iscsi, + int lun, + uint32_t blocksize) +{ + struct scsi_task *task = NULL; + struct scsi_copy_results_op_params *opp; + uint32_t io_segment_bytes; + + task = iscsi_receive_copy_results_sync(iscsi, lun, + SCSI_COPY_RESULTS_OP_PARAMS, 0, 1024); + if (task == NULL || task->status != SCSI_STATUS_GOOD) { + fprintf(stderr, "XCOPY RECEIVE COPY RESULTS failed: %s\n", + iscsi_get_error(iscsi)); + exit(10); + } + + opp = scsi_datain_unmarshall(task); + if (opp == NULL) { + fprintf(stderr, "failed to unmarshall XCOPY RCR datain blob\n"); + exit(10); + } + + if (opp->max_target_desc_count < 2) { + fprintf(stderr, "XCOPY max CSCD desc count %d too small\n", + opp->max_target_desc_count); + exit(10); + } + if (opp->max_segment_desc_count < 1) { + fprintf(stderr, "XCOPY max segment desc count %d too small\n", + opp->max_segment_desc_count); + exit(10); + } + + io_segment_bytes = blocks_per_io * blocksize; + if (io_segment_bytes > opp->max_segment_length) { + fprintf(stderr, + "%u bytes per I/O exceeds XCOPY max segment len %u\n", + io_segment_bytes, opp->max_segment_length); + exit(10); + } + if (blocks_per_io > USHRT_MAX) { + fprintf(stderr, + "%u blocks per I/O exceeds XCOPY field width max %u\n", + blocks_per_io, USHRT_MAX); + exit(10); + } + + scsi_free_scsi_task(task); +} + int main(int argc, char *argv[]) { char *src_url = NULL; @@ -204,6 +495,7 @@ int main(int argc, char *argv[]) {"initiator-name", required_argument, NULL, 'i'}, {"progress", no_argument, NULL, 'p'}, {"16", no_argument, NULL, '6'}, + {"xcopy", no_argument, NULL, 'x'}, {"max", required_argument, NULL, 'm'}, {"blocks", required_argument, NULL, 'b'}, {"ignore-errors", no_argument, NULL, 'n'}, @@ -233,6 +525,9 @@ int main(int argc, char *argv[]) case '6': client.use_16_for_rw = 1; break; + case 'x': + client.use_xcopy = 1; + break; case 'm': max_in_flight = strtoul(optarg, &endptr, 10); if (*endptr != '\0' || max_in_flight == UINT_MAX) { @@ -321,6 +616,13 @@ int main(int argc, char *argv[]) scsi_free_scsi_task(task); } + if (client.use_xcopy) { + cscd_ident_inq(client.src_iscsi, client.src_lun, + &client.src_tgt_desig); + cscd_param_check(client.src_iscsi, client.src_lun, + client.src_blocksize); + } + client.dst_iscsi = iscsi_create_context(initiator); if (client.dst_iscsi == NULL) { fprintf(stderr, "Failed to create context\n"); @@ -373,6 +675,13 @@ int main(int argc, char *argv[]) scsi_free_scsi_task(task); } + if (client.use_xcopy) { + cscd_ident_inq(client.dst_iscsi, client.dst_lun, + &client.dst_tgt_desig); + cscd_param_check(client.dst_iscsi, client.dst_lun, + client.dst_blocksize); + } + if (client.src_blocksize != client.dst_blocksize) { fprintf(stderr, "source LUN has different blocksize than destination than destination (%d != %d sectors)\n", client.src_blocksize, client.dst_blocksize); exit(10); @@ -383,7 +692,11 @@ int main(int argc, char *argv[]) exit(10); } - fill_read_queue(&client); + if (client.use_xcopy) { + fill_xcopy_queue(&client); + } else { + fill_read_queue(&client); + } while (client.finished == 0) { pfd[0].fd = iscsi_get_fd(client.src_iscsi); From 30a49f97cba7d0cbdf18ca5a10d6650341dc1bfc Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Mon, 2 Jan 2017 18:41:15 +0100 Subject: [PATCH 5/5] examples/dd: split out duplicate read capacity code Use a helper function, rather than having duplicate source and destination READ CAPACITY logic. Signed-off-by: David Disseldorp --- examples/iscsi-dd.c | 110 ++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 61 deletions(-) diff --git a/examples/iscsi-dd.c b/examples/iscsi-dd.c index 11d6e15..cd09650 100644 --- a/examples/iscsi-dd.c +++ b/examples/iscsi-dd.c @@ -477,14 +477,56 @@ void cscd_param_check(struct iscsi_context *iscsi, scsi_free_scsi_task(task); } +void readcap(struct iscsi_context *iscsi, int lun, int use_16, + int *_blocksize, uint64_t *_num_blocks) +{ + struct scsi_task *task; + + if (use_16) { + struct scsi_readcapacity16 *rc16; + + task = iscsi_readcapacity16_sync(iscsi, lun); + if (task == NULL || task->status != SCSI_STATUS_GOOD) { + fprintf(stderr, + "failed to send readcapacity command\n"); + exit(10); + } + rc16 = scsi_datain_unmarshall(task); + if (rc16 == NULL) { + fprintf(stderr, + "failed to unmarshall readcapacity16 data\n"); + exit(10); + } + *_blocksize = rc16->block_length; + *_num_blocks = rc16->returned_lba + 1; + } else { + struct scsi_readcapacity10 *rc10; + + task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); + if (task == NULL || task->status != SCSI_STATUS_GOOD) { + fprintf(stderr, + "failed to send readcapacity command\n"); + exit(10); + } + rc10 = scsi_datain_unmarshall(task); + if (rc10 == NULL) { + fprintf(stderr, + "failed to unmarshall readcapacity10 data\n"); + exit(10); + } + *_blocksize = rc10->block_size; + *_num_blocks = rc10->lba; + } + + scsi_free_scsi_task(task); + return; +} + int main(int argc, char *argv[]) { char *src_url = NULL; char *dst_url = NULL; struct iscsi_url *iscsi_url; - struct scsi_task *task; - struct scsi_readcapacity10 *rc10; - struct scsi_readcapacity16 *rc16; int c; struct pollfd pfd[2]; struct client client; @@ -586,35 +628,8 @@ int main(int argc, char *argv[]) client.src_lun = iscsi_url->lun; iscsi_destroy_url(iscsi_url); - if (client.use_16_for_rw) { - task = iscsi_readcapacity16_sync(client.src_iscsi, client.src_lun); - if (task == NULL || task->status != SCSI_STATUS_GOOD) { - fprintf(stderr, "failed to send readcapacity command\n"); - exit(10); - } - rc16 = scsi_datain_unmarshall(task); - if (rc16 == NULL) { - fprintf(stderr, "failed to unmarshall readcapacity16 data\n"); - exit(10); - } - client.src_blocksize = rc16->block_length; - client.src_num_blocks = rc16->returned_lba + 1; - scsi_free_scsi_task(task); - } else { - task = iscsi_readcapacity10_sync(client.src_iscsi, client.src_lun, 0, 0); - if (task == NULL || task->status != SCSI_STATUS_GOOD) { - fprintf(stderr, "failed to send readcapacity command\n"); - exit(10); - } - rc10 = scsi_datain_unmarshall(task); - if (rc10 == NULL) { - fprintf(stderr, "failed to unmarshall readcapacity10 data\n"); - exit(10); - } - client.src_blocksize = rc10->block_size; - client.src_num_blocks = rc10->lba; - scsi_free_scsi_task(task); - } + readcap(client.src_iscsi, client.src_lun, client.use_16_for_rw, + &client.src_blocksize, &client.src_num_blocks); if (client.use_xcopy) { cscd_ident_inq(client.src_iscsi, client.src_lun, @@ -645,35 +660,8 @@ int main(int argc, char *argv[]) client.dst_lun = iscsi_url->lun; iscsi_destroy_url(iscsi_url); - if (client.use_16_for_rw) { - task = iscsi_readcapacity16_sync(client.dst_iscsi, client.dst_lun); - if (task == NULL || task->status != SCSI_STATUS_GOOD) { - fprintf(stderr, "failed to send readcapacity command\n"); - exit(10); - } - rc16 = scsi_datain_unmarshall(task); - if (rc16 == NULL) { - fprintf(stderr, "failed to unmarshall readcapacity16 data\n"); - exit(10); - } - client.dst_blocksize = rc16->block_length; - client.dst_num_blocks = rc16->returned_lba + 1; - scsi_free_scsi_task(task); - } else { - task = iscsi_readcapacity10_sync(client.dst_iscsi, client.dst_lun, 0, 0); - if (task == NULL || task->status != SCSI_STATUS_GOOD) { - fprintf(stderr, "failed to send readcapacity command\n"); - exit(10); - } - rc10 = scsi_datain_unmarshall(task); - if (rc10 == NULL) { - fprintf(stderr, "failed to unmarshall readcapacity10 data\n"); - exit(10); - } - client.dst_blocksize = rc10->block_size; - client.dst_num_blocks = rc10->lba; - scsi_free_scsi_task(task); - } + readcap(client.dst_iscsi, client.dst_lun, client.use_16_for_rw, + &client.dst_blocksize, &client.dst_num_blocks); if (client.use_xcopy) { cscd_ident_inq(client.dst_iscsi, client.dst_lun,