brintos

brintos / linux-shallow public Read only

0
0
Text · 13.8 KiB · 2d44781 Raw
520 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*******************************************************************************3 * This file contains the iSCSI Target DataIN value generation functions.4 *5 * (c) Copyright 2007-2013 Datera, Inc.6 *7 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>8 *9 ******************************************************************************/10 11#include <linux/slab.h>12#include <scsi/iscsi_proto.h>13#include <target/iscsi/iscsi_target_core.h>14#include "iscsi_target_seq_pdu_list.h"15#include "iscsi_target_erl1.h"16#include "iscsi_target_util.h"17#include "iscsi_target.h"18#include "iscsi_target_datain_values.h"19 20struct iscsi_datain_req *iscsit_allocate_datain_req(void)21{22	struct iscsi_datain_req *dr;23 24	dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC);25	if (!dr) {26		pr_err("Unable to allocate memory for"27				" struct iscsi_datain_req\n");28		return NULL;29	}30	INIT_LIST_HEAD(&dr->cmd_datain_node);31 32	return dr;33}34 35void iscsit_attach_datain_req(struct iscsit_cmd *cmd, struct iscsi_datain_req *dr)36{37	spin_lock(&cmd->datain_lock);38	list_add_tail(&dr->cmd_datain_node, &cmd->datain_list);39	spin_unlock(&cmd->datain_lock);40}41 42void iscsit_free_datain_req(struct iscsit_cmd *cmd, struct iscsi_datain_req *dr)43{44	spin_lock(&cmd->datain_lock);45	list_del(&dr->cmd_datain_node);46	spin_unlock(&cmd->datain_lock);47 48	kmem_cache_free(lio_dr_cache, dr);49}50 51void iscsit_free_all_datain_reqs(struct iscsit_cmd *cmd)52{53	struct iscsi_datain_req *dr, *dr_tmp;54 55	spin_lock(&cmd->datain_lock);56	list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) {57		list_del(&dr->cmd_datain_node);58		kmem_cache_free(lio_dr_cache, dr);59	}60	spin_unlock(&cmd->datain_lock);61}62 63struct iscsi_datain_req *iscsit_get_datain_req(struct iscsit_cmd *cmd)64{65	if (list_empty(&cmd->datain_list)) {66		pr_err("cmd->datain_list is empty for ITT:"67			" 0x%08x\n", cmd->init_task_tag);68		return NULL;69	}70 71	return list_first_entry(&cmd->datain_list, struct iscsi_datain_req,72				cmd_datain_node);73}74 75/*76 *	For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.77 */78static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(79	struct iscsit_cmd *cmd,80	struct iscsi_datain *datain)81{82	u32 next_burst_len, read_data_done, read_data_left;83	struct iscsit_conn *conn = cmd->conn;84	struct iscsi_datain_req *dr;85 86	dr = iscsit_get_datain_req(cmd);87	if (!dr)88		return NULL;89 90	if (dr->recovery && dr->generate_recovery_values) {91		if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(92					cmd, dr) < 0)93			return NULL;94 95		dr->generate_recovery_values = 0;96	}97 98	next_burst_len = (!dr->recovery) ?99			cmd->next_burst_len : dr->next_burst_len;100	read_data_done = (!dr->recovery) ?101			cmd->read_data_done : dr->read_data_done;102 103	read_data_left = (cmd->se_cmd.data_length - read_data_done);104	if (!read_data_left) {105		pr_err("ITT: 0x%08x read_data_left is zero!\n",106				cmd->init_task_tag);107		return NULL;108	}109 110	if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) &&111	    (read_data_left <= (conn->sess->sess_ops->MaxBurstLength -112	     next_burst_len))) {113		datain->length = read_data_left;114 115		datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);116		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)117			datain->flags |= ISCSI_FLAG_DATA_ACK;118	} else {119		if ((next_burst_len +120		     conn->conn_ops->MaxRecvDataSegmentLength) <121		     conn->sess->sess_ops->MaxBurstLength) {122			datain->length =123				conn->conn_ops->MaxRecvDataSegmentLength;124			next_burst_len += datain->length;125		} else {126			datain->length = (conn->sess->sess_ops->MaxBurstLength -127					  next_burst_len);128			next_burst_len = 0;129 130			datain->flags |= ISCSI_FLAG_CMD_FINAL;131			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)132				datain->flags |= ISCSI_FLAG_DATA_ACK;133		}134	}135 136	datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;137	datain->offset = read_data_done;138 139	if (!dr->recovery) {140		cmd->next_burst_len = next_burst_len;141		cmd->read_data_done += datain->length;142	} else {143		dr->next_burst_len = next_burst_len;144		dr->read_data_done += datain->length;145	}146 147	if (!dr->recovery) {148		if (datain->flags & ISCSI_FLAG_DATA_STATUS)149			dr->dr_complete = DATAIN_COMPLETE_NORMAL;150 151		return dr;152	}153 154	if (!dr->runlength) {155		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {156			dr->dr_complete =157			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?158				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :159				DATAIN_COMPLETE_CONNECTION_RECOVERY;160		}161	} else {162		if ((dr->begrun + dr->runlength) == dr->data_sn) {163			dr->dr_complete =164			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?165				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :166				DATAIN_COMPLETE_CONNECTION_RECOVERY;167		}168	}169 170	return dr;171}172 173/*174 *	For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes.175 */176static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(177	struct iscsit_cmd *cmd,178	struct iscsi_datain *datain)179{180	u32 offset, read_data_done, read_data_left, seq_send_order;181	struct iscsit_conn *conn = cmd->conn;182	struct iscsi_datain_req *dr;183	struct iscsi_seq *seq;184 185	dr = iscsit_get_datain_req(cmd);186	if (!dr)187		return NULL;188 189	if (dr->recovery && dr->generate_recovery_values) {190		if (iscsit_create_recovery_datain_values_datasequenceinorder_no(191					cmd, dr) < 0)192			return NULL;193 194		dr->generate_recovery_values = 0;195	}196 197	read_data_done = (!dr->recovery) ?198			cmd->read_data_done : dr->read_data_done;199	seq_send_order = (!dr->recovery) ?200			cmd->seq_send_order : dr->seq_send_order;201 202	read_data_left = (cmd->se_cmd.data_length - read_data_done);203	if (!read_data_left) {204		pr_err("ITT: 0x%08x read_data_left is zero!\n",205				cmd->init_task_tag);206		return NULL;207	}208 209	seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);210	if (!seq)211		return NULL;212 213	seq->sent = 1;214 215	if (!dr->recovery && !seq->next_burst_len)216		seq->first_datasn = cmd->data_sn;217 218	offset = (seq->offset + seq->next_burst_len);219 220	if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=221	     cmd->se_cmd.data_length) {222		datain->length = (cmd->se_cmd.data_length - offset);223		datain->offset = offset;224 225		datain->flags |= ISCSI_FLAG_CMD_FINAL;226		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)227			datain->flags |= ISCSI_FLAG_DATA_ACK;228 229		seq->next_burst_len = 0;230		seq_send_order++;231	} else {232		if ((seq->next_burst_len +233		     conn->conn_ops->MaxRecvDataSegmentLength) <234		     conn->sess->sess_ops->MaxBurstLength) {235			datain->length =236				conn->conn_ops->MaxRecvDataSegmentLength;237			datain->offset = (seq->offset + seq->next_burst_len);238 239			seq->next_burst_len += datain->length;240		} else {241			datain->length = (conn->sess->sess_ops->MaxBurstLength -242					  seq->next_burst_len);243			datain->offset = (seq->offset + seq->next_burst_len);244 245			datain->flags |= ISCSI_FLAG_CMD_FINAL;246			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)247				datain->flags |= ISCSI_FLAG_DATA_ACK;248 249			seq->next_burst_len = 0;250			seq_send_order++;251		}252	}253 254	if ((read_data_done + datain->length) == cmd->se_cmd.data_length)255		datain->flags |= ISCSI_FLAG_DATA_STATUS;256 257	datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;258	if (!dr->recovery) {259		cmd->seq_send_order = seq_send_order;260		cmd->read_data_done += datain->length;261	} else {262		dr->seq_send_order = seq_send_order;263		dr->read_data_done += datain->length;264	}265 266	if (!dr->recovery) {267		if (datain->flags & ISCSI_FLAG_CMD_FINAL)268			seq->last_datasn = datain->data_sn;269		if (datain->flags & ISCSI_FLAG_DATA_STATUS)270			dr->dr_complete = DATAIN_COMPLETE_NORMAL;271 272		return dr;273	}274 275	if (!dr->runlength) {276		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {277			dr->dr_complete =278			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?279				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :280				DATAIN_COMPLETE_CONNECTION_RECOVERY;281		}282	} else {283		if ((dr->begrun + dr->runlength) == dr->data_sn) {284			dr->dr_complete =285			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?286				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :287				DATAIN_COMPLETE_CONNECTION_RECOVERY;288		}289	}290 291	return dr;292}293 294/*295 *	For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No.296 */297static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(298	struct iscsit_cmd *cmd,299	struct iscsi_datain *datain)300{301	u32 next_burst_len, read_data_done, read_data_left;302	struct iscsit_conn *conn = cmd->conn;303	struct iscsi_datain_req *dr;304	struct iscsi_pdu *pdu;305 306	dr = iscsit_get_datain_req(cmd);307	if (!dr)308		return NULL;309 310	if (dr->recovery && dr->generate_recovery_values) {311		if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(312					cmd, dr) < 0)313			return NULL;314 315		dr->generate_recovery_values = 0;316	}317 318	next_burst_len = (!dr->recovery) ?319			cmd->next_burst_len : dr->next_burst_len;320	read_data_done = (!dr->recovery) ?321			cmd->read_data_done : dr->read_data_done;322 323	read_data_left = (cmd->se_cmd.data_length - read_data_done);324	if (!read_data_left) {325		pr_err("ITT: 0x%08x read_data_left is zero!\n",326				cmd->init_task_tag);327		return dr;328	}329 330	pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL);331	if (!pdu)332		return dr;333 334	if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {335		pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);336		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)337			pdu->flags |= ISCSI_FLAG_DATA_ACK;338 339		next_burst_len = 0;340	} else {341		if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) <342		     conn->sess->sess_ops->MaxBurstLength)343			next_burst_len += pdu->length;344		else {345			pdu->flags |= ISCSI_FLAG_CMD_FINAL;346			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)347				pdu->flags |= ISCSI_FLAG_DATA_ACK;348 349			next_burst_len = 0;350		}351	}352 353	pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;354	if (!dr->recovery) {355		cmd->next_burst_len = next_burst_len;356		cmd->read_data_done += pdu->length;357	} else {358		dr->next_burst_len = next_burst_len;359		dr->read_data_done += pdu->length;360	}361 362	datain->flags = pdu->flags;363	datain->length = pdu->length;364	datain->offset = pdu->offset;365	datain->data_sn = pdu->data_sn;366 367	if (!dr->recovery) {368		if (datain->flags & ISCSI_FLAG_DATA_STATUS)369			dr->dr_complete = DATAIN_COMPLETE_NORMAL;370 371		return dr;372	}373 374	if (!dr->runlength) {375		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {376			dr->dr_complete =377			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?378				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :379				DATAIN_COMPLETE_CONNECTION_RECOVERY;380		}381	} else {382		if ((dr->begrun + dr->runlength) == dr->data_sn) {383			dr->dr_complete =384			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?385				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :386				DATAIN_COMPLETE_CONNECTION_RECOVERY;387		}388	}389 390	return dr;391}392 393/*394 *	For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No.395 */396static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(397	struct iscsit_cmd *cmd,398	struct iscsi_datain *datain)399{400	u32 read_data_done, read_data_left, seq_send_order;401	struct iscsit_conn *conn = cmd->conn;402	struct iscsi_datain_req *dr;403	struct iscsi_pdu *pdu;404	struct iscsi_seq *seq = NULL;405 406	dr = iscsit_get_datain_req(cmd);407	if (!dr)408		return NULL;409 410	if (dr->recovery && dr->generate_recovery_values) {411		if (iscsit_create_recovery_datain_values_datasequenceinorder_no(412					cmd, dr) < 0)413			return NULL;414 415		dr->generate_recovery_values = 0;416	}417 418	read_data_done = (!dr->recovery) ?419			cmd->read_data_done : dr->read_data_done;420	seq_send_order = (!dr->recovery) ?421			cmd->seq_send_order : dr->seq_send_order;422 423	read_data_left = (cmd->se_cmd.data_length - read_data_done);424	if (!read_data_left) {425		pr_err("ITT: 0x%08x read_data_left is zero!\n",426				cmd->init_task_tag);427		return NULL;428	}429 430	seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);431	if (!seq)432		return NULL;433 434	seq->sent = 1;435 436	if (!dr->recovery && !seq->next_burst_len)437		seq->first_datasn = cmd->data_sn;438 439	pdu = iscsit_get_pdu_holder_for_seq(cmd, seq);440	if (!pdu)441		return NULL;442 443	if (seq->pdu_send_order == seq->pdu_count) {444		pdu->flags |= ISCSI_FLAG_CMD_FINAL;445		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)446			pdu->flags |= ISCSI_FLAG_DATA_ACK;447 448		seq->next_burst_len = 0;449		seq_send_order++;450	} else451		seq->next_burst_len += pdu->length;452 453	if ((read_data_done + pdu->length) == cmd->se_cmd.data_length)454		pdu->flags |= ISCSI_FLAG_DATA_STATUS;455 456	pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;457	if (!dr->recovery) {458		cmd->seq_send_order = seq_send_order;459		cmd->read_data_done += pdu->length;460	} else {461		dr->seq_send_order = seq_send_order;462		dr->read_data_done += pdu->length;463	}464 465	datain->flags = pdu->flags;466	datain->length = pdu->length;467	datain->offset = pdu->offset;468	datain->data_sn = pdu->data_sn;469 470	if (!dr->recovery) {471		if (datain->flags & ISCSI_FLAG_CMD_FINAL)472			seq->last_datasn = datain->data_sn;473		if (datain->flags & ISCSI_FLAG_DATA_STATUS)474			dr->dr_complete = DATAIN_COMPLETE_NORMAL;475 476		return dr;477	}478 479	if (!dr->runlength) {480		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {481			dr->dr_complete =482			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?483				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :484				DATAIN_COMPLETE_CONNECTION_RECOVERY;485		}486	} else {487		if ((dr->begrun + dr->runlength) == dr->data_sn) {488			dr->dr_complete =489			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?490				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :491				DATAIN_COMPLETE_CONNECTION_RECOVERY;492		}493	}494 495	return dr;496}497 498struct iscsi_datain_req *iscsit_get_datain_values(499	struct iscsit_cmd *cmd,500	struct iscsi_datain *datain)501{502	struct iscsit_conn *conn = cmd->conn;503 504	if (conn->sess->sess_ops->DataSequenceInOrder &&505	    conn->sess->sess_ops->DataPDUInOrder)506		return iscsit_set_datain_values_yes_and_yes(cmd, datain);507	else if (!conn->sess->sess_ops->DataSequenceInOrder &&508		  conn->sess->sess_ops->DataPDUInOrder)509		return iscsit_set_datain_values_no_and_yes(cmd, datain);510	else if (conn->sess->sess_ops->DataSequenceInOrder &&511		 !conn->sess->sess_ops->DataPDUInOrder)512		return iscsit_set_datain_values_yes_and_no(cmd, datain);513	else if (!conn->sess->sess_ops->DataSequenceInOrder &&514		   !conn->sess->sess_ops->DataPDUInOrder)515		return iscsit_set_datain_values_no_and_no(cmd, datain);516 517	return NULL;518}519EXPORT_SYMBOL(iscsit_get_datain_values);520