diff --git a/Makefile.am b/Makefile.am index 3eddff0..296e48a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,7 +66,8 @@ bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \ test-tool/0160_readcapacity16_simple.c \ test-tool/0170_unmap_simple.c test-tool/0171_unmap_zero.c \ test-tool/0180_writesame10_unmap.c test-tool/0181_writesame10_unmap_unaligned.c \ - test-tool/0190_writesame16_unmap.c test-tool/0191_writesame16_unmap_unaligned.c + test-tool/0190_writesame16_unmap.c test-tool/0191_writesame16_unmap_unaligned.c \ + test-tool/0200_read16_simple.c endif # LD_PRELOAD library. diff --git a/include/iscsi.h b/include/iscsi.h index eef6c02..13c7ee4 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -599,9 +599,29 @@ iscsi_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, EXTERN struct scsi_task * iscsi_write10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int fua, - int fuanv, int blocksize, iscsi_command_cb cb, + int fua_nv, int blocksize, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * +iscsi_read12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data); +EXTERN struct scsi_task * +iscsi_write12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data); +EXTERN struct scsi_task * +iscsi_read16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data); +EXTERN struct scsi_task * +iscsi_write16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data); +EXTERN struct scsi_task * iscsi_verify10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, @@ -664,6 +684,31 @@ EXTERN struct scsi_task * iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize); +EXTERN struct scsi_task * +iscsi_write10_sync(struct iscsi_context *iscsi, int lun, + unsigned char *data, uint32_t datalen, uint32_t lba, int fua, + int fua_nv, int blocksize); + +EXTERN struct scsi_task * +iscsi_read12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number); + +EXTERN struct scsi_task * +iscsi_write12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int fua, int fua_nv, int group_number); + +EXTERN struct scsi_task * +iscsi_read16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, + uint32_t datalen, int blocksize, +int rdprotect, int dpo, int fua, int fua_nv, int group_number); + +EXTERN struct scsi_task * +iscsi_write16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int fua, int fua_nv, int group_number); + EXTERN struct scsi_task * iscsi_readcapacity10_sync(struct iscsi_context *iscsi, int lun, int lba, int pmi); @@ -675,11 +720,6 @@ EXTERN struct scsi_task * iscsi_synchronizecache10_sync(struct iscsi_context *iscsi, int lun, int lba, int num_blocks, int syncnv, int immed); -EXTERN struct scsi_task * -iscsi_write10_sync(struct iscsi_context *iscsi, int lun, - unsigned char *data, uint32_t datalen, uint32_t lba, int fua, - int fuanv, int blocksize); - EXTERN struct scsi_task * iscsi_verify10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index 15f4d59..7125f4b 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -32,10 +32,12 @@ enum scsi_opcode { SCSI_OPCODE_WRITE_SAME10 = 0x41, SCSI_OPCODE_UNMAP = 0x42, SCSI_OPCODE_READ16 = 0x88, + SCSI_OPCODE_WRITE16 = 0x8A, SCSI_OPCODE_WRITE_SAME16 = 0x93, SCSI_OPCODE_SERVICE_ACTION_IN = 0x9E, SCSI_OPCODE_REPORTLUNS = 0xA0, - SCSI_OPCODE_READ12 = 0xA8 + SCSI_OPCODE_READ12 = 0xA8, + SCSI_OPCODE_WRITE12 = 0xAA }; enum scsi_service_action_in { @@ -91,10 +93,26 @@ struct scsi_read10_params { uint32_t lba; uint32_t num_blocks; }; +struct scsi_read12_params { + uint32_t lba; + uint32_t num_blocks; +}; +struct scsi_read16_params { + uint64_t lba; + uint32_t num_blocks; +}; struct scsi_write10_params { uint32_t lba; uint32_t num_blocks; }; +struct scsi_write12_params { + uint32_t lba; + uint32_t num_blocks; +}; +struct scsi_write16_params { + uint64_t lba; + uint32_t num_blocks; +}; struct scsi_verify10_params { uint32_t lba; uint32_t num_blocks; @@ -152,7 +170,11 @@ struct scsi_task { union { struct scsi_read6_params read6; struct scsi_read10_params read10; + struct scsi_read12_params read12; + struct scsi_read16_params read16; struct scsi_write10_params write10; + struct scsi_write12_params write12; + struct scsi_write16_params write16; struct scsi_verify10_params verify10; struct scsi_readcapacity10_params readcapacity10; struct scsi_reportluns_params reportluns; @@ -557,8 +579,11 @@ EXTERN void *scsi_datain_unmarshall(struct scsi_task *task); 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); -EXTERN struct scsi_task *scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int fua, int fuanv, - int blocksize); +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 fua, int fuanv, int blocksize); +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_verify10(uint32_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, diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 02784ba..c691a86 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -47,8 +47,10 @@ iscsi_readcapacity16_task iscsi_synchronizecache10_task iscsi_read6_task iscsi_read10_task +iscsi_read12_task iscsi_verify10_task iscsi_write10_task +iscsi_write12_task iscsi_writesame10_task iscsi_writesame16_task iscsi_modesense6_task @@ -61,8 +63,10 @@ iscsi_readcapacity16_sync iscsi_synchronizecache10_sync iscsi_read6_sync iscsi_read10_sync +iscsi_read12_sync iscsi_verify10_sync iscsi_write10_sync +iscsi_write12_sync iscsi_writesame10_sync iscsi_writesame16_sync iscsi_scsi_task_cancel diff --git a/lib/scsi-command.c b/lib/scsi-command.c index 89ed1bc..08f9781 100644 --- a/lib/scsi-command.c +++ b/lib/scsi-command.c @@ -681,6 +681,66 @@ iscsi_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, return task; } +struct scsi_task * +iscsi_read12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data) +{ + struct scsi_task *task; + + if (datalen % blocksize != 0) { + iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " + "the blocksize:%d.", datalen, blocksize); + return NULL; + } + + task = scsi_cdb_read12(lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "read12 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_read16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data) +{ + struct scsi_task *task; + + if (datalen % blocksize != 0) { + iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " + "the blocksize:%d.", datalen, blocksize); + return NULL; + } + + task = scsi_cdb_read16(lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "read16 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_write10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int fua, int fuanv, int blocksize, @@ -714,6 +774,76 @@ iscsi_write10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, return task; } +struct scsi_task * +iscsi_write12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data) +{ + struct scsi_task *task; + struct iscsi_data outdata; + + if (datalen % blocksize != 0) { + iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " + "blocksize:%d.", datalen, blocksize); + return NULL; + } + + task = scsi_cdb_write12(lba, datalen, blocksize, wrprotect, + dpo, fua, fua_nv, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "write12 cdb."); + return NULL; + } + + outdata.data = data; + outdata.size = datalen; + + if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, + private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; + } + + return task; +} + +struct scsi_task * +iscsi_write16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data) +{ + struct scsi_task *task; + struct iscsi_data outdata; + + if (datalen % blocksize != 0) { + iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " + "blocksize:%d.", datalen, blocksize); + return NULL; + } + + task = scsi_cdb_write16(lba, datalen, blocksize, wrprotect, + dpo, fua, fua_nv, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "write16 cdb."); + return NULL; + } + + outdata.data = data; + outdata.size = datalen; + + if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, + private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; + } + + return task; +} + struct scsi_task * iscsi_verify10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize, diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 1f5b85a..f6aa123 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -675,11 +675,104 @@ scsi_cdb_read10(uint32_t lba, uint32_t xferlen, int blocksize) return task; } +/* + * READ12 + */ +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) +{ + 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_READ12; + + task->cdb[1] |= ((rdprotect & 0x07) << 5); + if (dpo) { + task->cdb[1] |= 0x10; + } + if (fua) { + task->cdb[1] |= 0x08; + } + if (fua_nv) { + task->cdb[1] |= 0x02; + } + + *(uint32_t *)&task->cdb[2] = htonl(lba); + *(uint32_t *)&task->cdb[6] = htonl(xferlen/blocksize); + + task->cdb[10] |= (group_number & 0x1f); + + task->cdb_size = 12; + if (xferlen != 0) { + task->xfer_dir = SCSI_XFER_READ; + } else { + task->xfer_dir = SCSI_XFER_NONE; + } + task->expxferlen = xferlen; + + task->params.read12.lba = lba; + task->params.read12.num_blocks = xferlen/blocksize; + + return task; +} + +/* + * READ16 + */ +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) +{ + 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_READ16; + + task->cdb[1] |= ((rdprotect & 0x07) << 5); + if (dpo) { + task->cdb[1] |= 0x10; + } + if (fua) { + task->cdb[1] |= 0x08; + } + if (fua_nv) { + task->cdb[1] |= 0x02; + } + + *(uint32_t *)&task->cdb[2] = htonl(lba >> 32); + *(uint32_t *)&task->cdb[6] = htonl(lba & 0xffffffff); + *(uint32_t *)&task->cdb[10] = htonl(xferlen/blocksize); + + task->cdb[14] |= (group_number & 0x1f); + + task->cdb_size = 16; + if (xferlen != 0) { + task->xfer_dir = SCSI_XFER_READ; + } else { + task->xfer_dir = SCSI_XFER_NONE; + } + task->expxferlen = xferlen; + + task->params.read16.lba = lba; + task->params.read16.num_blocks = xferlen/blocksize; + + return task; +} + /* * WRITE10 */ struct scsi_task * -scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int fua, int fuanv, int blocksize) +scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int fua, int fua_nv, int blocksize) { struct scsi_task *task; @@ -694,7 +787,7 @@ scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int fua, int fuanv, int blocksi if (fua) { task->cdb[1] |= 0x08; } - if (fuanv) { + if (fua_nv) { task->cdb[1] |= 0x02; } @@ -715,6 +808,98 @@ scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int fua, int fuanv, int blocksi return task; } +/* + * WRITE12 + */ +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) +{ + 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_WRITE12; + + task->cdb[1] |= ((wrprotect & 0x07) << 5); + if (dpo) { + task->cdb[1] |= 0x10; + } + if (fua) { + task->cdb[1] |= 0x08; + } + if (fua_nv) { + task->cdb[1] |= 0x02; + } + + *(uint32_t *)&task->cdb[2] = htonl(lba); + *(uint32_t *)&task->cdb[6] = htonl(xferlen/blocksize); + + task->cdb[10] |= (group_number & 0x1f); + + task->cdb_size = 12; + if (xferlen != 0) { + task->xfer_dir = SCSI_XFER_WRITE; + } else { + task->xfer_dir = SCSI_XFER_NONE; + } + task->expxferlen = xferlen; + + task->params.write12.lba = lba; + task->params.write12.num_blocks = xferlen/blocksize; + + return task; +} + +/* + * WRITE16 + */ +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) +{ + 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_WRITE16; + + task->cdb[1] |= ((wrprotect & 0x07) << 5); + if (dpo) { + task->cdb[1] |= 0x10; + } + if (fua) { + task->cdb[1] |= 0x08; + } + if (fua_nv) { + task->cdb[1] |= 0x02; + } + + *(uint32_t *)&task->cdb[2] = htonl(lba >> 32); + *(uint32_t *)&task->cdb[6] = htonl(lba & 0xffffffff); + *(uint32_t *)&task->cdb[10] = htonl(xferlen/blocksize); + + task->cdb[14] |= (group_number & 0x1f); + + task->cdb_size = 16; + if (xferlen != 0) { + task->xfer_dir = SCSI_XFER_WRITE; + } else { + task->xfer_dir = SCSI_XFER_NONE; + } + task->expxferlen = xferlen; + + task->params.write16.lba = lba; + task->params.write16.num_blocks = xferlen/blocksize; + + return task; +} /* * VERIFY10 diff --git a/lib/sync.c b/lib/sync.c index 027682c..1e6648c 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -271,6 +271,50 @@ iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, return state.task; } +struct scsi_task * +iscsi_read12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_read12_task(iscsi, lun, lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Read12 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + +struct scsi_task * +iscsi_read16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_read16_task(iscsi, lun, lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Read16 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_readcapacity10_sync(struct iscsi_context *iscsi, int lun, int lba, int pmi) @@ -351,6 +395,52 @@ iscsi_write10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, ui return state.task; } +struct scsi_task * +iscsi_write12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int fua, int fua_nv, int group_number) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_write12_task(iscsi, lun, lba, + data, datalen, blocksize, wrprotect, + dpo, fua, fua_nv, group_number, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Write12 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + +struct scsi_task * +iscsi_write16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int fua, int fua_nv, int group_number) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_write16_task(iscsi, lun, lba, + data, datalen, blocksize, wrprotect, + dpo, fua, fua_nv, group_number, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Write16 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_verify10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) diff --git a/test-tool/0200_read16_simple.c b/test-tool/0200_read16_simple.c new file mode 100644 index 0000000..3d5c1c4 --- /dev/null +++ b/test-tool/0200_read16_simple.c @@ -0,0 +1,113 @@ +/* + Copyright (C) 2012 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 "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-test.h" + +int T0200_read16_simple(const char *initiator, const char *url) +{ + struct iscsi_context *iscsi; + struct scsi_task *task; + struct scsi_readcapacity10 *rc10; + int ret, i, lun; + uint32_t block_size, num_blocks; + + iscsi = iscsi_context_login(initiator, url, &lun); + if (iscsi == NULL) { + printf("Failed to login to target\n"); + return -1; + } + + /* find the size of the LUN */ + task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); + if (task == NULL) { + printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); + ret = -1; + goto finished; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); + ret = -1; + scsi_free_scsi_task(task); + goto finished; + } + rc10 = scsi_datain_unmarshall(task); + if (rc10 == NULL) { + printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); + ret = -1; + scsi_free_scsi_task(task); + goto finished; + } + block_size = rc10->block_size; + num_blocks = rc10->lba; + scsi_free_scsi_task(task); + + + + ret = 0; + + /* read the first 1 - 256 blocks at the start of the LUN */ + printf("Reading first 1-256 blocks ... "); + for (i=1; i<=256; i++) { + task = iscsi_read16_sync(iscsi, lun, 0, i * block_size, block_size, 0, 0, 0, 0, 0); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); + ret = -1; + goto finished; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + ret = -1; + scsi_free_scsi_task(task); + goto finished; + } + scsi_free_scsi_task(task); + } + printf("[OK]\n"); + + + /* read the last 1 - 256 blocks at the end of the LUN */ + printf("Reading last 1-256 blocks ... "); + for (i=1; i<=256; i++) { + task = iscsi_read16_sync(iscsi, lun, num_blocks +1 - i, i * block_size, block_size, 0, 0, 0, 0, 0); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); + ret = -1; + goto finished; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + ret = -1; + scsi_free_scsi_task(task); + goto finished; + } + scsi_free_scsi_task(task); + } + printf("[OK]\n"); + + +finished: + iscsi_logout_sync(iscsi); + iscsi_destroy_context(iscsi); + return ret; +} diff --git a/test-tool/iscsi-test.c b/test-tool/iscsi-test.c index 9aad4b0..ef9f098 100644 --- a/test-tool/iscsi-test.c +++ b/test-tool/iscsi-test.c @@ -80,6 +80,9 @@ struct scsi_test tests[] = { { "T0190_writesame16_unmap", T0190_writesame16_unmap }, { "T0191_writesame16_unmap_unaligned", T0191_writesame16_unmap_unaligned }, +/* read16*/ +{ "T0200_read16_simple", T0200_read16_simple }, + { NULL, NULL } }; diff --git a/test-tool/iscsi-test.h b/test-tool/iscsi-test.h index eb97bf7..55923ca 100644 --- a/test-tool/iscsi-test.h +++ b/test-tool/iscsi-test.h @@ -53,3 +53,5 @@ int T0181_writesame10_unmap_unaligned(const char *initiator, const char *url); int T0190_writesame16_unmap(const char *initiator, const char *url); int T0191_writesame16_unmap_unaligned(const char *initiator, const char *url); + +int T0200_read16_simple(const char *initiator, const char *url);