18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*******************************************************************************
38c2ecf20Sopenharmony_ci * This file contains the iSCSI Target DataIN value generation functions.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * (c) Copyright 2007-2013 Datera, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci ******************************************************************************/
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <scsi/iscsi_proto.h>
138c2ecf20Sopenharmony_ci#include <target/iscsi/iscsi_target_core.h>
148c2ecf20Sopenharmony_ci#include "iscsi_target_seq_pdu_list.h"
158c2ecf20Sopenharmony_ci#include "iscsi_target_erl1.h"
168c2ecf20Sopenharmony_ci#include "iscsi_target_util.h"
178c2ecf20Sopenharmony_ci#include "iscsi_target.h"
188c2ecf20Sopenharmony_ci#include "iscsi_target_datain_values.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct iscsi_datain_req *iscsit_allocate_datain_req(void)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	struct iscsi_datain_req *dr;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC);
258c2ecf20Sopenharmony_ci	if (!dr) {
268c2ecf20Sopenharmony_ci		pr_err("Unable to allocate memory for"
278c2ecf20Sopenharmony_ci				" struct iscsi_datain_req\n");
288c2ecf20Sopenharmony_ci		return NULL;
298c2ecf20Sopenharmony_ci	}
308c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dr->cmd_datain_node);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	return dr;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_civoid iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	spin_lock(&cmd->datain_lock);
388c2ecf20Sopenharmony_ci	list_add_tail(&dr->cmd_datain_node, &cmd->datain_list);
398c2ecf20Sopenharmony_ci	spin_unlock(&cmd->datain_lock);
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_civoid iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	spin_lock(&cmd->datain_lock);
458c2ecf20Sopenharmony_ci	list_del(&dr->cmd_datain_node);
468c2ecf20Sopenharmony_ci	spin_unlock(&cmd->datain_lock);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	kmem_cache_free(lio_dr_cache, dr);
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_civoid iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	struct iscsi_datain_req *dr, *dr_tmp;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	spin_lock(&cmd->datain_lock);
568c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) {
578c2ecf20Sopenharmony_ci		list_del(&dr->cmd_datain_node);
588c2ecf20Sopenharmony_ci		kmem_cache_free(lio_dr_cache, dr);
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci	spin_unlock(&cmd->datain_lock);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistruct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	if (list_empty(&cmd->datain_list)) {
668c2ecf20Sopenharmony_ci		pr_err("cmd->datain_list is empty for ITT:"
678c2ecf20Sopenharmony_ci			" 0x%08x\n", cmd->init_task_tag);
688c2ecf20Sopenharmony_ci		return NULL;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return list_first_entry(&cmd->datain_list, struct iscsi_datain_req,
728c2ecf20Sopenharmony_ci				cmd_datain_node);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/*
768c2ecf20Sopenharmony_ci *	For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.
778c2ecf20Sopenharmony_ci */
788c2ecf20Sopenharmony_cistatic struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(
798c2ecf20Sopenharmony_ci	struct iscsi_cmd *cmd,
808c2ecf20Sopenharmony_ci	struct iscsi_datain *datain)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	u32 next_burst_len, read_data_done, read_data_left;
838c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = cmd->conn;
848c2ecf20Sopenharmony_ci	struct iscsi_datain_req *dr;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	dr = iscsit_get_datain_req(cmd);
878c2ecf20Sopenharmony_ci	if (!dr)
888c2ecf20Sopenharmony_ci		return NULL;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (dr->recovery && dr->generate_recovery_values) {
918c2ecf20Sopenharmony_ci		if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
928c2ecf20Sopenharmony_ci					cmd, dr) < 0)
938c2ecf20Sopenharmony_ci			return NULL;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		dr->generate_recovery_values = 0;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	next_burst_len = (!dr->recovery) ?
998c2ecf20Sopenharmony_ci			cmd->next_burst_len : dr->next_burst_len;
1008c2ecf20Sopenharmony_ci	read_data_done = (!dr->recovery) ?
1018c2ecf20Sopenharmony_ci			cmd->read_data_done : dr->read_data_done;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	read_data_left = (cmd->se_cmd.data_length - read_data_done);
1048c2ecf20Sopenharmony_ci	if (!read_data_left) {
1058c2ecf20Sopenharmony_ci		pr_err("ITT: 0x%08x read_data_left is zero!\n",
1068c2ecf20Sopenharmony_ci				cmd->init_task_tag);
1078c2ecf20Sopenharmony_ci		return NULL;
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) &&
1118c2ecf20Sopenharmony_ci	    (read_data_left <= (conn->sess->sess_ops->MaxBurstLength -
1128c2ecf20Sopenharmony_ci	     next_burst_len))) {
1138c2ecf20Sopenharmony_ci		datain->length = read_data_left;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci		datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
1168c2ecf20Sopenharmony_ci		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
1178c2ecf20Sopenharmony_ci			datain->flags |= ISCSI_FLAG_DATA_ACK;
1188c2ecf20Sopenharmony_ci	} else {
1198c2ecf20Sopenharmony_ci		if ((next_burst_len +
1208c2ecf20Sopenharmony_ci		     conn->conn_ops->MaxRecvDataSegmentLength) <
1218c2ecf20Sopenharmony_ci		     conn->sess->sess_ops->MaxBurstLength) {
1228c2ecf20Sopenharmony_ci			datain->length =
1238c2ecf20Sopenharmony_ci				conn->conn_ops->MaxRecvDataSegmentLength;
1248c2ecf20Sopenharmony_ci			next_burst_len += datain->length;
1258c2ecf20Sopenharmony_ci		} else {
1268c2ecf20Sopenharmony_ci			datain->length = (conn->sess->sess_ops->MaxBurstLength -
1278c2ecf20Sopenharmony_ci					  next_burst_len);
1288c2ecf20Sopenharmony_ci			next_burst_len = 0;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci			datain->flags |= ISCSI_FLAG_CMD_FINAL;
1318c2ecf20Sopenharmony_ci			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
1328c2ecf20Sopenharmony_ci				datain->flags |= ISCSI_FLAG_DATA_ACK;
1338c2ecf20Sopenharmony_ci		}
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
1378c2ecf20Sopenharmony_ci	datain->offset = read_data_done;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (!dr->recovery) {
1408c2ecf20Sopenharmony_ci		cmd->next_burst_len = next_burst_len;
1418c2ecf20Sopenharmony_ci		cmd->read_data_done += datain->length;
1428c2ecf20Sopenharmony_ci	} else {
1438c2ecf20Sopenharmony_ci		dr->next_burst_len = next_burst_len;
1448c2ecf20Sopenharmony_ci		dr->read_data_done += datain->length;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (!dr->recovery) {
1488c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_DATA_STATUS)
1498c2ecf20Sopenharmony_ci			dr->dr_complete = DATAIN_COMPLETE_NORMAL;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		return dr;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (!dr->runlength) {
1558c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
1568c2ecf20Sopenharmony_ci			dr->dr_complete =
1578c2ecf20Sopenharmony_ci			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
1588c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
1598c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_CONNECTION_RECOVERY;
1608c2ecf20Sopenharmony_ci		}
1618c2ecf20Sopenharmony_ci	} else {
1628c2ecf20Sopenharmony_ci		if ((dr->begrun + dr->runlength) == dr->data_sn) {
1638c2ecf20Sopenharmony_ci			dr->dr_complete =
1648c2ecf20Sopenharmony_ci			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
1658c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
1668c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_CONNECTION_RECOVERY;
1678c2ecf20Sopenharmony_ci		}
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return dr;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/*
1748c2ecf20Sopenharmony_ci *	For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes.
1758c2ecf20Sopenharmony_ci */
1768c2ecf20Sopenharmony_cistatic struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
1778c2ecf20Sopenharmony_ci	struct iscsi_cmd *cmd,
1788c2ecf20Sopenharmony_ci	struct iscsi_datain *datain)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	u32 offset, read_data_done, read_data_left, seq_send_order;
1818c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = cmd->conn;
1828c2ecf20Sopenharmony_ci	struct iscsi_datain_req *dr;
1838c2ecf20Sopenharmony_ci	struct iscsi_seq *seq;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	dr = iscsit_get_datain_req(cmd);
1868c2ecf20Sopenharmony_ci	if (!dr)
1878c2ecf20Sopenharmony_ci		return NULL;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (dr->recovery && dr->generate_recovery_values) {
1908c2ecf20Sopenharmony_ci		if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
1918c2ecf20Sopenharmony_ci					cmd, dr) < 0)
1928c2ecf20Sopenharmony_ci			return NULL;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		dr->generate_recovery_values = 0;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	read_data_done = (!dr->recovery) ?
1988c2ecf20Sopenharmony_ci			cmd->read_data_done : dr->read_data_done;
1998c2ecf20Sopenharmony_ci	seq_send_order = (!dr->recovery) ?
2008c2ecf20Sopenharmony_ci			cmd->seq_send_order : dr->seq_send_order;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	read_data_left = (cmd->se_cmd.data_length - read_data_done);
2038c2ecf20Sopenharmony_ci	if (!read_data_left) {
2048c2ecf20Sopenharmony_ci		pr_err("ITT: 0x%08x read_data_left is zero!\n",
2058c2ecf20Sopenharmony_ci				cmd->init_task_tag);
2068c2ecf20Sopenharmony_ci		return NULL;
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
2108c2ecf20Sopenharmony_ci	if (!seq)
2118c2ecf20Sopenharmony_ci		return NULL;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	seq->sent = 1;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (!dr->recovery && !seq->next_burst_len)
2168c2ecf20Sopenharmony_ci		seq->first_datasn = cmd->data_sn;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	offset = (seq->offset + seq->next_burst_len);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
2218c2ecf20Sopenharmony_ci	     cmd->se_cmd.data_length) {
2228c2ecf20Sopenharmony_ci		datain->length = (cmd->se_cmd.data_length - offset);
2238c2ecf20Sopenharmony_ci		datain->offset = offset;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		datain->flags |= ISCSI_FLAG_CMD_FINAL;
2268c2ecf20Sopenharmony_ci		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
2278c2ecf20Sopenharmony_ci			datain->flags |= ISCSI_FLAG_DATA_ACK;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci		seq->next_burst_len = 0;
2308c2ecf20Sopenharmony_ci		seq_send_order++;
2318c2ecf20Sopenharmony_ci	} else {
2328c2ecf20Sopenharmony_ci		if ((seq->next_burst_len +
2338c2ecf20Sopenharmony_ci		     conn->conn_ops->MaxRecvDataSegmentLength) <
2348c2ecf20Sopenharmony_ci		     conn->sess->sess_ops->MaxBurstLength) {
2358c2ecf20Sopenharmony_ci			datain->length =
2368c2ecf20Sopenharmony_ci				conn->conn_ops->MaxRecvDataSegmentLength;
2378c2ecf20Sopenharmony_ci			datain->offset = (seq->offset + seq->next_burst_len);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci			seq->next_burst_len += datain->length;
2408c2ecf20Sopenharmony_ci		} else {
2418c2ecf20Sopenharmony_ci			datain->length = (conn->sess->sess_ops->MaxBurstLength -
2428c2ecf20Sopenharmony_ci					  seq->next_burst_len);
2438c2ecf20Sopenharmony_ci			datain->offset = (seq->offset + seq->next_burst_len);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci			datain->flags |= ISCSI_FLAG_CMD_FINAL;
2468c2ecf20Sopenharmony_ci			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
2478c2ecf20Sopenharmony_ci				datain->flags |= ISCSI_FLAG_DATA_ACK;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci			seq->next_burst_len = 0;
2508c2ecf20Sopenharmony_ci			seq_send_order++;
2518c2ecf20Sopenharmony_ci		}
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if ((read_data_done + datain->length) == cmd->se_cmd.data_length)
2558c2ecf20Sopenharmony_ci		datain->flags |= ISCSI_FLAG_DATA_STATUS;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
2588c2ecf20Sopenharmony_ci	if (!dr->recovery) {
2598c2ecf20Sopenharmony_ci		cmd->seq_send_order = seq_send_order;
2608c2ecf20Sopenharmony_ci		cmd->read_data_done += datain->length;
2618c2ecf20Sopenharmony_ci	} else {
2628c2ecf20Sopenharmony_ci		dr->seq_send_order = seq_send_order;
2638c2ecf20Sopenharmony_ci		dr->read_data_done += datain->length;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (!dr->recovery) {
2678c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_CMD_FINAL)
2688c2ecf20Sopenharmony_ci			seq->last_datasn = datain->data_sn;
2698c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_DATA_STATUS)
2708c2ecf20Sopenharmony_ci			dr->dr_complete = DATAIN_COMPLETE_NORMAL;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		return dr;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (!dr->runlength) {
2768c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
2778c2ecf20Sopenharmony_ci			dr->dr_complete =
2788c2ecf20Sopenharmony_ci			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
2798c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
2808c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_CONNECTION_RECOVERY;
2818c2ecf20Sopenharmony_ci		}
2828c2ecf20Sopenharmony_ci	} else {
2838c2ecf20Sopenharmony_ci		if ((dr->begrun + dr->runlength) == dr->data_sn) {
2848c2ecf20Sopenharmony_ci			dr->dr_complete =
2858c2ecf20Sopenharmony_ci			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
2868c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
2878c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_CONNECTION_RECOVERY;
2888c2ecf20Sopenharmony_ci		}
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return dr;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/*
2958c2ecf20Sopenharmony_ci *	For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No.
2968c2ecf20Sopenharmony_ci */
2978c2ecf20Sopenharmony_cistatic struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
2988c2ecf20Sopenharmony_ci	struct iscsi_cmd *cmd,
2998c2ecf20Sopenharmony_ci	struct iscsi_datain *datain)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	u32 next_burst_len, read_data_done, read_data_left;
3028c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = cmd->conn;
3038c2ecf20Sopenharmony_ci	struct iscsi_datain_req *dr;
3048c2ecf20Sopenharmony_ci	struct iscsi_pdu *pdu;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	dr = iscsit_get_datain_req(cmd);
3078c2ecf20Sopenharmony_ci	if (!dr)
3088c2ecf20Sopenharmony_ci		return NULL;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (dr->recovery && dr->generate_recovery_values) {
3118c2ecf20Sopenharmony_ci		if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
3128c2ecf20Sopenharmony_ci					cmd, dr) < 0)
3138c2ecf20Sopenharmony_ci			return NULL;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		dr->generate_recovery_values = 0;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	next_burst_len = (!dr->recovery) ?
3198c2ecf20Sopenharmony_ci			cmd->next_burst_len : dr->next_burst_len;
3208c2ecf20Sopenharmony_ci	read_data_done = (!dr->recovery) ?
3218c2ecf20Sopenharmony_ci			cmd->read_data_done : dr->read_data_done;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	read_data_left = (cmd->se_cmd.data_length - read_data_done);
3248c2ecf20Sopenharmony_ci	if (!read_data_left) {
3258c2ecf20Sopenharmony_ci		pr_err("ITT: 0x%08x read_data_left is zero!\n",
3268c2ecf20Sopenharmony_ci				cmd->init_task_tag);
3278c2ecf20Sopenharmony_ci		return dr;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL);
3318c2ecf20Sopenharmony_ci	if (!pdu)
3328c2ecf20Sopenharmony_ci		return dr;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {
3358c2ecf20Sopenharmony_ci		pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
3368c2ecf20Sopenharmony_ci		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
3378c2ecf20Sopenharmony_ci			pdu->flags |= ISCSI_FLAG_DATA_ACK;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		next_burst_len = 0;
3408c2ecf20Sopenharmony_ci	} else {
3418c2ecf20Sopenharmony_ci		if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) <
3428c2ecf20Sopenharmony_ci		     conn->sess->sess_ops->MaxBurstLength)
3438c2ecf20Sopenharmony_ci			next_burst_len += pdu->length;
3448c2ecf20Sopenharmony_ci		else {
3458c2ecf20Sopenharmony_ci			pdu->flags |= ISCSI_FLAG_CMD_FINAL;
3468c2ecf20Sopenharmony_ci			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
3478c2ecf20Sopenharmony_ci				pdu->flags |= ISCSI_FLAG_DATA_ACK;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci			next_burst_len = 0;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
3548c2ecf20Sopenharmony_ci	if (!dr->recovery) {
3558c2ecf20Sopenharmony_ci		cmd->next_burst_len = next_burst_len;
3568c2ecf20Sopenharmony_ci		cmd->read_data_done += pdu->length;
3578c2ecf20Sopenharmony_ci	} else {
3588c2ecf20Sopenharmony_ci		dr->next_burst_len = next_burst_len;
3598c2ecf20Sopenharmony_ci		dr->read_data_done += pdu->length;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	datain->flags = pdu->flags;
3638c2ecf20Sopenharmony_ci	datain->length = pdu->length;
3648c2ecf20Sopenharmony_ci	datain->offset = pdu->offset;
3658c2ecf20Sopenharmony_ci	datain->data_sn = pdu->data_sn;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (!dr->recovery) {
3688c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_DATA_STATUS)
3698c2ecf20Sopenharmony_ci			dr->dr_complete = DATAIN_COMPLETE_NORMAL;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci		return dr;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (!dr->runlength) {
3758c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
3768c2ecf20Sopenharmony_ci			dr->dr_complete =
3778c2ecf20Sopenharmony_ci			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
3788c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
3798c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_CONNECTION_RECOVERY;
3808c2ecf20Sopenharmony_ci		}
3818c2ecf20Sopenharmony_ci	} else {
3828c2ecf20Sopenharmony_ci		if ((dr->begrun + dr->runlength) == dr->data_sn) {
3838c2ecf20Sopenharmony_ci			dr->dr_complete =
3848c2ecf20Sopenharmony_ci			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
3858c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
3868c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_CONNECTION_RECOVERY;
3878c2ecf20Sopenharmony_ci		}
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	return dr;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci/*
3948c2ecf20Sopenharmony_ci *	For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No.
3958c2ecf20Sopenharmony_ci */
3968c2ecf20Sopenharmony_cistatic struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
3978c2ecf20Sopenharmony_ci	struct iscsi_cmd *cmd,
3988c2ecf20Sopenharmony_ci	struct iscsi_datain *datain)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	u32 read_data_done, read_data_left, seq_send_order;
4018c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = cmd->conn;
4028c2ecf20Sopenharmony_ci	struct iscsi_datain_req *dr;
4038c2ecf20Sopenharmony_ci	struct iscsi_pdu *pdu;
4048c2ecf20Sopenharmony_ci	struct iscsi_seq *seq = NULL;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	dr = iscsit_get_datain_req(cmd);
4078c2ecf20Sopenharmony_ci	if (!dr)
4088c2ecf20Sopenharmony_ci		return NULL;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (dr->recovery && dr->generate_recovery_values) {
4118c2ecf20Sopenharmony_ci		if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
4128c2ecf20Sopenharmony_ci					cmd, dr) < 0)
4138c2ecf20Sopenharmony_ci			return NULL;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		dr->generate_recovery_values = 0;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	read_data_done = (!dr->recovery) ?
4198c2ecf20Sopenharmony_ci			cmd->read_data_done : dr->read_data_done;
4208c2ecf20Sopenharmony_ci	seq_send_order = (!dr->recovery) ?
4218c2ecf20Sopenharmony_ci			cmd->seq_send_order : dr->seq_send_order;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	read_data_left = (cmd->se_cmd.data_length - read_data_done);
4248c2ecf20Sopenharmony_ci	if (!read_data_left) {
4258c2ecf20Sopenharmony_ci		pr_err("ITT: 0x%08x read_data_left is zero!\n",
4268c2ecf20Sopenharmony_ci				cmd->init_task_tag);
4278c2ecf20Sopenharmony_ci		return NULL;
4288c2ecf20Sopenharmony_ci	}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
4318c2ecf20Sopenharmony_ci	if (!seq)
4328c2ecf20Sopenharmony_ci		return NULL;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	seq->sent = 1;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (!dr->recovery && !seq->next_burst_len)
4378c2ecf20Sopenharmony_ci		seq->first_datasn = cmd->data_sn;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	pdu = iscsit_get_pdu_holder_for_seq(cmd, seq);
4408c2ecf20Sopenharmony_ci	if (!pdu)
4418c2ecf20Sopenharmony_ci		return NULL;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	if (seq->pdu_send_order == seq->pdu_count) {
4448c2ecf20Sopenharmony_ci		pdu->flags |= ISCSI_FLAG_CMD_FINAL;
4458c2ecf20Sopenharmony_ci		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
4468c2ecf20Sopenharmony_ci			pdu->flags |= ISCSI_FLAG_DATA_ACK;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		seq->next_burst_len = 0;
4498c2ecf20Sopenharmony_ci		seq_send_order++;
4508c2ecf20Sopenharmony_ci	} else
4518c2ecf20Sopenharmony_ci		seq->next_burst_len += pdu->length;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if ((read_data_done + pdu->length) == cmd->se_cmd.data_length)
4548c2ecf20Sopenharmony_ci		pdu->flags |= ISCSI_FLAG_DATA_STATUS;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
4578c2ecf20Sopenharmony_ci	if (!dr->recovery) {
4588c2ecf20Sopenharmony_ci		cmd->seq_send_order = seq_send_order;
4598c2ecf20Sopenharmony_ci		cmd->read_data_done += pdu->length;
4608c2ecf20Sopenharmony_ci	} else {
4618c2ecf20Sopenharmony_ci		dr->seq_send_order = seq_send_order;
4628c2ecf20Sopenharmony_ci		dr->read_data_done += pdu->length;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	datain->flags = pdu->flags;
4668c2ecf20Sopenharmony_ci	datain->length = pdu->length;
4678c2ecf20Sopenharmony_ci	datain->offset = pdu->offset;
4688c2ecf20Sopenharmony_ci	datain->data_sn = pdu->data_sn;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	if (!dr->recovery) {
4718c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_CMD_FINAL)
4728c2ecf20Sopenharmony_ci			seq->last_datasn = datain->data_sn;
4738c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_DATA_STATUS)
4748c2ecf20Sopenharmony_ci			dr->dr_complete = DATAIN_COMPLETE_NORMAL;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		return dr;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (!dr->runlength) {
4808c2ecf20Sopenharmony_ci		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
4818c2ecf20Sopenharmony_ci			dr->dr_complete =
4828c2ecf20Sopenharmony_ci			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
4838c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
4848c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_CONNECTION_RECOVERY;
4858c2ecf20Sopenharmony_ci		}
4868c2ecf20Sopenharmony_ci	} else {
4878c2ecf20Sopenharmony_ci		if ((dr->begrun + dr->runlength) == dr->data_sn) {
4888c2ecf20Sopenharmony_ci			dr->dr_complete =
4898c2ecf20Sopenharmony_ci			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
4908c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
4918c2ecf20Sopenharmony_ci				DATAIN_COMPLETE_CONNECTION_RECOVERY;
4928c2ecf20Sopenharmony_ci		}
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return dr;
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistruct iscsi_datain_req *iscsit_get_datain_values(
4998c2ecf20Sopenharmony_ci	struct iscsi_cmd *cmd,
5008c2ecf20Sopenharmony_ci	struct iscsi_datain *datain)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = cmd->conn;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	if (conn->sess->sess_ops->DataSequenceInOrder &&
5058c2ecf20Sopenharmony_ci	    conn->sess->sess_ops->DataPDUInOrder)
5068c2ecf20Sopenharmony_ci		return iscsit_set_datain_values_yes_and_yes(cmd, datain);
5078c2ecf20Sopenharmony_ci	else if (!conn->sess->sess_ops->DataSequenceInOrder &&
5088c2ecf20Sopenharmony_ci		  conn->sess->sess_ops->DataPDUInOrder)
5098c2ecf20Sopenharmony_ci		return iscsit_set_datain_values_no_and_yes(cmd, datain);
5108c2ecf20Sopenharmony_ci	else if (conn->sess->sess_ops->DataSequenceInOrder &&
5118c2ecf20Sopenharmony_ci		 !conn->sess->sess_ops->DataPDUInOrder)
5128c2ecf20Sopenharmony_ci		return iscsit_set_datain_values_yes_and_no(cmd, datain);
5138c2ecf20Sopenharmony_ci	else if (!conn->sess->sess_ops->DataSequenceInOrder &&
5148c2ecf20Sopenharmony_ci		   !conn->sess->sess_ops->DataPDUInOrder)
5158c2ecf20Sopenharmony_ci		return iscsit_set_datain_values_no_and_no(cmd, datain);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	return NULL;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iscsit_get_datain_values);
520