162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/******************************************************************************* 362306a36Sopenharmony_ci * This file contains the iSCSI Target DataIN value generation functions. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (c) Copyright 2007-2013 Datera, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci ******************************************************************************/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <scsi/iscsi_proto.h> 1362306a36Sopenharmony_ci#include <target/iscsi/iscsi_target_core.h> 1462306a36Sopenharmony_ci#include "iscsi_target_seq_pdu_list.h" 1562306a36Sopenharmony_ci#include "iscsi_target_erl1.h" 1662306a36Sopenharmony_ci#include "iscsi_target_util.h" 1762306a36Sopenharmony_ci#include "iscsi_target.h" 1862306a36Sopenharmony_ci#include "iscsi_target_datain_values.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct iscsi_datain_req *iscsit_allocate_datain_req(void) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct iscsi_datain_req *dr; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC); 2562306a36Sopenharmony_ci if (!dr) { 2662306a36Sopenharmony_ci pr_err("Unable to allocate memory for" 2762306a36Sopenharmony_ci " struct iscsi_datain_req\n"); 2862306a36Sopenharmony_ci return NULL; 2962306a36Sopenharmony_ci } 3062306a36Sopenharmony_ci INIT_LIST_HEAD(&dr->cmd_datain_node); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci return dr; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_civoid iscsit_attach_datain_req(struct iscsit_cmd *cmd, struct iscsi_datain_req *dr) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci spin_lock(&cmd->datain_lock); 3862306a36Sopenharmony_ci list_add_tail(&dr->cmd_datain_node, &cmd->datain_list); 3962306a36Sopenharmony_ci spin_unlock(&cmd->datain_lock); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_civoid iscsit_free_datain_req(struct iscsit_cmd *cmd, struct iscsi_datain_req *dr) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci spin_lock(&cmd->datain_lock); 4562306a36Sopenharmony_ci list_del(&dr->cmd_datain_node); 4662306a36Sopenharmony_ci spin_unlock(&cmd->datain_lock); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci kmem_cache_free(lio_dr_cache, dr); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_civoid iscsit_free_all_datain_reqs(struct iscsit_cmd *cmd) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct iscsi_datain_req *dr, *dr_tmp; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci spin_lock(&cmd->datain_lock); 5662306a36Sopenharmony_ci list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) { 5762306a36Sopenharmony_ci list_del(&dr->cmd_datain_node); 5862306a36Sopenharmony_ci kmem_cache_free(lio_dr_cache, dr); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci spin_unlock(&cmd->datain_lock); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct iscsi_datain_req *iscsit_get_datain_req(struct iscsit_cmd *cmd) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci if (list_empty(&cmd->datain_list)) { 6662306a36Sopenharmony_ci pr_err("cmd->datain_list is empty for ITT:" 6762306a36Sopenharmony_ci " 0x%08x\n", cmd->init_task_tag); 6862306a36Sopenharmony_ci return NULL; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return list_first_entry(&cmd->datain_list, struct iscsi_datain_req, 7262306a36Sopenharmony_ci cmd_datain_node); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes. 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_cistatic struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes( 7962306a36Sopenharmony_ci struct iscsit_cmd *cmd, 8062306a36Sopenharmony_ci struct iscsi_datain *datain) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci u32 next_burst_len, read_data_done, read_data_left; 8362306a36Sopenharmony_ci struct iscsit_conn *conn = cmd->conn; 8462306a36Sopenharmony_ci struct iscsi_datain_req *dr; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci dr = iscsit_get_datain_req(cmd); 8762306a36Sopenharmony_ci if (!dr) 8862306a36Sopenharmony_ci return NULL; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (dr->recovery && dr->generate_recovery_values) { 9162306a36Sopenharmony_ci if (iscsit_create_recovery_datain_values_datasequenceinorder_yes( 9262306a36Sopenharmony_ci cmd, dr) < 0) 9362306a36Sopenharmony_ci return NULL; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci dr->generate_recovery_values = 0; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci next_burst_len = (!dr->recovery) ? 9962306a36Sopenharmony_ci cmd->next_burst_len : dr->next_burst_len; 10062306a36Sopenharmony_ci read_data_done = (!dr->recovery) ? 10162306a36Sopenharmony_ci cmd->read_data_done : dr->read_data_done; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci read_data_left = (cmd->se_cmd.data_length - read_data_done); 10462306a36Sopenharmony_ci if (!read_data_left) { 10562306a36Sopenharmony_ci pr_err("ITT: 0x%08x read_data_left is zero!\n", 10662306a36Sopenharmony_ci cmd->init_task_tag); 10762306a36Sopenharmony_ci return NULL; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) && 11162306a36Sopenharmony_ci (read_data_left <= (conn->sess->sess_ops->MaxBurstLength - 11262306a36Sopenharmony_ci next_burst_len))) { 11362306a36Sopenharmony_ci datain->length = read_data_left; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS); 11662306a36Sopenharmony_ci if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 11762306a36Sopenharmony_ci datain->flags |= ISCSI_FLAG_DATA_ACK; 11862306a36Sopenharmony_ci } else { 11962306a36Sopenharmony_ci if ((next_burst_len + 12062306a36Sopenharmony_ci conn->conn_ops->MaxRecvDataSegmentLength) < 12162306a36Sopenharmony_ci conn->sess->sess_ops->MaxBurstLength) { 12262306a36Sopenharmony_ci datain->length = 12362306a36Sopenharmony_ci conn->conn_ops->MaxRecvDataSegmentLength; 12462306a36Sopenharmony_ci next_burst_len += datain->length; 12562306a36Sopenharmony_ci } else { 12662306a36Sopenharmony_ci datain->length = (conn->sess->sess_ops->MaxBurstLength - 12762306a36Sopenharmony_ci next_burst_len); 12862306a36Sopenharmony_ci next_burst_len = 0; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci datain->flags |= ISCSI_FLAG_CMD_FINAL; 13162306a36Sopenharmony_ci if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 13262306a36Sopenharmony_ci datain->flags |= ISCSI_FLAG_DATA_ACK; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; 13762306a36Sopenharmony_ci datain->offset = read_data_done; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (!dr->recovery) { 14062306a36Sopenharmony_ci cmd->next_burst_len = next_burst_len; 14162306a36Sopenharmony_ci cmd->read_data_done += datain->length; 14262306a36Sopenharmony_ci } else { 14362306a36Sopenharmony_ci dr->next_burst_len = next_burst_len; 14462306a36Sopenharmony_ci dr->read_data_done += datain->length; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (!dr->recovery) { 14862306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_DATA_STATUS) 14962306a36Sopenharmony_ci dr->dr_complete = DATAIN_COMPLETE_NORMAL; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return dr; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (!dr->runlength) { 15562306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_DATA_STATUS) { 15662306a36Sopenharmony_ci dr->dr_complete = 15762306a36Sopenharmony_ci (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 15862306a36Sopenharmony_ci DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 15962306a36Sopenharmony_ci DATAIN_COMPLETE_CONNECTION_RECOVERY; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci if ((dr->begrun + dr->runlength) == dr->data_sn) { 16362306a36Sopenharmony_ci dr->dr_complete = 16462306a36Sopenharmony_ci (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 16562306a36Sopenharmony_ci DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 16662306a36Sopenharmony_ci DATAIN_COMPLETE_CONNECTION_RECOVERY; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return dr; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* 17462306a36Sopenharmony_ci * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_cistatic struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes( 17762306a36Sopenharmony_ci struct iscsit_cmd *cmd, 17862306a36Sopenharmony_ci struct iscsi_datain *datain) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci u32 offset, read_data_done, read_data_left, seq_send_order; 18162306a36Sopenharmony_ci struct iscsit_conn *conn = cmd->conn; 18262306a36Sopenharmony_ci struct iscsi_datain_req *dr; 18362306a36Sopenharmony_ci struct iscsi_seq *seq; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci dr = iscsit_get_datain_req(cmd); 18662306a36Sopenharmony_ci if (!dr) 18762306a36Sopenharmony_ci return NULL; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (dr->recovery && dr->generate_recovery_values) { 19062306a36Sopenharmony_ci if (iscsit_create_recovery_datain_values_datasequenceinorder_no( 19162306a36Sopenharmony_ci cmd, dr) < 0) 19262306a36Sopenharmony_ci return NULL; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci dr->generate_recovery_values = 0; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci read_data_done = (!dr->recovery) ? 19862306a36Sopenharmony_ci cmd->read_data_done : dr->read_data_done; 19962306a36Sopenharmony_ci seq_send_order = (!dr->recovery) ? 20062306a36Sopenharmony_ci cmd->seq_send_order : dr->seq_send_order; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci read_data_left = (cmd->se_cmd.data_length - read_data_done); 20362306a36Sopenharmony_ci if (!read_data_left) { 20462306a36Sopenharmony_ci pr_err("ITT: 0x%08x read_data_left is zero!\n", 20562306a36Sopenharmony_ci cmd->init_task_tag); 20662306a36Sopenharmony_ci return NULL; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order); 21062306a36Sopenharmony_ci if (!seq) 21162306a36Sopenharmony_ci return NULL; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci seq->sent = 1; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (!dr->recovery && !seq->next_burst_len) 21662306a36Sopenharmony_ci seq->first_datasn = cmd->data_sn; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci offset = (seq->offset + seq->next_burst_len); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= 22162306a36Sopenharmony_ci cmd->se_cmd.data_length) { 22262306a36Sopenharmony_ci datain->length = (cmd->se_cmd.data_length - offset); 22362306a36Sopenharmony_ci datain->offset = offset; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci datain->flags |= ISCSI_FLAG_CMD_FINAL; 22662306a36Sopenharmony_ci if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 22762306a36Sopenharmony_ci datain->flags |= ISCSI_FLAG_DATA_ACK; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci seq->next_burst_len = 0; 23062306a36Sopenharmony_ci seq_send_order++; 23162306a36Sopenharmony_ci } else { 23262306a36Sopenharmony_ci if ((seq->next_burst_len + 23362306a36Sopenharmony_ci conn->conn_ops->MaxRecvDataSegmentLength) < 23462306a36Sopenharmony_ci conn->sess->sess_ops->MaxBurstLength) { 23562306a36Sopenharmony_ci datain->length = 23662306a36Sopenharmony_ci conn->conn_ops->MaxRecvDataSegmentLength; 23762306a36Sopenharmony_ci datain->offset = (seq->offset + seq->next_burst_len); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci seq->next_burst_len += datain->length; 24062306a36Sopenharmony_ci } else { 24162306a36Sopenharmony_ci datain->length = (conn->sess->sess_ops->MaxBurstLength - 24262306a36Sopenharmony_ci seq->next_burst_len); 24362306a36Sopenharmony_ci datain->offset = (seq->offset + seq->next_burst_len); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci datain->flags |= ISCSI_FLAG_CMD_FINAL; 24662306a36Sopenharmony_ci if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 24762306a36Sopenharmony_ci datain->flags |= ISCSI_FLAG_DATA_ACK; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci seq->next_burst_len = 0; 25062306a36Sopenharmony_ci seq_send_order++; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if ((read_data_done + datain->length) == cmd->se_cmd.data_length) 25562306a36Sopenharmony_ci datain->flags |= ISCSI_FLAG_DATA_STATUS; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; 25862306a36Sopenharmony_ci if (!dr->recovery) { 25962306a36Sopenharmony_ci cmd->seq_send_order = seq_send_order; 26062306a36Sopenharmony_ci cmd->read_data_done += datain->length; 26162306a36Sopenharmony_ci } else { 26262306a36Sopenharmony_ci dr->seq_send_order = seq_send_order; 26362306a36Sopenharmony_ci dr->read_data_done += datain->length; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!dr->recovery) { 26762306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_CMD_FINAL) 26862306a36Sopenharmony_ci seq->last_datasn = datain->data_sn; 26962306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_DATA_STATUS) 27062306a36Sopenharmony_ci dr->dr_complete = DATAIN_COMPLETE_NORMAL; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return dr; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (!dr->runlength) { 27662306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_DATA_STATUS) { 27762306a36Sopenharmony_ci dr->dr_complete = 27862306a36Sopenharmony_ci (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 27962306a36Sopenharmony_ci DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 28062306a36Sopenharmony_ci DATAIN_COMPLETE_CONNECTION_RECOVERY; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci } else { 28362306a36Sopenharmony_ci if ((dr->begrun + dr->runlength) == dr->data_sn) { 28462306a36Sopenharmony_ci dr->dr_complete = 28562306a36Sopenharmony_ci (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 28662306a36Sopenharmony_ci DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 28762306a36Sopenharmony_ci DATAIN_COMPLETE_CONNECTION_RECOVERY; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return dr; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* 29562306a36Sopenharmony_ci * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cistatic struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no( 29862306a36Sopenharmony_ci struct iscsit_cmd *cmd, 29962306a36Sopenharmony_ci struct iscsi_datain *datain) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci u32 next_burst_len, read_data_done, read_data_left; 30262306a36Sopenharmony_ci struct iscsit_conn *conn = cmd->conn; 30362306a36Sopenharmony_ci struct iscsi_datain_req *dr; 30462306a36Sopenharmony_ci struct iscsi_pdu *pdu; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci dr = iscsit_get_datain_req(cmd); 30762306a36Sopenharmony_ci if (!dr) 30862306a36Sopenharmony_ci return NULL; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (dr->recovery && dr->generate_recovery_values) { 31162306a36Sopenharmony_ci if (iscsit_create_recovery_datain_values_datasequenceinorder_yes( 31262306a36Sopenharmony_ci cmd, dr) < 0) 31362306a36Sopenharmony_ci return NULL; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci dr->generate_recovery_values = 0; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci next_burst_len = (!dr->recovery) ? 31962306a36Sopenharmony_ci cmd->next_burst_len : dr->next_burst_len; 32062306a36Sopenharmony_ci read_data_done = (!dr->recovery) ? 32162306a36Sopenharmony_ci cmd->read_data_done : dr->read_data_done; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci read_data_left = (cmd->se_cmd.data_length - read_data_done); 32462306a36Sopenharmony_ci if (!read_data_left) { 32562306a36Sopenharmony_ci pr_err("ITT: 0x%08x read_data_left is zero!\n", 32662306a36Sopenharmony_ci cmd->init_task_tag); 32762306a36Sopenharmony_ci return dr; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL); 33162306a36Sopenharmony_ci if (!pdu) 33262306a36Sopenharmony_ci return dr; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) { 33562306a36Sopenharmony_ci pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS); 33662306a36Sopenharmony_ci if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 33762306a36Sopenharmony_ci pdu->flags |= ISCSI_FLAG_DATA_ACK; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci next_burst_len = 0; 34062306a36Sopenharmony_ci } else { 34162306a36Sopenharmony_ci if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) < 34262306a36Sopenharmony_ci conn->sess->sess_ops->MaxBurstLength) 34362306a36Sopenharmony_ci next_burst_len += pdu->length; 34462306a36Sopenharmony_ci else { 34562306a36Sopenharmony_ci pdu->flags |= ISCSI_FLAG_CMD_FINAL; 34662306a36Sopenharmony_ci if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 34762306a36Sopenharmony_ci pdu->flags |= ISCSI_FLAG_DATA_ACK; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci next_burst_len = 0; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; 35462306a36Sopenharmony_ci if (!dr->recovery) { 35562306a36Sopenharmony_ci cmd->next_burst_len = next_burst_len; 35662306a36Sopenharmony_ci cmd->read_data_done += pdu->length; 35762306a36Sopenharmony_ci } else { 35862306a36Sopenharmony_ci dr->next_burst_len = next_burst_len; 35962306a36Sopenharmony_ci dr->read_data_done += pdu->length; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci datain->flags = pdu->flags; 36362306a36Sopenharmony_ci datain->length = pdu->length; 36462306a36Sopenharmony_ci datain->offset = pdu->offset; 36562306a36Sopenharmony_ci datain->data_sn = pdu->data_sn; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (!dr->recovery) { 36862306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_DATA_STATUS) 36962306a36Sopenharmony_ci dr->dr_complete = DATAIN_COMPLETE_NORMAL; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return dr; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (!dr->runlength) { 37562306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_DATA_STATUS) { 37662306a36Sopenharmony_ci dr->dr_complete = 37762306a36Sopenharmony_ci (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 37862306a36Sopenharmony_ci DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 37962306a36Sopenharmony_ci DATAIN_COMPLETE_CONNECTION_RECOVERY; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci } else { 38262306a36Sopenharmony_ci if ((dr->begrun + dr->runlength) == dr->data_sn) { 38362306a36Sopenharmony_ci dr->dr_complete = 38462306a36Sopenharmony_ci (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 38562306a36Sopenharmony_ci DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 38662306a36Sopenharmony_ci DATAIN_COMPLETE_CONNECTION_RECOVERY; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return dr; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/* 39462306a36Sopenharmony_ci * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No. 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_cistatic struct iscsi_datain_req *iscsit_set_datain_values_no_and_no( 39762306a36Sopenharmony_ci struct iscsit_cmd *cmd, 39862306a36Sopenharmony_ci struct iscsi_datain *datain) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci u32 read_data_done, read_data_left, seq_send_order; 40162306a36Sopenharmony_ci struct iscsit_conn *conn = cmd->conn; 40262306a36Sopenharmony_ci struct iscsi_datain_req *dr; 40362306a36Sopenharmony_ci struct iscsi_pdu *pdu; 40462306a36Sopenharmony_ci struct iscsi_seq *seq = NULL; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci dr = iscsit_get_datain_req(cmd); 40762306a36Sopenharmony_ci if (!dr) 40862306a36Sopenharmony_ci return NULL; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (dr->recovery && dr->generate_recovery_values) { 41162306a36Sopenharmony_ci if (iscsit_create_recovery_datain_values_datasequenceinorder_no( 41262306a36Sopenharmony_ci cmd, dr) < 0) 41362306a36Sopenharmony_ci return NULL; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci dr->generate_recovery_values = 0; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci read_data_done = (!dr->recovery) ? 41962306a36Sopenharmony_ci cmd->read_data_done : dr->read_data_done; 42062306a36Sopenharmony_ci seq_send_order = (!dr->recovery) ? 42162306a36Sopenharmony_ci cmd->seq_send_order : dr->seq_send_order; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci read_data_left = (cmd->se_cmd.data_length - read_data_done); 42462306a36Sopenharmony_ci if (!read_data_left) { 42562306a36Sopenharmony_ci pr_err("ITT: 0x%08x read_data_left is zero!\n", 42662306a36Sopenharmony_ci cmd->init_task_tag); 42762306a36Sopenharmony_ci return NULL; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order); 43162306a36Sopenharmony_ci if (!seq) 43262306a36Sopenharmony_ci return NULL; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci seq->sent = 1; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (!dr->recovery && !seq->next_burst_len) 43762306a36Sopenharmony_ci seq->first_datasn = cmd->data_sn; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci pdu = iscsit_get_pdu_holder_for_seq(cmd, seq); 44062306a36Sopenharmony_ci if (!pdu) 44162306a36Sopenharmony_ci return NULL; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (seq->pdu_send_order == seq->pdu_count) { 44462306a36Sopenharmony_ci pdu->flags |= ISCSI_FLAG_CMD_FINAL; 44562306a36Sopenharmony_ci if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 44662306a36Sopenharmony_ci pdu->flags |= ISCSI_FLAG_DATA_ACK; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci seq->next_burst_len = 0; 44962306a36Sopenharmony_ci seq_send_order++; 45062306a36Sopenharmony_ci } else 45162306a36Sopenharmony_ci seq->next_burst_len += pdu->length; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) 45462306a36Sopenharmony_ci pdu->flags |= ISCSI_FLAG_DATA_STATUS; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; 45762306a36Sopenharmony_ci if (!dr->recovery) { 45862306a36Sopenharmony_ci cmd->seq_send_order = seq_send_order; 45962306a36Sopenharmony_ci cmd->read_data_done += pdu->length; 46062306a36Sopenharmony_ci } else { 46162306a36Sopenharmony_ci dr->seq_send_order = seq_send_order; 46262306a36Sopenharmony_ci dr->read_data_done += pdu->length; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci datain->flags = pdu->flags; 46662306a36Sopenharmony_ci datain->length = pdu->length; 46762306a36Sopenharmony_ci datain->offset = pdu->offset; 46862306a36Sopenharmony_ci datain->data_sn = pdu->data_sn; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (!dr->recovery) { 47162306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_CMD_FINAL) 47262306a36Sopenharmony_ci seq->last_datasn = datain->data_sn; 47362306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_DATA_STATUS) 47462306a36Sopenharmony_ci dr->dr_complete = DATAIN_COMPLETE_NORMAL; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return dr; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (!dr->runlength) { 48062306a36Sopenharmony_ci if (datain->flags & ISCSI_FLAG_DATA_STATUS) { 48162306a36Sopenharmony_ci dr->dr_complete = 48262306a36Sopenharmony_ci (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 48362306a36Sopenharmony_ci DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 48462306a36Sopenharmony_ci DATAIN_COMPLETE_CONNECTION_RECOVERY; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci } else { 48762306a36Sopenharmony_ci if ((dr->begrun + dr->runlength) == dr->data_sn) { 48862306a36Sopenharmony_ci dr->dr_complete = 48962306a36Sopenharmony_ci (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 49062306a36Sopenharmony_ci DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 49162306a36Sopenharmony_ci DATAIN_COMPLETE_CONNECTION_RECOVERY; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return dr; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistruct iscsi_datain_req *iscsit_get_datain_values( 49962306a36Sopenharmony_ci struct iscsit_cmd *cmd, 50062306a36Sopenharmony_ci struct iscsi_datain *datain) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct iscsit_conn *conn = cmd->conn; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (conn->sess->sess_ops->DataSequenceInOrder && 50562306a36Sopenharmony_ci conn->sess->sess_ops->DataPDUInOrder) 50662306a36Sopenharmony_ci return iscsit_set_datain_values_yes_and_yes(cmd, datain); 50762306a36Sopenharmony_ci else if (!conn->sess->sess_ops->DataSequenceInOrder && 50862306a36Sopenharmony_ci conn->sess->sess_ops->DataPDUInOrder) 50962306a36Sopenharmony_ci return iscsit_set_datain_values_no_and_yes(cmd, datain); 51062306a36Sopenharmony_ci else if (conn->sess->sess_ops->DataSequenceInOrder && 51162306a36Sopenharmony_ci !conn->sess->sess_ops->DataPDUInOrder) 51262306a36Sopenharmony_ci return iscsit_set_datain_values_yes_and_no(cmd, datain); 51362306a36Sopenharmony_ci else if (!conn->sess->sess_ops->DataSequenceInOrder && 51462306a36Sopenharmony_ci !conn->sess->sess_ops->DataPDUInOrder) 51562306a36Sopenharmony_ci return iscsit_set_datain_values_no_and_no(cmd, datain); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return NULL; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ciEXPORT_SYMBOL(iscsit_get_datain_values); 520