diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 7d1ec75..145c58f 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -271,7 +271,8 @@ void iscsi_pdu_set_datasn(struct iscsi_pdu *pdu, uint32_t datasn); void iscsi_pdu_set_bufferoffset(struct iscsi_pdu *pdu, uint32_t bufferoffset); int iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, unsigned char *dptr, int dsize); -EXTERN int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); +int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); +int iscsi_send_unsolicited_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); int iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data, unsigned char *dptr, int dsize, int pdualignment); diff --git a/lib/connect.c b/lib/connect.c index 4f4e2d0..a132243 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -242,10 +242,6 @@ void iscsi_defer_reconnect(struct iscsi_context *iscsi) } } -int -iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu, - uint32_t ttt, uint32_t offset, uint32_t tot_len); - int iscsi_reconnect(struct iscsi_context *old_iscsi) { struct iscsi_context *iscsi; @@ -347,7 +343,11 @@ try_again: if (pdu->flags & ISCSI_PDU_DROP_ON_RECONNECT) { /* - * We don't want to requeue NOPs. + * We don't want to requeue NOPs or DATA-OUT PDUs. + * In case of DATA-OUT PDUs that are part of the + * initial unsolicited data we have to regenerate + * them forther down so that we end the re-queued + * WRITE + DATA-OUT train with a PDU with the F bit. */ iscsi_free_pdu(old_iscsi, pdu); continue; @@ -367,13 +367,12 @@ try_again: pdu->outdata_written = 0; pdu->payload_written = 0; iscsi_queue_pdu(iscsi, pdu); - /* All PDUs that write data and do not have final set - * needs some additional data-out to be requeued. + /* Requeue any unsolicited data-out for the command PDU we + * just re-queued. These are commands that write data to the + * device but does not have the F bit set. */ if ((pdu->outdata.data[1] & (ISCSI_PDU_SCSI_WRITE | ISCSI_PDU_SCSI_FINAL)) == ISCSI_PDU_SCSI_WRITE) { - iscsi_send_data_out(iscsi, pdu, 0xffffffff, - pdu->payload_len, - pdu->expxferlen - pdu->payload_len); + iscsi_send_unsolicited_data_out(iscsi, pdu); } } diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 22a7284..c874d9a 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -67,7 +67,7 @@ iscsi_scsi_response_cb(struct iscsi_context *iscsi, int status, } } -int +static int iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu, uint32_t ttt, uint32_t offset, uint32_t tot_len) { @@ -190,6 +190,17 @@ iscsi_timeout_scan(struct iscsi_context *iscsi) } } +int +iscsi_send_unsolicited_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) +{ + uint32_t len = pdu->expxferlen - pdu->payload_len; + + if (len > iscsi->first_burst_length) { + len = iscsi->first_burst_length; + } + return iscsi_send_data_out(iscsi, pdu, 0xffffffff, + pdu->payload_len, len); +} /* Using 'struct iscsi_data *d' for data-out is optional * and will be converted into a one element data-out iovector. @@ -326,13 +337,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, * subtract from first_burst_length. */ if (!(flags & ISCSI_PDU_SCSI_FINAL)) { - uint32_t len = pdu->expxferlen - pdu->payload_len; - - if (len > iscsi->first_burst_length) { - len = iscsi->first_burst_length; - } - iscsi_send_data_out(iscsi, pdu, 0xffffffff, - pdu->payload_len, len); + iscsi_send_unsolicited_data_out(iscsi, pdu); } /* remember cmdsn and itt so we can use task management */