diff --git a/include/iscsi.h b/include/iscsi.h index 815664c..8823bfb 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -626,6 +626,11 @@ iscsi_write10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, int wrprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * +iscsi_writeverify10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, int group_number, + 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, @@ -636,6 +641,11 @@ iscsi_write12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, int wrprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * +iscsi_writeverify12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, 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, @@ -646,6 +656,11 @@ iscsi_write16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, int wrprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * +iscsi_writeverify16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, 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, @@ -731,6 +746,11 @@ iscsi_write10_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_writeverify10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, int group_number); + EXTERN struct scsi_task * iscsi_read12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, @@ -741,6 +761,11 @@ 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_writeverify12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, int group_number); + EXTERN struct scsi_task * iscsi_read16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, @@ -751,6 +776,11 @@ 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_writeverify16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, int group_number); + EXTERN struct scsi_task * iscsi_readcapacity10_sync(struct iscsi_context *iscsi, int lun, int lba, int pmi); diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index d9129f1..7cac330 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -31,6 +31,7 @@ enum scsi_opcode { SCSI_OPCODE_READCAPACITY10 = 0x25, SCSI_OPCODE_READ10 = 0x28, SCSI_OPCODE_WRITE10 = 0x2A, + SCSI_OPCODE_WRITE_VERIFY10 = 0x2E, SCSI_OPCODE_VERIFY10 = 0x2F, SCSI_OPCODE_PREFETCH10 = 0x34, SCSI_OPCODE_SYNCHRONIZECACHE10 = 0x35, @@ -38,6 +39,7 @@ enum scsi_opcode { SCSI_OPCODE_UNMAP = 0x42, SCSI_OPCODE_READ16 = 0x88, SCSI_OPCODE_WRITE16 = 0x8A, + SCSI_OPCODE_WRITE_VERIFY16 = 0x8E, SCSI_OPCODE_VERIFY16 = 0x8F, SCSI_OPCODE_PREFETCH16 = 0x90, SCSI_OPCODE_SYNCHRONIZECACHE16 = 0x91, @@ -46,6 +48,7 @@ enum scsi_opcode { SCSI_OPCODE_REPORTLUNS = 0xA0, SCSI_OPCODE_READ12 = 0xA8, SCSI_OPCODE_WRITE12 = 0xAA, + SCSI_OPCODE_WRITE_VERIFY12 = 0xAE, SCSI_OPCODE_VERIFY12 = 0xAF }; @@ -127,6 +130,18 @@ struct scsi_write16_params { uint64_t lba; uint32_t num_blocks; }; +struct scsi_writeverify10_params { + uint32_t lba; + uint32_t num_blocks; +}; +struct scsi_writeverify12_params { + uint32_t lba; + uint32_t num_blocks; +}; +struct scsi_writeverify16_params { + uint64_t lba; + uint32_t num_blocks; +}; struct scsi_verify10_params { uint32_t lba; uint32_t num_blocks; @@ -203,6 +218,9 @@ struct scsi_task { struct scsi_write10_params write10; struct scsi_write12_params write12; struct scsi_write16_params write16; + struct scsi_writeverify10_params writeverify10; + struct scsi_writeverify12_params writeverify12; + struct scsi_writeverify16_params writeverify16; struct scsi_verify10_params verify10; struct scsi_verify12_params verify12; struct scsi_verify16_params verify16; @@ -631,6 +649,9 @@ EXTERN struct scsi_task *scsi_cdb_read16(uint64_t lba, uint32_t xferlen, int blo EXTERN struct scsi_task *scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_write12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_write16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); +EXTERN struct scsi_task *scsi_cdb_writeverify10(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number); +EXTERN struct scsi_task *scsi_cdb_writeverify12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number); +EXTERN struct scsi_task *scsi_cdb_writeverify16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number); EXTERN struct scsi_task *scsi_cdb_verify10(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize); EXTERN struct scsi_task *scsi_cdb_verify12(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize); EXTERN struct scsi_task *scsi_cdb_verify16(uint64_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize); diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 0663da9..34c45ef 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -88,6 +88,12 @@ iscsi_write12_sync iscsi_write12_task iscsi_write16_sync iscsi_write16_task +iscsi_writeverify10_sync +iscsi_writeverify10_task +iscsi_writeverify12_sync +iscsi_writeverify12_task +iscsi_writeverify16_sync +iscsi_writeverify16_task iscsi_writesame10_sync iscsi_writesame10_task iscsi_writesame16_sync @@ -114,6 +120,9 @@ scsi_cdb_verify16 scsi_cdb_write10 scsi_cdb_write12 scsi_cdb_write16 +scsi_cdb_writeverify10 +scsi_cdb_writeverify12 +scsi_cdb_writeverify16 scsi_cdb_writesame10 scsi_cdb_writesame16 scsi_codeset_to_str diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index f798c00..afb70ab 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -86,6 +86,12 @@ iscsi_write12_sync iscsi_write12_task iscsi_write16_sync iscsi_write16_task +iscsi_writeverify10_sync +iscsi_writeverify10_task +iscsi_writeverify12_sync +iscsi_writeverify12_task +iscsi_writeverify16_sync +iscsi_writeverify16_task iscsi_writesame10_sync iscsi_writesame10_task iscsi_writesame16_sync @@ -112,6 +118,9 @@ scsi_cdb_verify16 scsi_cdb_write10 scsi_cdb_write12 scsi_cdb_write16 +scsi_cdb_writeverify10 +scsi_cdb_writeverify12 +scsi_cdb_writeverify16 scsi_cdb_writesame10 scsi_cdb_writesame16 scsi_codeset_to_str diff --git a/lib/scsi-command.c b/lib/scsi-command.c index 6b39ec7..4a07212 100644 --- a/lib/scsi-command.c +++ b/lib/scsi-command.c @@ -870,6 +870,111 @@ iscsi_write16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, return task; } +struct scsi_task * +iscsi_writeverify10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, 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_writeverify10(lba, datalen, blocksize, wrprotect, + dpo, bytchk, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "writeverify10 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_writeverify12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, 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_writeverify12(lba, datalen, blocksize, wrprotect, + dpo, bytchk, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "writeverify12 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_writeverify16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, 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_writeverify16(lba, datalen, blocksize, wrprotect, + dpo, bytchk, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "writeverify16 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 3f07634..eee5aaa 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -1623,6 +1623,136 @@ scsi_cdb_get_lba_status(uint64_t starting_lba, uint32_t alloc_len) return task; } +/* + * WRITEVERIFY10 + */ +struct scsi_task * +scsi_cdb_writeverify10(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, 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_WRITE_VERIFY10; + + task->cdb[1] |= ((wrprotect & 0x07) << 5); + if (dpo) { + task->cdb[1] |= 0x10; + } + if (bytchk) { + task->cdb[1] |= 0x02; + } + + *(uint32_t *)&task->cdb[2] = htonl(lba); + *(uint16_t *)&task->cdb[7] = htons(xferlen/blocksize); + + task->cdb[6] |= (group_number & 0x1f); + + task->cdb_size = 10; + if (xferlen != 0) { + task->xfer_dir = SCSI_XFER_WRITE; + } else { + task->xfer_dir = SCSI_XFER_NONE; + } + task->expxferlen = xferlen; + + task->params.writeverify10.lba = lba; + task->params.writeverify10.num_blocks = xferlen/blocksize; + + return task; +} + +/* + * WRITEVERIFY12 + */ +struct scsi_task * +scsi_cdb_writeverify12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, 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_WRITE_VERIFY12; + + task->cdb[1] |= ((wrprotect & 0x07) << 5); + if (dpo) { + task->cdb[1] |= 0x10; + } + if (bytchk) { + 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.writeverify12.lba = lba; + task->params.writeverify12.num_blocks = xferlen/blocksize; + + return task; +} + +/* + * WRITEVERIFY16 + */ +struct scsi_task * +scsi_cdb_writeverify16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, 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_WRITE_VERIFY16; + + task->cdb[1] |= ((wrprotect & 0x07) << 5); + if (dpo) { + task->cdb[1] |= 0x10; + } + if (bytchk) { + 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.writeverify16.lba = lba; + task->params.writeverify16.num_blocks = xferlen/blocksize; + + return task; +} + int scsi_datain_getfullsize(struct scsi_task *task) { diff --git a/lib/sync.c b/lib/sync.c index ff4366b..644493b 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -528,6 +528,74 @@ iscsi_write16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, return state.task; } +struct scsi_task * +iscsi_writeverify10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, int group_number) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_writeverify10_task(iscsi, lun, lba, data, datalen, blocksize, + wrprotect, dpo, bytchk, group_number, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Writeverify10 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + +struct scsi_task * +iscsi_writeverify12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, int group_number) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_writeverify12_task(iscsi, lun, lba, + data, datalen, blocksize, wrprotect, + dpo, bytchk, group_number, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Writeverify12 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + +struct scsi_task * +iscsi_writeverify16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, + unsigned char *data, uint32_t datalen, int blocksize, + int wrprotect, int dpo, int bytchk, int group_number) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_writeverify16_task(iscsi, lun, lba, + data, datalen, blocksize, wrprotect, + dpo, bytchk, group_number, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Writeverify16 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)