lun_reset cancelling lun tasks only

The existing implementation of iscsi_task_mgmt_lun_reset_async cancels
all tasks in ready-to-send and wait-for-completion queues.
If the ISCSI context has in-flight tasks for a different LUNs or
tasks that are not LUN-specific (such as NOPIN, NOPOUT), those tasks
are not supposed to be affected by the LUN reset.
Also, the tasks for the LUN being reset may have in-flight responses
not affected by a concurrent LUN reset; they have to be handled
accordingly.

This change cancels only the tasks for the LUN being reset if they are
in the ready-to-send queue ('outqueue'). The tasks in the wait-for-
completion queue should be cancelled on LUN reset completion.
For example:

    iscsi_task_mgmt_lun_reset_async(iscsi, lun, lun_reset_cb, ctxt);
    ....
....
void lun_reset_cb(struct iscsi_context * iscsi, int status,
                  void * command_data, void * private_data)
{
    // 'response' field per ISCSI spec rfc7143 section 11.6.1
    uint8_t iscsi_response = *(uint8_t *)command_data;
    if (iscsi_response == 0) {
        // The LUN has been reset. No further replies are expected
        // for in-flight tasks for that LUN. Explicitly cancelling
        // the tasks in wait-for-completion queue.
        for (.. scsi_task-s in flight ..) {
            iscsi_scsi_cancel_task(iscsi, task);
        }
    } ...
}
This commit is contained in:
Anatoliy Glagolev
2023-09-26 15:03:30 -06:00
parent d0cc81347f
commit 35cf3a401c
3 changed files with 35 additions and 1 deletions

View File

@@ -293,6 +293,7 @@ void iscsi_pdu_set_ritt(struct iscsi_pdu *pdu, uint32_t ritt);
void iscsi_pdu_set_datasn(struct iscsi_pdu *pdu, uint32_t datasn);
void iscsi_pdu_set_bufferoffset(struct iscsi_pdu *pdu, uint32_t bufferoffset);
void iscsi_cancel_pdus(struct iscsi_context *iscsi);
void iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun);
int iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
const unsigned char *dptr, int dsize);
int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);

View File

@@ -799,3 +799,36 @@ iscsi_cancel_pdus(struct iscsi_context *iscsi)
iscsi->drv->free_pdu(iscsi, pdu);
}
}
void
iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *next_pdu;
uint32_t cmdsn_gap = 0;
struct scsi_task * task = NULL;
for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
task = iscsi_scsi_get_task_from_pdu(pdu);
if (cmdsn_gap > 0) {
iscsi_pdu_set_cmdsn(pdu, pdu->cmdsn - cmdsn_gap);
}
if (task == NULL || task->lun != lun) {
continue;
}
if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) &&
(pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) {
iscsi->cmdsn--;
cmdsn_gap++;
}
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
iscsi_set_error(iscsi, "command cancelled");
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED,
NULL, pdu->private_data);
}
iscsi->drv->free_pdu(iscsi, pdu);
}
}

View File

@@ -130,7 +130,7 @@ 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);
iscsi_cancel_lun_pdus(iscsi, lun);
return iscsi_task_mgmt_async(iscsi,
lun, ISCSI_TM_LUN_RESET,