diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 87e2336..ef6337e 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -271,7 +271,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, iscsi_pdu_set_expxferlen(pdu, task->expxferlen); /* cmdsn */ - iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn++); + iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); /* cdb */ iscsi_pdu_set_cdb(pdu, task); @@ -285,6 +285,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, iscsi->drv->free_pdu(iscsi, pdu); return -1; } + iscsi->cmdsn++; /* The F flag is not set. This means we haven't sent all the unsolicited * data yet. Sent as much as we are allowed as a train of DATA-OUT PDUs. @@ -2667,6 +2668,9 @@ iscsi_scsi_cancel_task(struct iscsi_context *iscsi, struct scsi_task *task) { struct iscsi_pdu *pdu; + struct iscsi_pdu *next_pdu; + uint32_t cmdsn_gap = 0; + int ret = -1; for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { if (pdu->itt == task->itt) { @@ -2679,22 +2683,45 @@ iscsi_scsi_cancel_task(struct iscsi_context *iscsi, return 0; } } - for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) { + for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) { + next_pdu = pdu->next; + + if (cmdsn_gap > 0) { + iscsi_pdu_set_cmdsn(pdu, pdu->cmdsn - cmdsn_gap); + } + if (pdu->itt == task->itt) { ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu); if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, pdu->private_data); } + if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) && + (pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) { + iscsi->cmdsn--; + cmdsn_gap++; + } iscsi->drv->free_pdu(iscsi, pdu); - return 0; + ret = 0; + if (!cmdsn_gap) { + break; + } } } - return -1; + + if (iscsi->old_iscsi) { + return iscsi_scsi_cancel_task(iscsi->old_iscsi, task); + } + + return ret; } void iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi) { iscsi_cancel_pdus(iscsi); + + if (iscsi->old_iscsi) { + iscsi_cancel_pdus(iscsi->old_iscsi); + } } diff --git a/lib/nop.c b/lib/nop.c index 2137530..2c1391a 100644 --- a/lib/nop.c +++ b/lib/nop.c @@ -64,7 +64,7 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, iscsi_pdu_set_lun(pdu, 0); /* cmdsn */ - iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn++); + iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->callback = cb; pdu->private_data = private_data; @@ -83,6 +83,7 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, return -1; } + iscsi->cmdsn++; iscsi->nops_in_flight++; ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6, "NOP Out Send (nops_in_flight: %d, pdu->cmdsn %08x, pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x)", diff --git a/lib/pdu.c b/lib/pdu.c index 8c8fc99..0f52504 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -719,10 +719,14 @@ iscsi_timeout_scan(struct iscsi_context *iscsi) struct iscsi_pdu *pdu; struct iscsi_pdu *next_pdu; time_t t = time(NULL); + uint32_t cmdsn_gap = 0; for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) { next_pdu = pdu->next; + if (cmdsn_gap > 0) { + iscsi_pdu_set_cmdsn(pdu, pdu->cmdsn - cmdsn_gap); + } if (pdu->scsi_timeout == 0) { /* no timeout for this pdu */ continue; @@ -731,6 +735,11 @@ iscsi_timeout_scan(struct iscsi_context *iscsi) /* not expired yet */ 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 timed out"); iscsi_dump_pdu_header(iscsi, pdu->outdata.data); @@ -775,21 +784,21 @@ iscsi_cancel_pdus(struct iscsi_context *iscsi) while ((pdu = iscsi->outqueue)) { ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu); - if (iscsi->is_loggedin && pdu->callback) { - /* If an error happened during connect/login, - we don't want to call any of the callbacks. - */ + if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, pdu->private_data); } iscsi->drv->free_pdu(iscsi, pdu); + if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) && + (pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) { + iscsi->cmdsn--; + } + + } while ((pdu = iscsi->waitpdu)) { ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu); - if (iscsi->is_loggedin && pdu->callback) { - /* If an error happened during connect/login, - we don't want to call any of the callbacks. - */ + if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, pdu->private_data); } diff --git a/lib/socket.c b/lib/socket.c index f7c1b15..dc197ff 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -913,7 +913,7 @@ iscsi_tcp_service(struct iscsi_context *iscsi, int revents) return iscsi_reconnect(iscsi); } else { if (iscsi->old_iscsi) { - return 0; + goto check_timeout; } } } @@ -999,8 +999,14 @@ iscsi_tcp_service(struct iscsi_context *iscsi, int revents) return iscsi_service_reconnect_if_loggedin(iscsi); } } + +check_timeout: iscsi_timeout_scan(iscsi); + if (iscsi->old_iscsi) { + iscsi_timeout_scan(iscsi->old_iscsi); + } + return 0; }