brintos

brintos / linux-shallow public Read only

0
0
Text · 26.0 KiB · 07e9cf4 Raw
937 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/******************************************************************************3 * This file contains error recovery level zero functions used by4 * the iSCSI Target driver.5 *6 * (c) Copyright 2007-2013 Datera, Inc.7 *8 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>9 *10 ******************************************************************************/11 12#include <linux/sched/signal.h>13 14#include <scsi/iscsi_proto.h>15#include <target/target_core_base.h>16#include <target/target_core_fabric.h>17 18#include <target/iscsi/iscsi_target_core.h>19#include "iscsi_target_seq_pdu_list.h"20#include "iscsi_target_erl0.h"21#include "iscsi_target_erl1.h"22#include "iscsi_target_erl2.h"23#include "iscsi_target_util.h"24#include "iscsi_target.h"25 26/*27 *	Used to set values in struct iscsit_cmd that iscsit_dataout_check_sequence()28 *	checks against to determine a PDU's Offset+Length is within the current29 *	DataOUT Sequence.  Used for DataSequenceInOrder=Yes only.30 */31void iscsit_set_dataout_sequence_values(32	struct iscsit_cmd *cmd)33{34	struct iscsit_conn *conn = cmd->conn;35	/*36	 * Still set seq_start_offset and seq_end_offset for Unsolicited37	 * DataOUT, even if DataSequenceInOrder=No.38	 */39	if (cmd->unsolicited_data) {40		cmd->seq_start_offset = cmd->write_data_done;41		cmd->seq_end_offset = min(cmd->se_cmd.data_length,42					conn->sess->sess_ops->FirstBurstLength);43		return;44	}45 46	if (!conn->sess->sess_ops->DataSequenceInOrder)47		return;48 49	if (!cmd->seq_start_offset && !cmd->seq_end_offset) {50		cmd->seq_start_offset = cmd->write_data_done;51		cmd->seq_end_offset = (cmd->se_cmd.data_length >52			conn->sess->sess_ops->MaxBurstLength) ?53			(cmd->write_data_done +54			conn->sess->sess_ops->MaxBurstLength) : cmd->se_cmd.data_length;55	} else {56		cmd->seq_start_offset = cmd->seq_end_offset;57		cmd->seq_end_offset = ((cmd->seq_end_offset +58			conn->sess->sess_ops->MaxBurstLength) >=59			cmd->se_cmd.data_length) ? cmd->se_cmd.data_length :60			(cmd->seq_end_offset +61			 conn->sess->sess_ops->MaxBurstLength);62	}63}64 65static int iscsit_dataout_within_command_recovery_check(66	struct iscsit_cmd *cmd,67	unsigned char *buf)68{69	struct iscsit_conn *conn = cmd->conn;70	struct iscsi_data *hdr = (struct iscsi_data *) buf;71	u32 payload_length = ntoh24(hdr->dlength);72 73	/*74	 * We do the within-command recovery checks here as it is75	 * the first function called in iscsi_check_pre_dataout().76	 * Basically, if we are in within-command recovery and77	 * the PDU does not contain the offset the sequence needs,78	 * dump the payload.79	 *80	 * This only applies to DataPDUInOrder=Yes, for81	 * DataPDUInOrder=No we only re-request the failed PDU82	 * and check that all PDUs in a sequence are received83	 * upon end of sequence.84	 */85	if (conn->sess->sess_ops->DataSequenceInOrder) {86		if ((cmd->cmd_flags & ICF_WITHIN_COMMAND_RECOVERY) &&87		    cmd->write_data_done != be32_to_cpu(hdr->offset))88			goto dump;89 90		cmd->cmd_flags &= ~ICF_WITHIN_COMMAND_RECOVERY;91	} else {92		struct iscsi_seq *seq;93 94		seq = iscsit_get_seq_holder(cmd, be32_to_cpu(hdr->offset),95					    payload_length);96		if (!seq)97			return DATAOUT_CANNOT_RECOVER;98		/*99		 * Set the struct iscsi_seq pointer to reuse later.100		 */101		cmd->seq_ptr = seq;102 103		if (conn->sess->sess_ops->DataPDUInOrder) {104			if (seq->status ==105			    DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY &&106			   (seq->offset != be32_to_cpu(hdr->offset) ||107			    seq->data_sn != be32_to_cpu(hdr->datasn)))108				goto dump;109		} else {110			if (seq->status ==111			     DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY &&112			    seq->data_sn != be32_to_cpu(hdr->datasn))113				goto dump;114		}115 116		if (seq->status == DATAOUT_SEQUENCE_COMPLETE)117			goto dump;118 119		if (seq->status != DATAOUT_SEQUENCE_COMPLETE)120			seq->status = 0;121	}122 123	return DATAOUT_NORMAL;124 125dump:126	pr_err("Dumping DataOUT PDU Offset: %u Length: %d DataSN:"127		" 0x%08x\n", hdr->offset, payload_length, hdr->datasn);128	return iscsit_dump_data_payload(conn, payload_length, 1);129}130 131static int iscsit_dataout_check_unsolicited_sequence(132	struct iscsit_cmd *cmd,133	unsigned char *buf)134{135	u32 first_burst_len;136	struct iscsit_conn *conn = cmd->conn;137	struct iscsi_data *hdr = (struct iscsi_data *) buf;138	u32 payload_length = ntoh24(hdr->dlength);139 140 141	if ((be32_to_cpu(hdr->offset) < cmd->seq_start_offset) ||142	   ((be32_to_cpu(hdr->offset) + payload_length) > cmd->seq_end_offset)) {143		pr_err("Command ITT: 0x%08x with Offset: %u,"144		" Length: %u outside of Unsolicited Sequence %u:%u while"145		" DataSequenceInOrder=Yes.\n", cmd->init_task_tag,146		be32_to_cpu(hdr->offset), payload_length, cmd->seq_start_offset,147			cmd->seq_end_offset);148		return DATAOUT_CANNOT_RECOVER;149	}150 151	first_burst_len = (cmd->first_burst_len + payload_length);152 153	if (first_burst_len > conn->sess->sess_ops->FirstBurstLength) {154		pr_err("Total %u bytes exceeds FirstBurstLength: %u"155			" for this Unsolicited DataOut Burst.\n",156			first_burst_len, conn->sess->sess_ops->FirstBurstLength);157		transport_send_check_condition_and_sense(&cmd->se_cmd,158				TCM_INCORRECT_AMOUNT_OF_DATA, 0);159		return DATAOUT_CANNOT_RECOVER;160	}161 162	/*163	 * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity164	 * checks for the current Unsolicited DataOUT Sequence.165	 */166	if (hdr->flags & ISCSI_FLAG_CMD_FINAL) {167		/*168		 * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of169		 * sequence checks are handled in170		 * iscsit_dataout_datapduinorder_no_fbit().171		 */172		if (!conn->sess->sess_ops->DataPDUInOrder)173			goto out;174 175		if ((first_burst_len != cmd->se_cmd.data_length) &&176		    (first_burst_len != conn->sess->sess_ops->FirstBurstLength)) {177			pr_err("Unsolicited non-immediate data"178			" received %u does not equal FirstBurstLength: %u, and"179			" does not equal ExpXferLen %u.\n", first_burst_len,180				conn->sess->sess_ops->FirstBurstLength,181				cmd->se_cmd.data_length);182			transport_send_check_condition_and_sense(&cmd->se_cmd,183					TCM_INCORRECT_AMOUNT_OF_DATA, 0);184			return DATAOUT_CANNOT_RECOVER;185		}186	} else {187		if (first_burst_len == conn->sess->sess_ops->FirstBurstLength) {188			pr_err("Command ITT: 0x%08x reached"189			" FirstBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol"190				" error.\n", cmd->init_task_tag,191				conn->sess->sess_ops->FirstBurstLength);192			return DATAOUT_CANNOT_RECOVER;193		}194		if (first_burst_len == cmd->se_cmd.data_length) {195			pr_err("Command ITT: 0x%08x reached"196			" ExpXferLen: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol"197			" error.\n", cmd->init_task_tag, cmd->se_cmd.data_length);198			return DATAOUT_CANNOT_RECOVER;199		}200	}201 202out:203	return DATAOUT_NORMAL;204}205 206static int iscsit_dataout_check_sequence(207	struct iscsit_cmd *cmd,208	unsigned char *buf)209{210	u32 next_burst_len;211	struct iscsit_conn *conn = cmd->conn;212	struct iscsi_seq *seq = NULL;213	struct iscsi_data *hdr = (struct iscsi_data *) buf;214	u32 payload_length = ntoh24(hdr->dlength);215 216	/*217	 * For DataSequenceInOrder=Yes: Check that the offset and offset+length218	 * is within range as defined by iscsi_set_dataout_sequence_values().219	 *220	 * For DataSequenceInOrder=No: Check that an struct iscsi_seq exists for221	 * offset+length tuple.222	 */223	if (conn->sess->sess_ops->DataSequenceInOrder) {224		/*225		 * Due to possibility of recovery DataOUT sent by the initiator226		 * fullfilling an Recovery R2T, it's best to just dump the227		 * payload here, instead of erroring out.228		 */229		if ((be32_to_cpu(hdr->offset) < cmd->seq_start_offset) ||230		   ((be32_to_cpu(hdr->offset) + payload_length) > cmd->seq_end_offset)) {231			pr_err("Command ITT: 0x%08x with Offset: %u,"232			" Length: %u outside of Sequence %u:%u while"233			" DataSequenceInOrder=Yes.\n", cmd->init_task_tag,234			be32_to_cpu(hdr->offset), payload_length, cmd->seq_start_offset,235				cmd->seq_end_offset);236 237			if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)238				return DATAOUT_CANNOT_RECOVER;239			return DATAOUT_WITHIN_COMMAND_RECOVERY;240		}241 242		next_burst_len = (cmd->next_burst_len + payload_length);243	} else {244		seq = iscsit_get_seq_holder(cmd, be32_to_cpu(hdr->offset),245					    payload_length);246		if (!seq)247			return DATAOUT_CANNOT_RECOVER;248		/*249		 * Set the struct iscsi_seq pointer to reuse later.250		 */251		cmd->seq_ptr = seq;252 253		if (seq->status == DATAOUT_SEQUENCE_COMPLETE) {254			if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)255				return DATAOUT_CANNOT_RECOVER;256			return DATAOUT_WITHIN_COMMAND_RECOVERY;257		}258 259		next_burst_len = (seq->next_burst_len + payload_length);260	}261 262	if (next_burst_len > conn->sess->sess_ops->MaxBurstLength) {263		pr_err("Command ITT: 0x%08x, NextBurstLength: %u and"264			" Length: %u exceeds MaxBurstLength: %u. protocol"265			" error.\n", cmd->init_task_tag,266			(next_burst_len - payload_length),267			payload_length, conn->sess->sess_ops->MaxBurstLength);268		return DATAOUT_CANNOT_RECOVER;269	}270 271	/*272	 * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity273	 * checks for the current DataOUT Sequence.274	 */275	if (hdr->flags & ISCSI_FLAG_CMD_FINAL) {276		/*277		 * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of278		 * sequence checks are handled in279		 * iscsit_dataout_datapduinorder_no_fbit().280		 */281		if (!conn->sess->sess_ops->DataPDUInOrder)282			goto out;283 284		if (conn->sess->sess_ops->DataSequenceInOrder) {285			if ((next_burst_len <286			     conn->sess->sess_ops->MaxBurstLength) &&287			   ((cmd->write_data_done + payload_length) <288			     cmd->se_cmd.data_length)) {289				pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL"290				" before end of DataOUT sequence, protocol"291				" error.\n", cmd->init_task_tag);292				return DATAOUT_CANNOT_RECOVER;293			}294		} else {295			if (next_burst_len < seq->xfer_len) {296				pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL"297				" before end of DataOUT sequence, protocol"298				" error.\n", cmd->init_task_tag);299				return DATAOUT_CANNOT_RECOVER;300			}301		}302	} else {303		if (conn->sess->sess_ops->DataSequenceInOrder) {304			if (next_burst_len ==305					conn->sess->sess_ops->MaxBurstLength) {306				pr_err("Command ITT: 0x%08x reached"307				" MaxBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is"308				" not set, protocol error.", cmd->init_task_tag,309					conn->sess->sess_ops->MaxBurstLength);310				return DATAOUT_CANNOT_RECOVER;311			}312			if ((cmd->write_data_done + payload_length) ==313					cmd->se_cmd.data_length) {314				pr_err("Command ITT: 0x%08x reached"315				" last DataOUT PDU in sequence but ISCSI_FLAG_"316				"CMD_FINAL is not set, protocol error.\n",317					cmd->init_task_tag);318				return DATAOUT_CANNOT_RECOVER;319			}320		} else {321			if (next_burst_len == seq->xfer_len) {322				pr_err("Command ITT: 0x%08x reached"323				" last DataOUT PDU in sequence but ISCSI_FLAG_"324				"CMD_FINAL is not set, protocol error.\n",325					cmd->init_task_tag);326				return DATAOUT_CANNOT_RECOVER;327			}328		}329	}330 331out:332	return DATAOUT_NORMAL;333}334 335static int iscsit_dataout_check_datasn(336	struct iscsit_cmd *cmd,337	unsigned char *buf)338{339	u32 data_sn = 0;340	struct iscsit_conn *conn = cmd->conn;341	struct iscsi_data *hdr = (struct iscsi_data *) buf;342	u32 payload_length = ntoh24(hdr->dlength);343 344	/*345	 * Considering the target has no method of re-requesting DataOUT346	 * by DataSN, if we receieve a greater DataSN than expected we347	 * assume the functions for DataPDUInOrder=[Yes,No] below will348	 * handle it.349	 *350	 * If the DataSN is less than expected, dump the payload.351	 */352	if (conn->sess->sess_ops->DataSequenceInOrder)353		data_sn = cmd->data_sn;354	else {355		struct iscsi_seq *seq = cmd->seq_ptr;356		data_sn = seq->data_sn;357	}358 359	if (be32_to_cpu(hdr->datasn) > data_sn) {360		pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"361			" higher than expected 0x%08x.\n", cmd->init_task_tag,362				be32_to_cpu(hdr->datasn), data_sn);363		goto recover;364	} else if (be32_to_cpu(hdr->datasn) < data_sn) {365		pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"366			" lower than expected 0x%08x, discarding payload.\n",367			cmd->init_task_tag, be32_to_cpu(hdr->datasn), data_sn);368		goto dump;369	}370 371	return DATAOUT_NORMAL;372 373recover:374	if (!conn->sess->sess_ops->ErrorRecoveryLevel) {375		pr_err("Unable to perform within-command recovery"376				" while ERL=0.\n");377		return DATAOUT_CANNOT_RECOVER;378	}379dump:380	if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)381		return DATAOUT_CANNOT_RECOVER;382 383	return DATAOUT_WITHIN_COMMAND_RECOVERY;384}385 386static int iscsit_dataout_pre_datapduinorder_yes(387	struct iscsit_cmd *cmd,388	unsigned char *buf)389{390	int dump = 0, recovery = 0;391	struct iscsit_conn *conn = cmd->conn;392	struct iscsi_data *hdr = (struct iscsi_data *) buf;393	u32 payload_length = ntoh24(hdr->dlength);394 395	/*396	 * For DataSequenceInOrder=Yes: If the offset is greater than the global397	 * DataPDUInOrder=Yes offset counter in struct iscsit_cmd a protcol error has398	 * occurred and fail the connection.399	 *400	 * For DataSequenceInOrder=No: If the offset is greater than the per401	 * sequence DataPDUInOrder=Yes offset counter in struct iscsi_seq a protocol402	 * error has occurred and fail the connection.403	 */404	if (conn->sess->sess_ops->DataSequenceInOrder) {405		if (be32_to_cpu(hdr->offset) != cmd->write_data_done) {406			pr_err("Command ITT: 0x%08x, received offset"407			" %u different than expected %u.\n", cmd->init_task_tag,408				be32_to_cpu(hdr->offset), cmd->write_data_done);409			recovery = 1;410			goto recover;411		}412	} else {413		struct iscsi_seq *seq = cmd->seq_ptr;414 415		if (be32_to_cpu(hdr->offset) > seq->offset) {416			pr_err("Command ITT: 0x%08x, received offset"417			" %u greater than expected %u.\n", cmd->init_task_tag,418				be32_to_cpu(hdr->offset), seq->offset);419			recovery = 1;420			goto recover;421		} else if (be32_to_cpu(hdr->offset) < seq->offset) {422			pr_err("Command ITT: 0x%08x, received offset"423			" %u less than expected %u, discarding payload.\n",424				cmd->init_task_tag, be32_to_cpu(hdr->offset),425				seq->offset);426			dump = 1;427			goto dump;428		}429	}430 431	return DATAOUT_NORMAL;432 433recover:434	if (!conn->sess->sess_ops->ErrorRecoveryLevel) {435		pr_err("Unable to perform within-command recovery"436				" while ERL=0.\n");437		return DATAOUT_CANNOT_RECOVER;438	}439dump:440	if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)441		return DATAOUT_CANNOT_RECOVER;442 443	return (recovery) ? iscsit_recover_dataout_sequence(cmd,444		be32_to_cpu(hdr->offset), payload_length) :445	       (dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY : DATAOUT_NORMAL;446}447 448static int iscsit_dataout_pre_datapduinorder_no(449	struct iscsit_cmd *cmd,450	unsigned char *buf)451{452	struct iscsi_pdu *pdu;453	struct iscsi_data *hdr = (struct iscsi_data *) buf;454	u32 payload_length = ntoh24(hdr->dlength);455 456	pdu = iscsit_get_pdu_holder(cmd, be32_to_cpu(hdr->offset),457				    payload_length);458	if (!pdu)459		return DATAOUT_CANNOT_RECOVER;460 461	cmd->pdu_ptr = pdu;462 463	switch (pdu->status) {464	case ISCSI_PDU_NOT_RECEIVED:465	case ISCSI_PDU_CRC_FAILED:466	case ISCSI_PDU_TIMED_OUT:467		break;468	case ISCSI_PDU_RECEIVED_OK:469		pr_err("Command ITT: 0x%08x received already gotten"470			" Offset: %u, Length: %u\n", cmd->init_task_tag,471				be32_to_cpu(hdr->offset), payload_length);472		return iscsit_dump_data_payload(cmd->conn, payload_length, 1);473	default:474		return DATAOUT_CANNOT_RECOVER;475	}476 477	return DATAOUT_NORMAL;478}479 480static int iscsit_dataout_update_r2t(struct iscsit_cmd *cmd, u32 offset, u32 length)481{482	struct iscsi_r2t *r2t;483 484	if (cmd->unsolicited_data)485		return 0;486 487	r2t = iscsit_get_r2t_for_eos(cmd, offset, length);488	if (!r2t)489		return -1;490 491	spin_lock_bh(&cmd->r2t_lock);492	r2t->seq_complete = 1;493	cmd->outstanding_r2ts--;494	spin_unlock_bh(&cmd->r2t_lock);495 496	return 0;497}498 499static int iscsit_dataout_update_datapduinorder_no(500	struct iscsit_cmd *cmd,501	u32 data_sn,502	int f_bit)503{504	int ret = 0;505	struct iscsi_pdu *pdu = cmd->pdu_ptr;506 507	pdu->data_sn = data_sn;508 509	switch (pdu->status) {510	case ISCSI_PDU_NOT_RECEIVED:511		pdu->status = ISCSI_PDU_RECEIVED_OK;512		break;513	case ISCSI_PDU_CRC_FAILED:514		pdu->status = ISCSI_PDU_RECEIVED_OK;515		break;516	case ISCSI_PDU_TIMED_OUT:517		pdu->status = ISCSI_PDU_RECEIVED_OK;518		break;519	default:520		return DATAOUT_CANNOT_RECOVER;521	}522 523	if (f_bit) {524		ret = iscsit_dataout_datapduinorder_no_fbit(cmd, pdu);525		if (ret == DATAOUT_CANNOT_RECOVER)526			return ret;527	}528 529	return DATAOUT_NORMAL;530}531 532static int iscsit_dataout_post_crc_passed(533	struct iscsit_cmd *cmd,534	unsigned char *buf)535{536	int ret, send_r2t = 0;537	struct iscsit_conn *conn = cmd->conn;538	struct iscsi_seq *seq = NULL;539	struct iscsi_data *hdr = (struct iscsi_data *) buf;540	u32 payload_length = ntoh24(hdr->dlength);541 542	if (cmd->unsolicited_data) {543		if ((cmd->first_burst_len + payload_length) ==544		     conn->sess->sess_ops->FirstBurstLength) {545			if (iscsit_dataout_update_r2t(cmd, be32_to_cpu(hdr->offset),546					payload_length) < 0)547				return DATAOUT_CANNOT_RECOVER;548			send_r2t = 1;549		}550 551		if (!conn->sess->sess_ops->DataPDUInOrder) {552			ret = iscsit_dataout_update_datapduinorder_no(cmd,553				be32_to_cpu(hdr->datasn),554				(hdr->flags & ISCSI_FLAG_CMD_FINAL));555			if (ret == DATAOUT_CANNOT_RECOVER)556				return ret;557		}558 559		cmd->first_burst_len += payload_length;560 561		if (conn->sess->sess_ops->DataSequenceInOrder)562			cmd->data_sn++;563		else {564			seq = cmd->seq_ptr;565			seq->data_sn++;566			seq->offset += payload_length;567		}568 569		if (send_r2t) {570			if (seq)571				seq->status = DATAOUT_SEQUENCE_COMPLETE;572			cmd->first_burst_len = 0;573			cmd->unsolicited_data = 0;574		}575	} else {576		if (conn->sess->sess_ops->DataSequenceInOrder) {577			if ((cmd->next_burst_len + payload_length) ==578			     conn->sess->sess_ops->MaxBurstLength) {579				if (iscsit_dataout_update_r2t(cmd,580						be32_to_cpu(hdr->offset),581						payload_length) < 0)582					return DATAOUT_CANNOT_RECOVER;583				send_r2t = 1;584			}585 586			if (!conn->sess->sess_ops->DataPDUInOrder) {587				ret = iscsit_dataout_update_datapduinorder_no(588						cmd, be32_to_cpu(hdr->datasn),589						(hdr->flags & ISCSI_FLAG_CMD_FINAL));590				if (ret == DATAOUT_CANNOT_RECOVER)591					return ret;592			}593 594			cmd->next_burst_len += payload_length;595			cmd->data_sn++;596 597			if (send_r2t)598				cmd->next_burst_len = 0;599		} else {600			seq = cmd->seq_ptr;601 602			if ((seq->next_burst_len + payload_length) ==603			     seq->xfer_len) {604				if (iscsit_dataout_update_r2t(cmd,605						be32_to_cpu(hdr->offset),606						payload_length) < 0)607					return DATAOUT_CANNOT_RECOVER;608				send_r2t = 1;609			}610 611			if (!conn->sess->sess_ops->DataPDUInOrder) {612				ret = iscsit_dataout_update_datapduinorder_no(613						cmd, be32_to_cpu(hdr->datasn),614						(hdr->flags & ISCSI_FLAG_CMD_FINAL));615				if (ret == DATAOUT_CANNOT_RECOVER)616					return ret;617			}618 619			seq->data_sn++;620			seq->offset += payload_length;621			seq->next_burst_len += payload_length;622 623			if (send_r2t) {624				seq->next_burst_len = 0;625				seq->status = DATAOUT_SEQUENCE_COMPLETE;626			}627		}628	}629 630	if (send_r2t && conn->sess->sess_ops->DataSequenceInOrder)631		cmd->data_sn = 0;632 633	cmd->write_data_done += payload_length;634 635	if (cmd->write_data_done == cmd->se_cmd.data_length)636		return DATAOUT_SEND_TO_TRANSPORT;637	else if (send_r2t)638		return DATAOUT_SEND_R2T;639	else640		return DATAOUT_NORMAL;641}642 643static int iscsit_dataout_post_crc_failed(644	struct iscsit_cmd *cmd,645	unsigned char *buf)646{647	struct iscsit_conn *conn = cmd->conn;648	struct iscsi_pdu *pdu;649	struct iscsi_data *hdr = (struct iscsi_data *) buf;650	u32 payload_length = ntoh24(hdr->dlength);651 652	if (conn->sess->sess_ops->DataPDUInOrder)653		goto recover;654	/*655	 * The rest of this function is only called when DataPDUInOrder=No.656	 */657	pdu = cmd->pdu_ptr;658 659	switch (pdu->status) {660	case ISCSI_PDU_NOT_RECEIVED:661		pdu->status = ISCSI_PDU_CRC_FAILED;662		break;663	case ISCSI_PDU_CRC_FAILED:664		break;665	case ISCSI_PDU_TIMED_OUT:666		pdu->status = ISCSI_PDU_CRC_FAILED;667		break;668	default:669		return DATAOUT_CANNOT_RECOVER;670	}671 672recover:673	return iscsit_recover_dataout_sequence(cmd, be32_to_cpu(hdr->offset),674						payload_length);675}676 677/*678 *	Called from iscsit_handle_data_out() before DataOUT Payload is received679 *	and CRC computed.680 */681int iscsit_check_pre_dataout(682	struct iscsit_cmd *cmd,683	unsigned char *buf)684{685	int ret;686	struct iscsit_conn *conn = cmd->conn;687 688	ret = iscsit_dataout_within_command_recovery_check(cmd, buf);689	if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||690	    (ret == DATAOUT_CANNOT_RECOVER))691		return ret;692 693	ret = iscsit_dataout_check_datasn(cmd, buf);694	if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||695	    (ret == DATAOUT_CANNOT_RECOVER))696		return ret;697 698	if (cmd->unsolicited_data) {699		ret = iscsit_dataout_check_unsolicited_sequence(cmd, buf);700		if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||701		    (ret == DATAOUT_CANNOT_RECOVER))702			return ret;703	} else {704		ret = iscsit_dataout_check_sequence(cmd, buf);705		if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||706		    (ret == DATAOUT_CANNOT_RECOVER))707			return ret;708	}709 710	return (conn->sess->sess_ops->DataPDUInOrder) ?711		iscsit_dataout_pre_datapduinorder_yes(cmd, buf) :712		iscsit_dataout_pre_datapduinorder_no(cmd, buf);713}714 715/*716 *	Called from iscsit_handle_data_out() after DataOUT Payload is received717 *	and CRC computed.718 */719int iscsit_check_post_dataout(720	struct iscsit_cmd *cmd,721	unsigned char *buf,722	u8 data_crc_failed)723{724	struct iscsit_conn *conn = cmd->conn;725 726	cmd->dataout_timeout_retries = 0;727 728	if (!data_crc_failed)729		return iscsit_dataout_post_crc_passed(cmd, buf);730	else {731		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {732			pr_err("Unable to recover from DataOUT CRC"733				" failure while ERL=0, closing session.\n");734			iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,735					  buf);736			return DATAOUT_CANNOT_RECOVER;737		}738 739		iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, buf);740		return iscsit_dataout_post_crc_failed(cmd, buf);741	}742}743 744void iscsit_handle_time2retain_timeout(struct timer_list *t)745{746	struct iscsit_session *sess = from_timer(sess, t, time2retain_timer);747	struct iscsi_portal_group *tpg = sess->tpg;748	struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;749 750	spin_lock_bh(&se_tpg->session_lock);751	if (sess->time2retain_timer_flags & ISCSI_TF_STOP) {752		spin_unlock_bh(&se_tpg->session_lock);753		return;754	}755	if (atomic_read(&sess->session_reinstatement)) {756		pr_err("Exiting Time2Retain handler because"757				" session_reinstatement=1\n");758		spin_unlock_bh(&se_tpg->session_lock);759		return;760	}761	sess->time2retain_timer_flags |= ISCSI_TF_EXPIRED;762 763	pr_err("Time2Retain timer expired for SID: %u, cleaning up"764			" iSCSI session.\n", sess->sid);765 766	iscsit_fill_cxn_timeout_err_stats(sess);767	spin_unlock_bh(&se_tpg->session_lock);768	iscsit_close_session(sess, false);769}770 771void iscsit_start_time2retain_handler(struct iscsit_session *sess)772{773	int tpg_active;774	/*775	 * Only start Time2Retain timer when the associated TPG is still in776	 * an ACTIVE (eg: not disabled or shutdown) state.777	 */778	spin_lock(&sess->tpg->tpg_state_lock);779	tpg_active = (sess->tpg->tpg_state == TPG_STATE_ACTIVE);780	spin_unlock(&sess->tpg->tpg_state_lock);781 782	if (!tpg_active)783		return;784 785	if (sess->time2retain_timer_flags & ISCSI_TF_RUNNING)786		return;787 788	pr_debug("Starting Time2Retain timer for %u seconds on"789		" SID: %u\n", sess->sess_ops->DefaultTime2Retain, sess->sid);790 791	sess->time2retain_timer_flags &= ~ISCSI_TF_STOP;792	sess->time2retain_timer_flags |= ISCSI_TF_RUNNING;793	mod_timer(&sess->time2retain_timer,794		  jiffies + sess->sess_ops->DefaultTime2Retain * HZ);795}796 797int iscsit_stop_time2retain_timer(struct iscsit_session *sess)798{799	struct iscsi_portal_group *tpg = sess->tpg;800	struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;801 802	lockdep_assert_held(&se_tpg->session_lock);803 804	if (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)805		return -1;806 807	if (!(sess->time2retain_timer_flags & ISCSI_TF_RUNNING))808		return 0;809 810	sess->time2retain_timer_flags |= ISCSI_TF_STOP;811	spin_unlock(&se_tpg->session_lock);812 813	del_timer_sync(&sess->time2retain_timer);814 815	spin_lock(&se_tpg->session_lock);816	sess->time2retain_timer_flags &= ~ISCSI_TF_RUNNING;817	pr_debug("Stopped Time2Retain Timer for SID: %u\n",818			sess->sid);819	return 0;820}821 822void iscsit_connection_reinstatement_rcfr(struct iscsit_conn *conn)823{824	spin_lock_bh(&conn->state_lock);825	if (atomic_read(&conn->connection_exit)) {826		spin_unlock_bh(&conn->state_lock);827		goto sleep;828	}829 830	if (atomic_read(&conn->transport_failed)) {831		spin_unlock_bh(&conn->state_lock);832		goto sleep;833	}834	spin_unlock_bh(&conn->state_lock);835 836	if (conn->tx_thread && conn->tx_thread_active)837		send_sig(SIGINT, conn->tx_thread, 1);838	if (conn->rx_thread && conn->rx_thread_active)839		send_sig(SIGINT, conn->rx_thread, 1);840 841sleep:842	wait_for_completion(&conn->conn_wait_rcfr_comp);843	complete(&conn->conn_post_wait_comp);844}845 846void iscsit_cause_connection_reinstatement(struct iscsit_conn *conn, int sleep)847{848	spin_lock_bh(&conn->state_lock);849	if (atomic_read(&conn->connection_exit)) {850		spin_unlock_bh(&conn->state_lock);851		return;852	}853 854	if (atomic_read(&conn->transport_failed)) {855		spin_unlock_bh(&conn->state_lock);856		return;857	}858 859	if (atomic_read(&conn->connection_reinstatement)) {860		spin_unlock_bh(&conn->state_lock);861		return;862	}863 864	if (conn->tx_thread && conn->tx_thread_active)865		send_sig(SIGINT, conn->tx_thread, 1);866	if (conn->rx_thread && conn->rx_thread_active)867		send_sig(SIGINT, conn->rx_thread, 1);868 869	atomic_set(&conn->connection_reinstatement, 1);870	if (!sleep) {871		spin_unlock_bh(&conn->state_lock);872		return;873	}874 875	atomic_set(&conn->sleep_on_conn_wait_comp, 1);876	spin_unlock_bh(&conn->state_lock);877 878	wait_for_completion(&conn->conn_wait_comp);879	complete(&conn->conn_post_wait_comp);880}881EXPORT_SYMBOL(iscsit_cause_connection_reinstatement);882 883void iscsit_fall_back_to_erl0(struct iscsit_session *sess)884{885	pr_debug("Falling back to ErrorRecoveryLevel=0 for SID:"886			" %u\n", sess->sid);887 888	atomic_set(&sess->session_fall_back_to_erl0, 1);889}890 891static void iscsit_handle_connection_cleanup(struct iscsit_conn *conn)892{893	struct iscsit_session *sess = conn->sess;894 895	if ((sess->sess_ops->ErrorRecoveryLevel == 2) &&896	    !atomic_read(&sess->session_reinstatement) &&897	    !atomic_read(&sess->session_fall_back_to_erl0))898		iscsit_connection_recovery_transport_reset(conn);899	else {900		pr_debug("Performing cleanup for failed iSCSI"901			" Connection ID: %hu from %s\n", conn->cid,902			sess->sess_ops->InitiatorName);903		iscsit_close_connection(conn);904	}905}906 907void iscsit_take_action_for_connection_exit(struct iscsit_conn *conn, bool *conn_freed)908{909	*conn_freed = false;910 911	spin_lock_bh(&conn->state_lock);912	if (atomic_read(&conn->connection_exit)) {913		spin_unlock_bh(&conn->state_lock);914		return;915	}916	atomic_set(&conn->connection_exit, 1);917 918	if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {919		spin_unlock_bh(&conn->state_lock);920		iscsit_close_connection(conn);921		*conn_freed = true;922		return;923	}924 925	if (conn->conn_state == TARG_CONN_STATE_CLEANUP_WAIT) {926		spin_unlock_bh(&conn->state_lock);927		return;928	}929 930	pr_debug("Moving to TARG_CONN_STATE_CLEANUP_WAIT.\n");931	conn->conn_state = TARG_CONN_STATE_CLEANUP_WAIT;932	spin_unlock_bh(&conn->state_lock);933 934	iscsit_handle_connection_cleanup(conn);935	*conn_freed = true;936}937