Task Management. When we abort a task or a task set, or reset the lun or target

we must also cancel all active tasks.
This will trigger all affected tasks to have their callback invoked with
SCSI_STATUS_CANCELLED
This commit is contained in:
Ronnie Sahlberg
2012-03-10 12:12:47 +11:00
parent 3f44347dae
commit 50594830bd
7 changed files with 83 additions and 6 deletions
+2
View File
@@ -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); unsigned long crc32c(char *buf, int len);
struct scsi_task *iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu);
#endif /* __iscsi_private_h__ */ #endif /* __iscsi_private_h__ */
+18 -4
View File
@@ -462,6 +462,11 @@ enum iscsi_task_mgmt_funcs {
* *
* The callback will NOT be invoked if the session is explicitely torn down * The callback will NOT be invoked if the session is explicitely torn down
* through a call to iscsi_disconnect() or iscsi_destroy_context(). * 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 EXTERN int
iscsi_task_mgmt_async(struct iscsi_context *iscsi, 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); 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. * This function is used when you want to cancel a scsi task.
* The task will be immeidately cancelled and the callback for the task will * The callback for the task will immediately be invoked with SCSI_STATUS_CANCELLED.
* never be invoked. * The cancellation is only local in libiscsi. If the task is already in-flight
* The cancellation is only local in libiscsi. If the tast is already in-flight
* this call will not cancel the task at the target. * 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. * 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, iscsi_scsi_task_cancel(struct iscsi_context *iscsi,
struct scsi_task *task); 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__ */ #endif /* __iscsi_h__ */
+2 -1
View File
@@ -59,7 +59,8 @@ iscsi_read6_sync
iscsi_read10_sync iscsi_read10_sync
iscsi_verify10_sync iscsi_verify10_sync
iscsi_write10_sync iscsi_write10_sync
iscsi_task_cancel iscsi_scsi_task_cancel
iscsi_scsi_cancel_all_tasks
poll poll
scsi_task_add_data_in_buffer scsi_task_add_data_in_buffer
scsi_sense_key_str scsi_sense_key_str
+6
View File
@@ -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); 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;
}
+43
View File
@@ -1197,6 +1197,10 @@ iscsi_scsi_task_cancel(struct iscsi_context *iscsi,
SLIST_REMOVE(&task->in_buffers, ptr); SLIST_REMOVE(&task->in_buffers, ptr);
} }
SLIST_REMOVE(&iscsi->waitpdu, pdu); 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); iscsi_free_pdu(iscsi, pdu);
return 0; return 0;
} }
@@ -1208,9 +1212,48 @@ iscsi_scsi_task_cancel(struct iscsi_context *iscsi,
SLIST_REMOVE(&task->in_buffers, ptr); SLIST_REMOVE(&task->in_buffers, ptr);
} }
SLIST_REMOVE(&iscsi->outqueue, pdu); 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); iscsi_free_pdu(iscsi, pdu);
return 0; return 0;
} }
} }
return -1; 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);
}
}
+11
View File
@@ -97,6 +97,8 @@ iscsi_task_mgmt_abort_task_async(struct iscsi_context *iscsi,
struct scsi_task *task, struct scsi_task *task,
iscsi_command_cb cb, void *private_data) iscsi_command_cb cb, void *private_data)
{ {
iscsi_scsi_task_cancel(iscsi, task);
return iscsi_task_mgmt_async(iscsi, return iscsi_task_mgmt_async(iscsi,
task->lun, ISCSI_TM_ABORT_TASK, task->lun, ISCSI_TM_ABORT_TASK,
task->itt, task->cmdsn, task->itt, task->cmdsn,
@@ -108,6 +110,8 @@ iscsi_task_mgmt_abort_task_set_async(struct iscsi_context *iscsi,
uint32_t lun, uint32_t lun,
iscsi_command_cb cb, void *private_data) iscsi_command_cb cb, void *private_data)
{ {
iscsi_scsi_cancel_all_tasks(iscsi);
return iscsi_task_mgmt_async(iscsi, return iscsi_task_mgmt_async(iscsi,
lun, ISCSI_TM_ABORT_TASK_SET, lun, ISCSI_TM_ABORT_TASK_SET,
0xffffffff, 0, 0xffffffff, 0,
@@ -119,6 +123,8 @@ iscsi_task_mgmt_lun_reset_async(struct iscsi_context *iscsi,
uint32_t lun, uint32_t lun,
iscsi_command_cb cb, void *private_data) iscsi_command_cb cb, void *private_data)
{ {
iscsi_scsi_cancel_all_tasks(iscsi);
return iscsi_task_mgmt_async(iscsi, return iscsi_task_mgmt_async(iscsi,
lun, ISCSI_TM_LUN_RESET, lun, ISCSI_TM_LUN_RESET,
0xffffffff, 0, 0xffffffff, 0,
@@ -129,16 +135,21 @@ int
iscsi_task_mgmt_target_warm_reset_async(struct iscsi_context *iscsi, iscsi_task_mgmt_target_warm_reset_async(struct iscsi_context *iscsi,
iscsi_command_cb cb, void *private_data) iscsi_command_cb cb, void *private_data)
{ {
iscsi_scsi_cancel_all_tasks(iscsi);
return iscsi_task_mgmt_async(iscsi, return iscsi_task_mgmt_async(iscsi,
0, ISCSI_TM_TARGET_WARM_RESET, 0, ISCSI_TM_TARGET_WARM_RESET,
0xffffffff, 0, 0xffffffff, 0,
cb, private_data); cb, private_data);
} }
int int
iscsi_task_mgmt_target_cold_reset_async(struct iscsi_context *iscsi, iscsi_task_mgmt_target_cold_reset_async(struct iscsi_context *iscsi,
iscsi_command_cb cb, void *private_data) iscsi_command_cb cb, void *private_data)
{ {
iscsi_scsi_cancel_all_tasks(iscsi);
return iscsi_task_mgmt_async(iscsi, return iscsi_task_mgmt_async(iscsi,
0, ISCSI_TM_TARGET_COLD_RESET, 0, ISCSI_TM_TARGET_COLD_RESET,
0xffffffff, 0, 0xffffffff, 0,
+1 -1
View File
@@ -25,7 +25,7 @@
#include "scsi-lowlevel.h" #include "scsi-lowlevel.h"
int showluns; int showluns;
char *initiator = "iqn.2010-11.ronnie:iscsi-ls"; const char *initiator = "iqn.2010-11.ronnie:iscsi-ls";
struct client_state { struct client_state {
int finished; int finished;