int iscsit_create_recovery_datain_values_datasequenceinorder_no()

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;
}