File Index
Files and directories
Sign in
FILE

iscsi_target_erl0.c

File preview with syntax highlighting.

linux-6.19.14/drivers/target/iscsi/iscsi_target_erl0.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/******************************************************************************
  3 * This file contains error recovery level zero functions used by
  4 * 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 current
 29 *	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 Unsolicited
 37	 * 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 is
 75	 * the first function called in iscsi_check_pre_dataout().
 76	 * Basically, if we are in within-command recovery and
 77	 * the PDU does not contain the offset the sequence needs,
 78	 * dump the payload.
 79	 *
 80	 * This only applies to DataPDUInOrder=Yes, for
 81	 * DataPDUInOrder=No we only re-request the failed PDU
 82	 * and check that all PDUs in a sequence are received
 83	 * 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 sanity
164	 * 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 of
169		 * sequence checks are handled in
170		 * 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+length
218	 * is within range as defined by iscsi_set_dataout_sequence_values().
219	 *
220	 * For DataSequenceInOrder=No: Check that an struct iscsi_seq exists for
221	 * offset+length tuple.
222	 */
223	if (conn->sess->sess_ops->DataSequenceInOrder) {
224		/*
225		 * Due to possibility of recovery DataOUT sent by the initiator
226		 * fullfilling an Recovery R2T, it's best to just dump the
227		 * 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 sanity
273	 * 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 of
278		 * sequence checks are handled in
279		 * 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 DataOUT
346	 * by DataSN, if we receieve a greater DataSN than expected we
347	 * assume the functions for DataPDUInOrder=[Yes,No] below will
348	 * 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 global
397	 * DataPDUInOrder=Yes offset counter in struct iscsit_cmd a protcol error has
398	 * occurred and fail the connection.
399	 *
400	 * For DataSequenceInOrder=No: If the offset is greater than the per
401	 * sequence DataPDUInOrder=Yes offset counter in struct iscsi_seq a protocol
402	 * 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	else
640		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 received
679 *	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 received
717 *	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 = timer_container_of(sess, t,
747							 time2retain_timer);
748	struct iscsi_portal_group *tpg = sess->tpg;
749	struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
750
751	spin_lock_bh(&se_tpg->session_lock);
752	if (sess->time2retain_timer_flags & ISCSI_TF_STOP) {
753		spin_unlock_bh(&se_tpg->session_lock);
754		return;
755	}
756	if (atomic_read(&sess->session_reinstatement)) {
757		pr_err("Exiting Time2Retain handler because"
758				" session_reinstatement=1\n");
759		spin_unlock_bh(&se_tpg->session_lock);
760		return;
761	}
762	sess->time2retain_timer_flags |= ISCSI_TF_EXPIRED;
763
764	pr_err("Time2Retain timer expired for SID: %u, cleaning up"
765			" iSCSI session.\n", sess->sid);
766
767	iscsit_fill_cxn_timeout_err_stats(sess);
768	spin_unlock_bh(&se_tpg->session_lock);
769	iscsit_close_session(sess, false);
770}
771
772void iscsit_start_time2retain_handler(struct iscsit_session *sess)
773{
774	int tpg_active;
775	/*
776	 * Only start Time2Retain timer when the associated TPG is still in
777	 * an ACTIVE (eg: not disabled or shutdown) state.
778	 */
779	spin_lock(&sess->tpg->tpg_state_lock);
780	tpg_active = (sess->tpg->tpg_state == TPG_STATE_ACTIVE);
781	spin_unlock(&sess->tpg->tpg_state_lock);
782
783	if (!tpg_active)
784		return;
785
786	if (sess->time2retain_timer_flags & ISCSI_TF_RUNNING)
787		return;
788
789	pr_debug("Starting Time2Retain timer for %u seconds on"
790		" SID: %u\n", sess->sess_ops->DefaultTime2Retain, sess->sid);
791
792	sess->time2retain_timer_flags &= ~ISCSI_TF_STOP;
793	sess->time2retain_timer_flags |= ISCSI_TF_RUNNING;
794	mod_timer(&sess->time2retain_timer,
795		  jiffies + sess->sess_ops->DefaultTime2Retain * HZ);
796}
797
798int iscsit_stop_time2retain_timer(struct iscsit_session *sess)
799{
800	struct iscsi_portal_group *tpg = sess->tpg;
801	struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
802
803	lockdep_assert_held(&se_tpg->session_lock);
804
805	if (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)
806		return -1;
807
808	if (!(sess->time2retain_timer_flags & ISCSI_TF_RUNNING))
809		return 0;
810
811	sess->time2retain_timer_flags |= ISCSI_TF_STOP;
812	spin_unlock(&se_tpg->session_lock);
813
814	timer_delete_sync(&sess->time2retain_timer);
815
816	spin_lock(&se_tpg->session_lock);
817	sess->time2retain_timer_flags &= ~ISCSI_TF_RUNNING;
818	pr_debug("Stopped Time2Retain Timer for SID: %u\n",
819			sess->sid);
820	return 0;
821}
822
823void iscsit_connection_reinstatement_rcfr(struct iscsit_conn *conn)
824{
825	spin_lock_bh(&conn->state_lock);
826	if (atomic_read(&conn->connection_exit)) {
827		spin_unlock_bh(&conn->state_lock);
828		goto sleep;
829	}
830
831	if (atomic_read(&conn->transport_failed)) {
832		spin_unlock_bh(&conn->state_lock);
833		goto sleep;
834	}
835	spin_unlock_bh(&conn->state_lock);
836
837	if (conn->tx_thread && conn->tx_thread_active)
838		send_sig(SIGINT, conn->tx_thread, 1);
839	if (conn->rx_thread && conn->rx_thread_active)
840		send_sig(SIGINT, conn->rx_thread, 1);
841
842sleep:
843	wait_for_completion(&conn->conn_wait_rcfr_comp);
844	complete(&conn->conn_post_wait_comp);
845}
846
847void iscsit_cause_connection_reinstatement(struct iscsit_conn *conn, int sleep)
848{
849	spin_lock_bh(&conn->state_lock);
850	if (atomic_read(&conn->connection_exit)) {
851		spin_unlock_bh(&conn->state_lock);
852		return;
853	}
854
855	if (atomic_read(&conn->transport_failed)) {
856		spin_unlock_bh(&conn->state_lock);
857		return;
858	}
859
860	if (atomic_read(&conn->connection_reinstatement)) {
861		spin_unlock_bh(&conn->state_lock);
862		return;
863	}
864
865	if (conn->tx_thread && conn->tx_thread_active)
866		send_sig(SIGINT, conn->tx_thread, 1);
867	if (conn->rx_thread && conn->rx_thread_active)
868		send_sig(SIGINT, conn->rx_thread, 1);
869
870	atomic_set(&conn->connection_reinstatement, 1);
871	if (!sleep) {
872		spin_unlock_bh(&conn->state_lock);
873		return;
874	}
875
876	atomic_set(&conn->sleep_on_conn_wait_comp, 1);
877	spin_unlock_bh(&conn->state_lock);
878
879	wait_for_completion(&conn->conn_wait_comp);
880	complete(&conn->conn_post_wait_comp);
881}
882EXPORT_SYMBOL(iscsit_cause_connection_reinstatement);
883
884void iscsit_fall_back_to_erl0(struct iscsit_session *sess)
885{
886	pr_debug("Falling back to ErrorRecoveryLevel=0 for SID:"
887			" %u\n", sess->sid);
888
889	atomic_set(&sess->session_fall_back_to_erl0, 1);
890}
891
892static void iscsit_handle_connection_cleanup(struct iscsit_conn *conn)
893{
894	struct iscsit_session *sess = conn->sess;
895
896	if ((sess->sess_ops->ErrorRecoveryLevel == 2) &&
897	    !atomic_read(&sess->session_reinstatement) &&
898	    !atomic_read(&sess->session_fall_back_to_erl0))
899		iscsit_connection_recovery_transport_reset(conn);
900	else {
901		pr_debug("Performing cleanup for failed iSCSI"
902			" Connection ID: %hu from %s\n", conn->cid,
903			sess->sess_ops->InitiatorName);
904		iscsit_close_connection(conn);
905	}
906}
907
908void iscsit_take_action_for_connection_exit(struct iscsit_conn *conn, bool *conn_freed)
909{
910	*conn_freed = false;
911
912	spin_lock_bh(&conn->state_lock);
913	if (atomic_read(&conn->connection_exit)) {
914		spin_unlock_bh(&conn->state_lock);
915		return;
916	}
917	atomic_set(&conn->connection_exit, 1);
918
919	if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
920		spin_unlock_bh(&conn->state_lock);
921		iscsit_close_connection(conn);
922		*conn_freed = true;
923		return;
924	}
925
926	if (conn->conn_state == TARG_CONN_STATE_CLEANUP_WAIT) {
927		spin_unlock_bh(&conn->state_lock);
928		return;
929	}
930
931	pr_debug("Moving to TARG_CONN_STATE_CLEANUP_WAIT.\n");
932	conn->conn_state = TARG_CONN_STATE_CLEANUP_WAIT;
933	spin_unlock_bh(&conn->state_lock);
934
935	iscsit_handle_connection_cleanup(conn);
936	*conn_freed = true;
937}
~/ Read-only file preview.