diff --git a/include/iscsi.h b/include/iscsi.h index 0436230..f980e64 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -661,6 +661,11 @@ iscsi_orwrite_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_startstopunit_task(struct iscsi_context *iscsi, int lun, + int immed, int pcm, int pc, + int no_flush, int loej, int start, + iscsi_command_cb cb, void *private_data); +EXTERN struct scsi_task * iscsi_compareandwrite_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, @@ -791,6 +796,11 @@ iscsi_orwrite_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_startstopunit_sync(struct iscsi_context *iscsi, int lun, + int immed, int pcm, int pc, + int no_flush, int loej, int start); + EXTERN struct scsi_task * iscsi_compareandwrite_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t datalen, int blocksize, diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index c607ccc..94523d2 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -28,6 +28,7 @@ enum scsi_opcode { SCSI_OPCODE_READ6 = 0x08, SCSI_OPCODE_INQUIRY = 0x12, SCSI_OPCODE_MODESENSE6 = 0x1a, + SCSI_OPCODE_STARTSTOPUNIT = 0x1b, SCSI_OPCODE_READCAPACITY10 = 0x25, SCSI_OPCODE_READ10 = 0x28, SCSI_OPCODE_WRITE10 = 0x2A, @@ -133,6 +134,14 @@ struct scsi_write16_params { uint64_t lba; uint32_t num_blocks; }; +struct scsi_startstopunit_params { + int immed; + int pcm; + int pc; + int no_flush; + int loej; + int start; +}; struct scsi_orwrite_params { uint64_t lba; uint32_t num_blocks; @@ -229,6 +238,7 @@ struct scsi_task { struct scsi_write10_params write10; struct scsi_write12_params write12; struct scsi_write16_params write16; + struct scsi_startstopunit_params startstopunit; struct scsi_orwrite_params orwrite; struct scsi_compareandwrite_params compareandwrite; struct scsi_writeverify10_params writeverify10; @@ -662,6 +672,7 @@ 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_startstopunit(int immed, int pcm, int pc, int no_flush, int loej, int start); EXTERN struct scsi_task *scsi_cdb_orwrite(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_compareandwrite(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); diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 9120089..3c99a9b 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -61,6 +61,8 @@ iscsi_set_isid_reserved iscsi_set_session_type iscsi_set_targetname iscsi_set_tcp_keepalive +iscsi_startstopunit_sync +iscsi_startstopunit_task iscsi_synchronizecache10_sync iscsi_synchronizecache10_task iscsi_synchronizecache16_sync @@ -115,7 +117,9 @@ scsi_cdb_read6 scsi_cdb_readcapacity10 scsi_cdb_readcapacity16 scsi_cdb_serviceactionin16 +scsi_cdb_startstopunit scsi_cdb_synchronizecache10 +scsi_cdb_synchronizecache16 scsi_cdb_testunitready scsi_cdb_unmap scsi_cdb_verify10 diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index 20af681..c475765 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -59,6 +59,8 @@ iscsi_set_isid_reserved iscsi_set_session_type iscsi_set_targetname iscsi_set_tcp_keepalive +iscsi_startstopunit_sync +iscsi_startstopunit_task iscsi_synchronizecache10_sync iscsi_synchronizecache10_task iscsi_synchronizecache16_sync @@ -113,7 +115,9 @@ scsi_cdb_read6 scsi_cdb_readcapacity10 scsi_cdb_readcapacity16 scsi_cdb_serviceactionin16 +scsi_cdb_startstopunit scsi_cdb_synchronizecache10 +scsi_cdb_synchronizecache16 scsi_cdb_testunitready scsi_cdb_unmap scsi_cdb_verify10 diff --git a/lib/scsi-command.c b/lib/scsi-command.c index 96d3130..56f2f54 100644 --- a/lib/scsi-command.c +++ b/lib/scsi-command.c @@ -1168,6 +1168,30 @@ iscsi_modesense6_task(struct iscsi_context *iscsi, int lun, int dbd, int pc, return task; } +struct scsi_task * +iscsi_startstopunit_task(struct iscsi_context *iscsi, int lun, + int immed, int pcm, int pc, + int no_flush, int loej, int start, + iscsi_command_cb cb, void *private_data) +{ + struct scsi_task *task; + + task = scsi_cdb_startstopunit(immed, pcm, pc, no_flush, + loej, start); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "startstopunit 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_synchronizecache10_task(struct iscsi_context *iscsi, int lun, int lba, int num_blocks, int syncnv, int immed, diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index cae8d30..8f738e5 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -1521,6 +1521,51 @@ scsi_modesense_datain_unmarshall(struct scsi_task *task) return ms; } +/* + * STARTSTOPUNIT + */ +struct scsi_task * +scsi_cdb_startstopunit(int immed, int pcm, int pc, int no_flush, int loej, int start) +{ + 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_STARTSTOPUNIT; + + if (immed) { + task->cdb[1] |= 0x01; + } + task->cdb[3] |= pcm & 0x0f; + task->cdb[4] |= (pc << 4) & 0xf0; + if (no_flush) { + task->cdb[4] |= 0x04; + } + if (loej) { + task->cdb[4] |= 0x02; + } + if (start) { + task->cdb[4] |= 0x01; + } + + + task->cdb_size = 6; + task->xfer_dir = SCSI_XFER_NONE; + task->expxferlen = 0; + + task->params.startstopunit.immed = immed; + task->params.startstopunit.pcm = pcm; + task->params.startstopunit.pc = pc; + task->params.startstopunit.no_flush = no_flush; + task->params.startstopunit.loej = loej; + task->params.startstopunit.start = start; + + return task; +} /* * SYNCHRONIZECACHE10 diff --git a/lib/sync.c b/lib/sync.c index 6c93b96..fdcd401 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -397,6 +397,28 @@ iscsi_synchronizecache10_sync(struct iscsi_context *iscsi, int lun, int lba, return state.task; } +struct scsi_task * +iscsi_startstopunit_sync(struct iscsi_context *iscsi, int lun, + int immed, int pcm, int pc, + int no_flush, int loej, int start) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_startstopunit_task(iscsi, lun, immed, pcm, pc, + no_flush, loej, start, + scsi_sync_cb, &state) == NULL) { + iscsi_set_error(iscsi, + "Failed to send StartStopUnit command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_synchronizecache16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t num_blocks, int syncnv, int immed)