diff --git a/examples/iscsiclient.c b/examples/iscsiclient.c index ef326f3..d8f95e9 100644 --- a/examples/iscsiclient.c +++ b/examples/iscsiclient.c @@ -130,6 +130,36 @@ void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void scsi_free_scsi_task(task); } +void read6_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) +{ + struct client_state *clnt = (struct client_state *)private_data; + struct scsi_task *task = command_data; + int i; + + if (status == SCSI_STATUS_CHECK_CONDITION) { + printf("Read6 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); + scsi_free_scsi_task(task); + exit(10); + } + + printf("READ6 successful. Block content:\n"); + for (i=0;idatain.size;i++) { + printf("%02x ", task->datain.data[i]); + if (i%16==15) + printf("\n"); + if (i==69) + break; + } + printf("...\n"); + + if (iscsi_read10_task(iscsi, clnt->lun, 0, clnt->block_size, clnt->block_size, read10_cb, private_data) == NULL) { + printf("failed to send read10 command\n"); + scsi_free_scsi_task(task); + exit(10); + } + scsi_free_scsi_task(task); +} + void readcapacity10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; @@ -159,8 +189,8 @@ void readcapacity10_cb(struct iscsi_context *iscsi, int status, void *command_da clnt->block_size = rc10->block_size; printf("READCAPACITY10 successful. Size:%d blocks blocksize:%d. Read first block\n", rc10->lba, rc10->block_size); - if (iscsi_read10_task(iscsi, clnt->lun, 0, clnt->block_size, clnt->block_size, read10_cb, private_data) == NULL) { - printf("failed to send read10 command\n"); + if (iscsi_read6_task(iscsi, clnt->lun, 0, clnt->block_size, clnt->block_size, read6_cb, private_data) == NULL) { + printf("failed to send read6 command\n"); scsi_free_scsi_task(task); exit(10); } diff --git a/include/iscsi.h b/include/iscsi.h index c86dbe3..15021e6 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -572,6 +572,11 @@ iscsi_synchronizecache10_task(struct iscsi_context *iscsi, int lun, int immed, iscsi_command_cb cb, void *private_data); struct scsi_task * +iscsi_read6_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, iscsi_command_cb cb, + void *private_data); + +struct scsi_task * iscsi_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, iscsi_command_cb cb, void *private_data); @@ -605,6 +610,10 @@ struct scsi_task * iscsi_inquiry_sync(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize); +struct scsi_task * +iscsi_read6_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize); + struct scsi_task * iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize); diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index a41b66a..81928c3 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -21,6 +21,7 @@ enum scsi_opcode { SCSI_OPCODE_TESTUNITREADY = 0x00, + SCSI_OPCODE_READ6 = 0x08, SCSI_OPCODE_INQUIRY = 0x12, SCSI_OPCODE_MODESENSE6 = 0x1a, SCSI_OPCODE_READCAPACITY10 = 0x25, @@ -69,6 +70,10 @@ enum scsi_xfer_dir { struct scsi_reportluns_params { int report_type; }; +struct scsi_read6_params { + uint32_t lba; + uint32_t num_blocks; +}; struct scsi_read10_params { uint32_t lba; uint32_t num_blocks; @@ -122,6 +127,7 @@ struct scsi_task { int expxferlen; unsigned char cdb[SCSI_CDB_MAX_SIZE]; union { + struct scsi_read6_params read6; struct scsi_read10_params read10; struct scsi_write10_params write10; struct scsi_readcapacity10_params readcapacity10; diff --git a/lib/scsi-command.c b/lib/scsi-command.c index bad369e..5eaebc7 100644 --- a/lib/scsi-command.c +++ b/lib/scsi-command.c @@ -582,6 +582,34 @@ iscsi_readcapacity10_task(struct iscsi_context *iscsi, int lun, int lba, return task; } +struct scsi_task * +iscsi_read6_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + 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_read6(lba, datalen, blocksize); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "read6 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_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 3cdc855..087bbdc 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -505,6 +505,50 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task) return NULL; } +/* + * READ6 + */ +struct scsi_task * +scsi_cdb_read6(uint32_t lba, uint32_t xferlen, int blocksize) +{ + struct scsi_task *task; + int num_blocks; + + num_blocks = xferlen/blocksize; + if (num_blocks > 265) { + return NULL; + } + + if (lba > 0x1fffff) { + return NULL; + } + + task = malloc(sizeof(struct scsi_task)); + if (task == NULL) { + return NULL; + } + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ6; + task->cdb_size = 6; + + task->cdb[1] = (lba>>16)&0x1f; + task->cdb[2] = (lba>> 8)&0xff; + task->cdb[3] = (lba )&0xff; + + if (num_blocks < 256) { + task->cdb[4] = num_blocks; + } + + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = xferlen; + + task->params.read6.lba = lba; + task->params.read6.num_blocks = num_blocks; + + return task; +} + /* * READ10 */ diff --git a/lib/sync.c b/lib/sync.c index 50289dd..b3fabbe 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -216,6 +216,26 @@ iscsi_inquiry_sync(struct iscsi_context *iscsi, int lun, int evpd, return state.task; } +struct scsi_task * +iscsi_read6_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_read6_task(iscsi, lun, lba, datalen, blocksize, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Read6 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize)