in iscsi/iscsi_target_erl1.c [215:371]
int iscsit_create_recovery_datain_values_datasequenceinorder_no(
struct iscsi_cmd *cmd,
struct iscsi_datain_req *dr)
{
int found_seq = 0, i;
u32 data_sn, read_data_done = 0, seq_send_order = 0;
u32 begrun = dr->begrun;
u32 runlength = dr->runlength;
struct iscsi_conn *conn = cmd->conn;
struct iscsi_seq *first_seq = NULL, *seq = NULL;
if (!cmd->seq_list) {
pr_err("struct iscsi_cmd->seq_list is NULL!\n");
return -1;
}
/*
* Calculate read_data_done for all sequences containing a
* first_datasn and last_datasn less than the BegRun.
*
* Locate the struct iscsi_seq the BegRun lies within and calculate
* NextBurstLenghth up to the DataSN based on MaxRecvDataSegmentLength.
*
* Also use struct iscsi_seq->seq_send_order to determine where to start.
*/
for (i = 0; i < cmd->seq_count; i++) {
seq = &cmd->seq_list[i];
if (!seq->seq_send_order)
first_seq = seq;
/*
* No data has been transferred for this DataIN sequence, so the
* seq->first_datasn and seq->last_datasn have not been set.
*/
if (!seq->sent) {
pr_err("Ignoring non-sent sequence 0x%08x ->"
" 0x%08x\n\n", seq->first_datasn,
seq->last_datasn);
continue;
}
/*
* This DataIN sequence is precedes the received BegRun, add the
* total xfer_len of the sequence to read_data_done and reset
* seq->pdu_send_order.
*/
if ((seq->first_datasn < begrun) &&
(seq->last_datasn < begrun)) {
pr_err("Pre BegRun sequence 0x%08x ->"
" 0x%08x\n", seq->first_datasn,
seq->last_datasn);
read_data_done += cmd->seq_list[i].xfer_len;
seq->next_burst_len = seq->pdu_send_order = 0;
continue;
}
/*
* The BegRun lies within this DataIN sequence.
*/
if ((seq->first_datasn <= begrun) &&
(seq->last_datasn >= begrun)) {
pr_err("Found sequence begrun: 0x%08x in"
" 0x%08x -> 0x%08x\n", begrun,
seq->first_datasn, seq->last_datasn);
seq_send_order = seq->seq_send_order;
data_sn = seq->first_datasn;
seq->next_burst_len = seq->pdu_send_order = 0;
found_seq = 1;
/*
* For DataPDUInOrder=Yes, while the first DataSN of
* the sequence is less than the received BegRun, add
* the MaxRecvDataSegmentLength to read_data_done and
* to the sequence's next_burst_len;
*
* For DataPDUInOrder=No, while the first DataSN of the
* sequence is less than the received BegRun, find the
* struct iscsi_pdu of the DataSN in question and add the
* MaxRecvDataSegmentLength to read_data_done and to the
* sequence's next_burst_len;
*/
if (conn->sess->sess_ops->DataPDUInOrder) {
while (data_sn < begrun) {
seq->pdu_send_order++;
read_data_done +=
conn->conn_ops->MaxRecvDataSegmentLength;
seq->next_burst_len +=
conn->conn_ops->MaxRecvDataSegmentLength;
data_sn++;
}
} else {
int j;
struct iscsi_pdu *pdu;
while (data_sn < begrun) {
seq->pdu_send_order++;
for (j = 0; j < seq->pdu_count; j++) {
pdu = &cmd->pdu_list[
seq->pdu_start + j];
if (pdu->data_sn == data_sn) {
read_data_done +=
pdu->length;
seq->next_burst_len +=
pdu->length;
}
}
data_sn++;
}
}
continue;
}
/*
* This DataIN sequence is larger than the received BegRun,
* reset seq->pdu_send_order and continue.
*/
if ((seq->first_datasn > begrun) ||
(seq->last_datasn > begrun)) {
pr_err("Post BegRun sequence 0x%08x -> 0x%08x\n",
seq->first_datasn, seq->last_datasn);
seq->next_burst_len = seq->pdu_send_order = 0;
continue;
}
}
if (!found_seq) {
if (!begrun) {
if (!first_seq) {
pr_err("ITT: 0x%08x, Begrun: 0x%08x"
" but first_seq is NULL\n",
cmd->init_task_tag, begrun);
return -1;
}
seq_send_order = first_seq->seq_send_order;
seq->next_burst_len = seq->pdu_send_order = 0;
goto done;
}
pr_err("Unable to locate struct iscsi_seq for ITT: 0x%08x,"
" BegRun: 0x%08x, RunLength: 0x%08x while"
" DataSequenceInOrder=No and DataPDUInOrder=%s.\n",
cmd->init_task_tag, begrun, runlength,
(conn->sess->sess_ops->DataPDUInOrder) ? "Yes" : "No");
return -1;
}
done:
dr->read_data_done = read_data_done;
dr->seq_send_order = seq_send_order;
return 0;
}