| /******************************************************************************* | 
 |  * This file contains the iSCSI Target DataIN value generation functions. | 
 |  * | 
 |  * (c) Copyright 2007-2013 Datera, Inc. | 
 |  * | 
 |  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or modify | 
 |  * it under the terms of the GNU General Public License as published by | 
 |  * the Free Software Foundation; either version 2 of the License, or | 
 |  * (at your option) any later version. | 
 |  * | 
 |  * This program is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |  * GNU General Public License for more details. | 
 |  ******************************************************************************/ | 
 |  | 
 | #include <scsi/iscsi_proto.h> | 
 |  | 
 | #include <target/iscsi/iscsi_target_core.h> | 
 | #include "iscsi_target_seq_pdu_list.h" | 
 | #include "iscsi_target_erl1.h" | 
 | #include "iscsi_target_util.h" | 
 | #include "iscsi_target.h" | 
 | #include "iscsi_target_datain_values.h" | 
 |  | 
 | struct iscsi_datain_req *iscsit_allocate_datain_req(void) | 
 | { | 
 | 	struct iscsi_datain_req *dr; | 
 |  | 
 | 	dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC); | 
 | 	if (!dr) { | 
 | 		pr_err("Unable to allocate memory for" | 
 | 				" struct iscsi_datain_req\n"); | 
 | 		return NULL; | 
 | 	} | 
 | 	INIT_LIST_HEAD(&dr->cmd_datain_node); | 
 |  | 
 | 	return dr; | 
 | } | 
 |  | 
 | void iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr) | 
 | { | 
 | 	spin_lock(&cmd->datain_lock); | 
 | 	list_add_tail(&dr->cmd_datain_node, &cmd->datain_list); | 
 | 	spin_unlock(&cmd->datain_lock); | 
 | } | 
 |  | 
 | void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr) | 
 | { | 
 | 	spin_lock(&cmd->datain_lock); | 
 | 	list_del(&dr->cmd_datain_node); | 
 | 	spin_unlock(&cmd->datain_lock); | 
 |  | 
 | 	kmem_cache_free(lio_dr_cache, dr); | 
 | } | 
 |  | 
 | void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd) | 
 | { | 
 | 	struct iscsi_datain_req *dr, *dr_tmp; | 
 |  | 
 | 	spin_lock(&cmd->datain_lock); | 
 | 	list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) { | 
 | 		list_del(&dr->cmd_datain_node); | 
 | 		kmem_cache_free(lio_dr_cache, dr); | 
 | 	} | 
 | 	spin_unlock(&cmd->datain_lock); | 
 | } | 
 |  | 
 | struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd) | 
 | { | 
 | 	if (list_empty(&cmd->datain_list)) { | 
 | 		pr_err("cmd->datain_list is empty for ITT:" | 
 | 			" 0x%08x\n", cmd->init_task_tag); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	return list_first_entry(&cmd->datain_list, struct iscsi_datain_req, | 
 | 				cmd_datain_node); | 
 | } | 
 |  | 
 | /* | 
 |  *	For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes. | 
 |  */ | 
 | static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes( | 
 | 	struct iscsi_cmd *cmd, | 
 | 	struct iscsi_datain *datain) | 
 | { | 
 | 	u32 next_burst_len, read_data_done, read_data_left; | 
 | 	struct iscsi_conn *conn = cmd->conn; | 
 | 	struct iscsi_datain_req *dr; | 
 |  | 
 | 	dr = iscsit_get_datain_req(cmd); | 
 | 	if (!dr) | 
 | 		return NULL; | 
 |  | 
 | 	if (dr->recovery && dr->generate_recovery_values) { | 
 | 		if (iscsit_create_recovery_datain_values_datasequenceinorder_yes( | 
 | 					cmd, dr) < 0) | 
 | 			return NULL; | 
 |  | 
 | 		dr->generate_recovery_values = 0; | 
 | 	} | 
 |  | 
 | 	next_burst_len = (!dr->recovery) ? | 
 | 			cmd->next_burst_len : dr->next_burst_len; | 
 | 	read_data_done = (!dr->recovery) ? | 
 | 			cmd->read_data_done : dr->read_data_done; | 
 |  | 
 | 	read_data_left = (cmd->se_cmd.data_length - read_data_done); | 
 | 	if (!read_data_left) { | 
 | 		pr_err("ITT: 0x%08x read_data_left is zero!\n", | 
 | 				cmd->init_task_tag); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) && | 
 | 	    (read_data_left <= (conn->sess->sess_ops->MaxBurstLength - | 
 | 	     next_burst_len))) { | 
 | 		datain->length = read_data_left; | 
 |  | 
 | 		datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS); | 
 | 		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) | 
 | 			datain->flags |= ISCSI_FLAG_DATA_ACK; | 
 | 	} else { | 
 | 		if ((next_burst_len + | 
 | 		     conn->conn_ops->MaxRecvDataSegmentLength) < | 
 | 		     conn->sess->sess_ops->MaxBurstLength) { | 
 | 			datain->length = | 
 | 				conn->conn_ops->MaxRecvDataSegmentLength; | 
 | 			next_burst_len += datain->length; | 
 | 		} else { | 
 | 			datain->length = (conn->sess->sess_ops->MaxBurstLength - | 
 | 					  next_burst_len); | 
 | 			next_burst_len = 0; | 
 |  | 
 | 			datain->flags |= ISCSI_FLAG_CMD_FINAL; | 
 | 			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) | 
 | 				datain->flags |= ISCSI_FLAG_DATA_ACK; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; | 
 | 	datain->offset = read_data_done; | 
 |  | 
 | 	if (!dr->recovery) { | 
 | 		cmd->next_burst_len = next_burst_len; | 
 | 		cmd->read_data_done += datain->length; | 
 | 	} else { | 
 | 		dr->next_burst_len = next_burst_len; | 
 | 		dr->read_data_done += datain->length; | 
 | 	} | 
 |  | 
 | 	if (!dr->recovery) { | 
 | 		if (datain->flags & ISCSI_FLAG_DATA_STATUS) | 
 | 			dr->dr_complete = DATAIN_COMPLETE_NORMAL; | 
 |  | 
 | 		return dr; | 
 | 	} | 
 |  | 
 | 	if (!dr->runlength) { | 
 | 		if (datain->flags & ISCSI_FLAG_DATA_STATUS) { | 
 | 			dr->dr_complete = | 
 | 			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? | 
 | 				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : | 
 | 				DATAIN_COMPLETE_CONNECTION_RECOVERY; | 
 | 		} | 
 | 	} else { | 
 | 		if ((dr->begrun + dr->runlength) == dr->data_sn) { | 
 | 			dr->dr_complete = | 
 | 			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? | 
 | 				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : | 
 | 				DATAIN_COMPLETE_CONNECTION_RECOVERY; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return dr; | 
 | } | 
 |  | 
 | /* | 
 |  *	For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes. | 
 |  */ | 
 | static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes( | 
 | 	struct iscsi_cmd *cmd, | 
 | 	struct iscsi_datain *datain) | 
 | { | 
 | 	u32 offset, read_data_done, read_data_left, seq_send_order; | 
 | 	struct iscsi_conn *conn = cmd->conn; | 
 | 	struct iscsi_datain_req *dr; | 
 | 	struct iscsi_seq *seq; | 
 |  | 
 | 	dr = iscsit_get_datain_req(cmd); | 
 | 	if (!dr) | 
 | 		return NULL; | 
 |  | 
 | 	if (dr->recovery && dr->generate_recovery_values) { | 
 | 		if (iscsit_create_recovery_datain_values_datasequenceinorder_no( | 
 | 					cmd, dr) < 0) | 
 | 			return NULL; | 
 |  | 
 | 		dr->generate_recovery_values = 0; | 
 | 	} | 
 |  | 
 | 	read_data_done = (!dr->recovery) ? | 
 | 			cmd->read_data_done : dr->read_data_done; | 
 | 	seq_send_order = (!dr->recovery) ? | 
 | 			cmd->seq_send_order : dr->seq_send_order; | 
 |  | 
 | 	read_data_left = (cmd->se_cmd.data_length - read_data_done); | 
 | 	if (!read_data_left) { | 
 | 		pr_err("ITT: 0x%08x read_data_left is zero!\n", | 
 | 				cmd->init_task_tag); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order); | 
 | 	if (!seq) | 
 | 		return NULL; | 
 |  | 
 | 	seq->sent = 1; | 
 |  | 
 | 	if (!dr->recovery && !seq->next_burst_len) | 
 | 		seq->first_datasn = cmd->data_sn; | 
 |  | 
 | 	offset = (seq->offset + seq->next_burst_len); | 
 |  | 
 | 	if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= | 
 | 	     cmd->se_cmd.data_length) { | 
 | 		datain->length = (cmd->se_cmd.data_length - offset); | 
 | 		datain->offset = offset; | 
 |  | 
 | 		datain->flags |= ISCSI_FLAG_CMD_FINAL; | 
 | 		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) | 
 | 			datain->flags |= ISCSI_FLAG_DATA_ACK; | 
 |  | 
 | 		seq->next_burst_len = 0; | 
 | 		seq_send_order++; | 
 | 	} else { | 
 | 		if ((seq->next_burst_len + | 
 | 		     conn->conn_ops->MaxRecvDataSegmentLength) < | 
 | 		     conn->sess->sess_ops->MaxBurstLength) { | 
 | 			datain->length = | 
 | 				conn->conn_ops->MaxRecvDataSegmentLength; | 
 | 			datain->offset = (seq->offset + seq->next_burst_len); | 
 |  | 
 | 			seq->next_burst_len += datain->length; | 
 | 		} else { | 
 | 			datain->length = (conn->sess->sess_ops->MaxBurstLength - | 
 | 					  seq->next_burst_len); | 
 | 			datain->offset = (seq->offset + seq->next_burst_len); | 
 |  | 
 | 			datain->flags |= ISCSI_FLAG_CMD_FINAL; | 
 | 			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) | 
 | 				datain->flags |= ISCSI_FLAG_DATA_ACK; | 
 |  | 
 | 			seq->next_burst_len = 0; | 
 | 			seq_send_order++; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if ((read_data_done + datain->length) == cmd->se_cmd.data_length) | 
 | 		datain->flags |= ISCSI_FLAG_DATA_STATUS; | 
 |  | 
 | 	datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; | 
 | 	if (!dr->recovery) { | 
 | 		cmd->seq_send_order = seq_send_order; | 
 | 		cmd->read_data_done += datain->length; | 
 | 	} else { | 
 | 		dr->seq_send_order = seq_send_order; | 
 | 		dr->read_data_done += datain->length; | 
 | 	} | 
 |  | 
 | 	if (!dr->recovery) { | 
 | 		if (datain->flags & ISCSI_FLAG_CMD_FINAL) | 
 | 			seq->last_datasn = datain->data_sn; | 
 | 		if (datain->flags & ISCSI_FLAG_DATA_STATUS) | 
 | 			dr->dr_complete = DATAIN_COMPLETE_NORMAL; | 
 |  | 
 | 		return dr; | 
 | 	} | 
 |  | 
 | 	if (!dr->runlength) { | 
 | 		if (datain->flags & ISCSI_FLAG_DATA_STATUS) { | 
 | 			dr->dr_complete = | 
 | 			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? | 
 | 				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : | 
 | 				DATAIN_COMPLETE_CONNECTION_RECOVERY; | 
 | 		} | 
 | 	} else { | 
 | 		if ((dr->begrun + dr->runlength) == dr->data_sn) { | 
 | 			dr->dr_complete = | 
 | 			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? | 
 | 				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : | 
 | 				DATAIN_COMPLETE_CONNECTION_RECOVERY; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return dr; | 
 | } | 
 |  | 
 | /* | 
 |  *	For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No. | 
 |  */ | 
 | static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no( | 
 | 	struct iscsi_cmd *cmd, | 
 | 	struct iscsi_datain *datain) | 
 | { | 
 | 	u32 next_burst_len, read_data_done, read_data_left; | 
 | 	struct iscsi_conn *conn = cmd->conn; | 
 | 	struct iscsi_datain_req *dr; | 
 | 	struct iscsi_pdu *pdu; | 
 |  | 
 | 	dr = iscsit_get_datain_req(cmd); | 
 | 	if (!dr) | 
 | 		return NULL; | 
 |  | 
 | 	if (dr->recovery && dr->generate_recovery_values) { | 
 | 		if (iscsit_create_recovery_datain_values_datasequenceinorder_yes( | 
 | 					cmd, dr) < 0) | 
 | 			return NULL; | 
 |  | 
 | 		dr->generate_recovery_values = 0; | 
 | 	} | 
 |  | 
 | 	next_burst_len = (!dr->recovery) ? | 
 | 			cmd->next_burst_len : dr->next_burst_len; | 
 | 	read_data_done = (!dr->recovery) ? | 
 | 			cmd->read_data_done : dr->read_data_done; | 
 |  | 
 | 	read_data_left = (cmd->se_cmd.data_length - read_data_done); | 
 | 	if (!read_data_left) { | 
 | 		pr_err("ITT: 0x%08x read_data_left is zero!\n", | 
 | 				cmd->init_task_tag); | 
 | 		return dr; | 
 | 	} | 
 |  | 
 | 	pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL); | 
 | 	if (!pdu) | 
 | 		return dr; | 
 |  | 
 | 	if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) { | 
 | 		pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS); | 
 | 		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) | 
 | 			pdu->flags |= ISCSI_FLAG_DATA_ACK; | 
 |  | 
 | 		next_burst_len = 0; | 
 | 	} else { | 
 | 		if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) < | 
 | 		     conn->sess->sess_ops->MaxBurstLength) | 
 | 			next_burst_len += pdu->length; | 
 | 		else { | 
 | 			pdu->flags |= ISCSI_FLAG_CMD_FINAL; | 
 | 			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) | 
 | 				pdu->flags |= ISCSI_FLAG_DATA_ACK; | 
 |  | 
 | 			next_burst_len = 0; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; | 
 | 	if (!dr->recovery) { | 
 | 		cmd->next_burst_len = next_burst_len; | 
 | 		cmd->read_data_done += pdu->length; | 
 | 	} else { | 
 | 		dr->next_burst_len = next_burst_len; | 
 | 		dr->read_data_done += pdu->length; | 
 | 	} | 
 |  | 
 | 	datain->flags = pdu->flags; | 
 | 	datain->length = pdu->length; | 
 | 	datain->offset = pdu->offset; | 
 | 	datain->data_sn = pdu->data_sn; | 
 |  | 
 | 	if (!dr->recovery) { | 
 | 		if (datain->flags & ISCSI_FLAG_DATA_STATUS) | 
 | 			dr->dr_complete = DATAIN_COMPLETE_NORMAL; | 
 |  | 
 | 		return dr; | 
 | 	} | 
 |  | 
 | 	if (!dr->runlength) { | 
 | 		if (datain->flags & ISCSI_FLAG_DATA_STATUS) { | 
 | 			dr->dr_complete = | 
 | 			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? | 
 | 				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : | 
 | 				DATAIN_COMPLETE_CONNECTION_RECOVERY; | 
 | 		} | 
 | 	} else { | 
 | 		if ((dr->begrun + dr->runlength) == dr->data_sn) { | 
 | 			dr->dr_complete = | 
 | 			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? | 
 | 				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : | 
 | 				DATAIN_COMPLETE_CONNECTION_RECOVERY; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return dr; | 
 | } | 
 |  | 
 | /* | 
 |  *	For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No. | 
 |  */ | 
 | static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no( | 
 | 	struct iscsi_cmd *cmd, | 
 | 	struct iscsi_datain *datain) | 
 | { | 
 | 	u32 read_data_done, read_data_left, seq_send_order; | 
 | 	struct iscsi_conn *conn = cmd->conn; | 
 | 	struct iscsi_datain_req *dr; | 
 | 	struct iscsi_pdu *pdu; | 
 | 	struct iscsi_seq *seq = NULL; | 
 |  | 
 | 	dr = iscsit_get_datain_req(cmd); | 
 | 	if (!dr) | 
 | 		return NULL; | 
 |  | 
 | 	if (dr->recovery && dr->generate_recovery_values) { | 
 | 		if (iscsit_create_recovery_datain_values_datasequenceinorder_no( | 
 | 					cmd, dr) < 0) | 
 | 			return NULL; | 
 |  | 
 | 		dr->generate_recovery_values = 0; | 
 | 	} | 
 |  | 
 | 	read_data_done = (!dr->recovery) ? | 
 | 			cmd->read_data_done : dr->read_data_done; | 
 | 	seq_send_order = (!dr->recovery) ? | 
 | 			cmd->seq_send_order : dr->seq_send_order; | 
 |  | 
 | 	read_data_left = (cmd->se_cmd.data_length - read_data_done); | 
 | 	if (!read_data_left) { | 
 | 		pr_err("ITT: 0x%08x read_data_left is zero!\n", | 
 | 				cmd->init_task_tag); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order); | 
 | 	if (!seq) | 
 | 		return NULL; | 
 |  | 
 | 	seq->sent = 1; | 
 |  | 
 | 	if (!dr->recovery && !seq->next_burst_len) | 
 | 		seq->first_datasn = cmd->data_sn; | 
 |  | 
 | 	pdu = iscsit_get_pdu_holder_for_seq(cmd, seq); | 
 | 	if (!pdu) | 
 | 		return NULL; | 
 |  | 
 | 	if (seq->pdu_send_order == seq->pdu_count) { | 
 | 		pdu->flags |= ISCSI_FLAG_CMD_FINAL; | 
 | 		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) | 
 | 			pdu->flags |= ISCSI_FLAG_DATA_ACK; | 
 |  | 
 | 		seq->next_burst_len = 0; | 
 | 		seq_send_order++; | 
 | 	} else | 
 | 		seq->next_burst_len += pdu->length; | 
 |  | 
 | 	if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) | 
 | 		pdu->flags |= ISCSI_FLAG_DATA_STATUS; | 
 |  | 
 | 	pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; | 
 | 	if (!dr->recovery) { | 
 | 		cmd->seq_send_order = seq_send_order; | 
 | 		cmd->read_data_done += pdu->length; | 
 | 	} else { | 
 | 		dr->seq_send_order = seq_send_order; | 
 | 		dr->read_data_done += pdu->length; | 
 | 	} | 
 |  | 
 | 	datain->flags = pdu->flags; | 
 | 	datain->length = pdu->length; | 
 | 	datain->offset = pdu->offset; | 
 | 	datain->data_sn = pdu->data_sn; | 
 |  | 
 | 	if (!dr->recovery) { | 
 | 		if (datain->flags & ISCSI_FLAG_CMD_FINAL) | 
 | 			seq->last_datasn = datain->data_sn; | 
 | 		if (datain->flags & ISCSI_FLAG_DATA_STATUS) | 
 | 			dr->dr_complete = DATAIN_COMPLETE_NORMAL; | 
 |  | 
 | 		return dr; | 
 | 	} | 
 |  | 
 | 	if (!dr->runlength) { | 
 | 		if (datain->flags & ISCSI_FLAG_DATA_STATUS) { | 
 | 			dr->dr_complete = | 
 | 			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? | 
 | 				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : | 
 | 				DATAIN_COMPLETE_CONNECTION_RECOVERY; | 
 | 		} | 
 | 	} else { | 
 | 		if ((dr->begrun + dr->runlength) == dr->data_sn) { | 
 | 			dr->dr_complete = | 
 | 			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? | 
 | 				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : | 
 | 				DATAIN_COMPLETE_CONNECTION_RECOVERY; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return dr; | 
 | } | 
 |  | 
 | struct iscsi_datain_req *iscsit_get_datain_values( | 
 | 	struct iscsi_cmd *cmd, | 
 | 	struct iscsi_datain *datain) | 
 | { | 
 | 	struct iscsi_conn *conn = cmd->conn; | 
 |  | 
 | 	if (conn->sess->sess_ops->DataSequenceInOrder && | 
 | 	    conn->sess->sess_ops->DataPDUInOrder) | 
 | 		return iscsit_set_datain_values_yes_and_yes(cmd, datain); | 
 | 	else if (!conn->sess->sess_ops->DataSequenceInOrder && | 
 | 		  conn->sess->sess_ops->DataPDUInOrder) | 
 | 		return iscsit_set_datain_values_no_and_yes(cmd, datain); | 
 | 	else if (conn->sess->sess_ops->DataSequenceInOrder && | 
 | 		 !conn->sess->sess_ops->DataPDUInOrder) | 
 | 		return iscsit_set_datain_values_yes_and_no(cmd, datain); | 
 | 	else if (!conn->sess->sess_ops->DataSequenceInOrder && | 
 | 		   !conn->sess->sess_ops->DataPDUInOrder) | 
 | 		return iscsit_set_datain_values_no_and_no(cmd, datain); | 
 |  | 
 | 	return NULL; | 
 | } |