diff --git a/include/iscsi-private.h b/include/iscsi-private.h index c061516..6229cfc 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -259,5 +259,7 @@ unsigned char *scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos unsigned long crc32c(char *buf, int len); +struct scsi_task *iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu); + #endif /* __iscsi_private_h__ */ diff --git a/include/iscsi.h b/include/iscsi.h index 6e6fb26..06fae78 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -462,6 +462,11 @@ enum iscsi_task_mgmt_funcs { * * The callback will NOT be invoked if the session is explicitely torn down * through a call to iscsi_disconnect() or iscsi_destroy_context(). + * + * abort_task will also cancel the scsi task. The callback for the scsi task will be invoked with + * SCSI_STATUS_CANCELLED + * abort_task_set, lun_reset, target_warn_reset, target_cold_reset will cancel all tasks. The callback for + * all tasks will be invoked with SCSI_STATUS_CANCELLED */ EXTERN int iscsi_task_mgmt_async(struct iscsi_context *iscsi, @@ -674,10 +679,9 @@ iscsi_verify10_sync(struct iscsi_context *iscsi, int lun, EXTERN int scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf); /* - * This function is used when you want to cancel a iscsi task. - * The task will be immeidately cancelled and the callback for the task will - * never be invoked. - * The cancellation is only local in libiscsi. If the tast is already in-flight + * This function is used when you want to cancel a scsi task. + * The callback for the task will immediately be invoked with SCSI_STATUS_CANCELLED. + * The cancellation is only local in libiscsi. If the task is already in-flight * this call will not cancel the task at the target. * To cancel the task also a the target you need to call the task management functions. */ @@ -685,4 +689,14 @@ EXTERN int iscsi_scsi_task_cancel(struct iscsi_context *iscsi, struct scsi_task *task); +/* + * This function is used when you want to cancel all scsi tasks. + * The callback for the tasks will immediately be invoked with SCSI_STATUS_CANCELLED. + * The cancellation is only local in libiscsi. If the tasks are already in-flight + * this call will not cancel the tasks at the target. + * To cancel the tasks also a the target you need to call the task management functions. + */ +EXTERN void +iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi); + #endif /* __iscsi_h__ */ diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 32ce0be..e9e8a33 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -59,7 +59,8 @@ iscsi_read6_sync iscsi_read10_sync iscsi_verify10_sync iscsi_write10_sync -iscsi_task_cancel +iscsi_scsi_task_cancel +iscsi_scsi_cancel_all_tasks poll scsi_task_add_data_in_buffer scsi_sense_key_str diff --git a/lib/scsi-command.c b/lib/scsi-command.c index 2ab38e2..35c2f75 100644 --- a/lib/scsi-command.c +++ b/lib/scsi-command.c @@ -798,3 +798,9 @@ iscsi_get_user_in_buffer(struct iscsi_context *iscsi, struct iscsi_in_pdu *in, u return scsi_task_get_data_in_buffer(pdu->scsi_cbdata->task, offset + pos, count); } + +struct scsi_task * +iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu) +{ + return pdu->scsi_cbdata->task; +} diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index e2db940..465e445 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -1197,6 +1197,10 @@ iscsi_scsi_task_cancel(struct iscsi_context *iscsi, SLIST_REMOVE(&task->in_buffers, ptr); } SLIST_REMOVE(&iscsi->waitpdu, pdu); + if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { + pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, + pdu->private_data); + } iscsi_free_pdu(iscsi, pdu); return 0; } @@ -1208,9 +1212,48 @@ iscsi_scsi_task_cancel(struct iscsi_context *iscsi, SLIST_REMOVE(&task->in_buffers, ptr); } SLIST_REMOVE(&iscsi->outqueue, pdu); + if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { + pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, + pdu->private_data); + } iscsi_free_pdu(iscsi, pdu); return 0; } } return -1; } + +void +iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi) +{ + struct iscsi_pdu *pdu; + + for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { + struct scsi_task *task = iscsi_scsi_get_task_from_pdu(pdu); + + while(task->in_buffers != NULL) { + struct scsi_data_buffer *ptr = task->in_buffers; + SLIST_REMOVE(&task->in_buffers, ptr); + } + SLIST_REMOVE(&iscsi->waitpdu, pdu); + if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { + pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, + pdu->private_data); + } + iscsi_free_pdu(iscsi, pdu); + } + for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) { + struct scsi_task *task = iscsi_scsi_get_task_from_pdu(pdu); + + while(task->in_buffers != NULL) { + struct scsi_data_buffer *ptr = task->in_buffers; + SLIST_REMOVE(&task->in_buffers, ptr); + } + SLIST_REMOVE(&iscsi->outqueue, pdu); + if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { + pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, + pdu->private_data); + } + iscsi_free_pdu(iscsi, pdu); + } +} diff --git a/lib/task_mgmt.c b/lib/task_mgmt.c index cc12585..513a8d4 100644 --- a/lib/task_mgmt.c +++ b/lib/task_mgmt.c @@ -97,6 +97,8 @@ iscsi_task_mgmt_abort_task_async(struct iscsi_context *iscsi, struct scsi_task *task, iscsi_command_cb cb, void *private_data) { + iscsi_scsi_task_cancel(iscsi, task); + return iscsi_task_mgmt_async(iscsi, task->lun, ISCSI_TM_ABORT_TASK, task->itt, task->cmdsn, @@ -108,6 +110,8 @@ iscsi_task_mgmt_abort_task_set_async(struct iscsi_context *iscsi, uint32_t lun, iscsi_command_cb cb, void *private_data) { + iscsi_scsi_cancel_all_tasks(iscsi); + return iscsi_task_mgmt_async(iscsi, lun, ISCSI_TM_ABORT_TASK_SET, 0xffffffff, 0, @@ -119,6 +123,8 @@ iscsi_task_mgmt_lun_reset_async(struct iscsi_context *iscsi, uint32_t lun, iscsi_command_cb cb, void *private_data) { + iscsi_scsi_cancel_all_tasks(iscsi); + return iscsi_task_mgmt_async(iscsi, lun, ISCSI_TM_LUN_RESET, 0xffffffff, 0, @@ -129,16 +135,21 @@ int iscsi_task_mgmt_target_warm_reset_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data) { + iscsi_scsi_cancel_all_tasks(iscsi); + return iscsi_task_mgmt_async(iscsi, 0, ISCSI_TM_TARGET_WARM_RESET, 0xffffffff, 0, cb, private_data); } + int iscsi_task_mgmt_target_cold_reset_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data) { + iscsi_scsi_cancel_all_tasks(iscsi); + return iscsi_task_mgmt_async(iscsi, 0, ISCSI_TM_TARGET_COLD_RESET, 0xffffffff, 0, diff --git a/src/iscsi-ls.c b/src/iscsi-ls.c index 0e91d4c..34b7f88 100644 --- a/src/iscsi-ls.c +++ b/src/iscsi-ls.c @@ -25,7 +25,7 @@ #include "scsi-lowlevel.h" int showluns; -char *initiator = "iqn.2010-11.ronnie:iscsi-ls"; +const char *initiator = "iqn.2010-11.ronnie:iscsi-ls"; struct client_state { int finished;