1275970Scy// SPDX-License-Identifier: GPL-2.0-or-later
2275970Scy/*******************************************************************************
3275970Scy * This file contains main functions related to iSCSI DataSequenceInOrder=No
4275970Scy * and DataPDUInOrder=No.
5275970Scy *
6275970Scy * (c) Copyright 2007-2013 Datera, Inc.
7275970Scy *
8275970Scy * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
9275970Scy *
10275970Scy ******************************************************************************/
11275970Scy
12275970Scy#include <linux/slab.h>
13275970Scy#include <linux/random.h>
14275970Scy
15275970Scy#include <target/iscsi/iscsi_target_core.h>
16275970Scy#include "iscsi_target_util.h"
17275970Scy#include "iscsi_target_tpg.h"
18275970Scy#include "iscsi_target_seq_pdu_list.h"
19275970Scy
20275970Scy#ifdef DEBUG
21275970Scystatic void iscsit_dump_seq_list(struct iscsit_cmd *cmd)
22275970Scy{
23275970Scy	int i;
24275970Scy	struct iscsi_seq *seq;
25275970Scy
26275970Scy	pr_debug("Dumping Sequence List for ITT: 0x%08x:\n",
27275970Scy			cmd->init_task_tag);
28275970Scy
29275970Scy	for (i = 0; i < cmd->seq_count; i++) {
30275970Scy		seq = &cmd->seq_list[i];
31275970Scy		pr_debug("i: %d, pdu_start: %d, pdu_count: %d,"
32275970Scy			" offset: %d, xfer_len: %d, seq_send_order: %d,"
33275970Scy			" seq_no: %d\n", i, seq->pdu_start, seq->pdu_count,
34275970Scy			seq->offset, seq->xfer_len, seq->seq_send_order,
35275970Scy			seq->seq_no);
36275970Scy	}
37275970Scy}
38275970Scy
39275970Scystatic void iscsit_dump_pdu_list(struct iscsit_cmd *cmd)
40275970Scy{
41275970Scy	int i;
42275970Scy	struct iscsi_pdu *pdu;
43275970Scy
44275970Scy	pr_debug("Dumping PDU List for ITT: 0x%08x:\n",
45275970Scy			cmd->init_task_tag);
46275970Scy
47275970Scy	for (i = 0; i < cmd->pdu_count; i++) {
48275970Scy		pdu = &cmd->pdu_list[i];
49275970Scy		pr_debug("i: %d, offset: %d, length: %d,"
50275970Scy			" pdu_send_order: %d, seq_no: %d\n", i, pdu->offset,
51275970Scy			pdu->length, pdu->pdu_send_order, pdu->seq_no);
52275970Scy	}
53275970Scy}
54275970Scy#else
55275970Scystatic void iscsit_dump_seq_list(struct iscsit_cmd *cmd) {}
56275970Scystatic void iscsit_dump_pdu_list(struct iscsit_cmd *cmd) {}
57275970Scy#endif
58275970Scy
59275970Scystatic void iscsit_ordered_seq_lists(
60275970Scy	struct iscsit_cmd *cmd,
61275970Scy	u8 type)
62275970Scy{
63275970Scy	u32 i, seq_count = 0;
64275970Scy
65275970Scy	for (i = 0; i < cmd->seq_count; i++) {
66275970Scy		if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
67275970Scy			continue;
68275970Scy		cmd->seq_list[i].seq_send_order = seq_count++;
69275970Scy	}
70275970Scy}
71275970Scy
72275970Scystatic void iscsit_ordered_pdu_lists(
73275970Scy	struct iscsit_cmd *cmd,
74275970Scy	u8 type)
75275970Scy{
76275970Scy	u32 i, pdu_send_order = 0, seq_no = 0;
77275970Scy
78275970Scy	for (i = 0; i < cmd->pdu_count; i++) {
79275970Scyredo:
80275970Scy		if (cmd->pdu_list[i].seq_no == seq_no) {
81275970Scy			cmd->pdu_list[i].pdu_send_order = pdu_send_order++;
82275970Scy			continue;
83275970Scy		}
84275970Scy		seq_no++;
85275970Scy		pdu_send_order = 0;
86275970Scy		goto redo;
87275970Scy	}
88275970Scy}
89275970Scy
90275970Scy/*
91275970Scy *	Generate count random values into array.
92275970Scy *	Use 0x80000000 to mark generates valued in array[].
93275970Scy */
94275970Scystatic void iscsit_create_random_array(u32 *array, u32 count)
95275970Scy{
96275970Scy	int i, j, k;
97275970Scy
98275970Scy	if (count == 1) {
99275970Scy		array[0] = 0;
100275970Scy		return;
101275970Scy	}
102275970Scy
103275970Scy	for (i = 0; i < count; i++) {
104275970Scyredo:
105275970Scy		get_random_bytes(&j, sizeof(u32));
106275970Scy		j = (1 + (int) (9999 + 1) - j) % count;
107275970Scy		for (k = 0; k < i + 1; k++) {
108275970Scy			j |= 0x80000000;
109275970Scy			if ((array[k] & 0x80000000) && (array[k] == j))
110275970Scy				goto redo;
111275970Scy		}
112275970Scy		array[i] = j;
113275970Scy	}
114275970Scy
115275970Scy	for (i = 0; i < count; i++)
116275970Scy		array[i] &= ~0x80000000;
117275970Scy}
118275970Scy
119275970Scystatic int iscsit_randomize_pdu_lists(
120275970Scy	struct iscsit_cmd *cmd,
121275970Scy	u8 type)
122275970Scy{
123275970Scy	int i = 0;
124275970Scy	u32 *array, pdu_count, seq_count = 0, seq_no = 0, seq_offset = 0;
125275970Scy
126275970Scy	for (pdu_count = 0; pdu_count < cmd->pdu_count; pdu_count++) {
127275970Scyredo:
128275970Scy		if (cmd->pdu_list[pdu_count].seq_no == seq_no) {
129275970Scy			seq_count++;
130275970Scy			continue;
131275970Scy		}
132275970Scy		array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
133275970Scy		if (!array) {
134275970Scy			pr_err("Unable to allocate memory"
135275970Scy				" for random array.\n");
136275970Scy			return -ENOMEM;
137275970Scy		}
138275970Scy		iscsit_create_random_array(array, seq_count);
139275970Scy
140275970Scy		for (i = 0; i < seq_count; i++)
141275970Scy			cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
142275970Scy
143275970Scy		kfree(array);
144275970Scy
145275970Scy		seq_offset += seq_count;
146275970Scy		seq_count = 0;
147275970Scy		seq_no++;
148275970Scy		goto redo;
149275970Scy	}
150275970Scy
151275970Scy	if (seq_count) {
152275970Scy		array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
153275970Scy		if (!array) {
154275970Scy			pr_err("Unable to allocate memory for"
155275970Scy				" random array.\n");
156275970Scy			return -ENOMEM;
157275970Scy		}
158275970Scy		iscsit_create_random_array(array, seq_count);
159275970Scy
160275970Scy		for (i = 0; i < seq_count; i++)
161275970Scy			cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
162275970Scy
163275970Scy		kfree(array);
164275970Scy	}
165275970Scy
166275970Scy	return 0;
167275970Scy}
168275970Scy
169275970Scystatic int iscsit_randomize_seq_lists(
170275970Scy	struct iscsit_cmd *cmd,
171275970Scy	u8 type)
172275970Scy{
173275970Scy	int i, j = 0;
174275970Scy	u32 *array, seq_count = cmd->seq_count;
175275970Scy
176275970Scy	if ((type == PDULIST_IMMEDIATE) || (type == PDULIST_UNSOLICITED))
177275970Scy		seq_count--;
178275970Scy	else if (type == PDULIST_IMMEDIATE_AND_UNSOLICITED)
179275970Scy		seq_count -= 2;
180275970Scy
181275970Scy	if (!seq_count)
182275970Scy		return 0;
183275970Scy
184275970Scy	array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
185275970Scy	if (!array) {
186275970Scy		pr_err("Unable to allocate memory for random array.\n");
187275970Scy		return -ENOMEM;
188275970Scy	}
189275970Scy	iscsit_create_random_array(array, seq_count);
190275970Scy
191275970Scy	for (i = 0; i < cmd->seq_count; i++) {
192275970Scy		if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
193275970Scy			continue;
194275970Scy		cmd->seq_list[i].seq_send_order = array[j++];
195275970Scy	}
196275970Scy
197275970Scy	kfree(array);
198275970Scy	return 0;
199275970Scy}
200275970Scy
201275970Scystatic void iscsit_determine_counts_for_list(
202275970Scy	struct iscsit_cmd *cmd,
203275970Scy	struct iscsi_build_list *bl,
204275970Scy	u32 *seq_count,
205275970Scy	u32 *pdu_count)
206275970Scy{
207275970Scy	int check_immediate = 0;
208275970Scy	u32 burstlength = 0, offset = 0;
209275970Scy	u32 unsolicited_data_length = 0;
210275970Scy	u32 mdsl;
211275970Scy	struct iscsit_conn *conn = cmd->conn;
212275970Scy
213275970Scy	if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
214275970Scy		mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
215275970Scy	else
216275970Scy		mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
217275970Scy
218275970Scy	if ((bl->type == PDULIST_IMMEDIATE) ||
219275970Scy	    (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
220275970Scy		check_immediate = 1;
221275970Scy
222275970Scy	if ((bl->type == PDULIST_UNSOLICITED) ||
223275970Scy	    (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
224275970Scy		unsolicited_data_length = min(cmd->se_cmd.data_length,
225275970Scy			conn->sess->sess_ops->FirstBurstLength);
226275970Scy
227275970Scy	while (offset < cmd->se_cmd.data_length) {
228275970Scy		*pdu_count += 1;
229275970Scy
230275970Scy		if (check_immediate) {
231275970Scy			check_immediate = 0;
232275970Scy			offset += bl->immediate_data_length;
233275970Scy			*seq_count += 1;
234275970Scy			if (unsolicited_data_length)
235275970Scy				unsolicited_data_length -=
236275970Scy					bl->immediate_data_length;
237275970Scy			continue;
238275970Scy		}
239275970Scy		if (unsolicited_data_length > 0) {
240275970Scy			if ((offset + mdsl) >= cmd->se_cmd.data_length) {
241275970Scy				unsolicited_data_length -=
242275970Scy					(cmd->se_cmd.data_length - offset);
243275970Scy				offset += (cmd->se_cmd.data_length - offset);
244275970Scy				continue;
245275970Scy			}
246275970Scy			if ((offset + mdsl)
247275970Scy					>= conn->sess->sess_ops->FirstBurstLength) {
248275970Scy				unsolicited_data_length -=
249275970Scy					(conn->sess->sess_ops->FirstBurstLength -
250275970Scy					offset);
251275970Scy				offset += (conn->sess->sess_ops->FirstBurstLength -
252275970Scy					offset);
253275970Scy				burstlength = 0;
254275970Scy				*seq_count += 1;
255275970Scy				continue;
256275970Scy			}
257275970Scy
258275970Scy			offset += mdsl;
259275970Scy			unsolicited_data_length -= mdsl;
260275970Scy			continue;
261275970Scy		}
262275970Scy		if ((offset + mdsl) >= cmd->se_cmd.data_length) {
263275970Scy			offset += (cmd->se_cmd.data_length - offset);
264275970Scy			continue;
265275970Scy		}
266275970Scy		if ((burstlength + mdsl) >=
267275970Scy		     conn->sess->sess_ops->MaxBurstLength) {
268275970Scy			offset += (conn->sess->sess_ops->MaxBurstLength -
269275970Scy					burstlength);
270275970Scy			burstlength = 0;
271275970Scy			*seq_count += 1;
272275970Scy			continue;
273275970Scy		}
274275970Scy
275275970Scy		burstlength += mdsl;
276275970Scy		offset += mdsl;
277275970Scy	}
278275970Scy}
279275970Scy
280275970Scy
281275970Scy/*
282275970Scy *	Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
283275970Scy *	or DataPDUInOrder=No.
284275970Scy */
285275970Scystatic int iscsit_do_build_pdu_and_seq_lists(
286275970Scy	struct iscsit_cmd *cmd,
287275970Scy	struct iscsi_build_list *bl)
288275970Scy{
289275970Scy	int check_immediate = 0, datapduinorder, datasequenceinorder;
290275970Scy	u32 burstlength = 0, offset = 0, i = 0, mdsl;
291275970Scy	u32 pdu_count = 0, seq_no = 0, unsolicited_data_length = 0;
292275970Scy	struct iscsit_conn *conn = cmd->conn;
293275970Scy	struct iscsi_pdu *pdu = cmd->pdu_list;
294275970Scy	struct iscsi_seq *seq = cmd->seq_list;
295275970Scy
296275970Scy	if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
297275970Scy		mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
298275970Scy	else
299275970Scy		mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
300275970Scy
301275970Scy	datapduinorder = conn->sess->sess_ops->DataPDUInOrder;
302275970Scy	datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder;
303275970Scy
304275970Scy	if ((bl->type == PDULIST_IMMEDIATE) ||
305275970Scy	    (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
306275970Scy		check_immediate = 1;
307275970Scy
308275970Scy	if ((bl->type == PDULIST_UNSOLICITED) ||
309275970Scy	    (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
310275970Scy		unsolicited_data_length = min(cmd->se_cmd.data_length,
311275970Scy			conn->sess->sess_ops->FirstBurstLength);
312275970Scy
313275970Scy	while (offset < cmd->se_cmd.data_length) {
314275970Scy		pdu_count++;
315275970Scy		if (!datapduinorder) {
316275970Scy			pdu[i].offset = offset;
317275970Scy			pdu[i].seq_no = seq_no;
318275970Scy		}
319275970Scy		if (!datasequenceinorder && (pdu_count == 1)) {
320275970Scy			seq[seq_no].pdu_start = i;
321275970Scy			seq[seq_no].seq_no = seq_no;
322275970Scy			seq[seq_no].offset = offset;
323275970Scy			seq[seq_no].orig_offset = offset;
324275970Scy		}
325275970Scy
326275970Scy		if (check_immediate) {
327275970Scy			check_immediate = 0;
328275970Scy			if (!datapduinorder) {
329275970Scy				pdu[i].type = PDUTYPE_IMMEDIATE;
330275970Scy				pdu[i++].length = bl->immediate_data_length;
331275970Scy			}
332275970Scy			if (!datasequenceinorder) {
333275970Scy				seq[seq_no].type = SEQTYPE_IMMEDIATE;
334275970Scy				seq[seq_no].pdu_count = 1;
335275970Scy				seq[seq_no].xfer_len =
336275970Scy					bl->immediate_data_length;
337275970Scy			}
338275970Scy			offset += bl->immediate_data_length;
339275970Scy			pdu_count = 0;
340275970Scy			seq_no++;
341275970Scy			if (unsolicited_data_length)
342275970Scy				unsolicited_data_length -=
343275970Scy					bl->immediate_data_length;
344275970Scy			continue;
345275970Scy		}
346275970Scy		if (unsolicited_data_length > 0) {
347275970Scy			if ((offset + mdsl) >= cmd->se_cmd.data_length) {
348275970Scy				if (!datapduinorder) {
349275970Scy					pdu[i].type = PDUTYPE_UNSOLICITED;
350275970Scy					pdu[i].length =
351275970Scy						(cmd->se_cmd.data_length - offset);
352275970Scy				}
353275970Scy				if (!datasequenceinorder) {
354275970Scy					seq[seq_no].type = SEQTYPE_UNSOLICITED;
355275970Scy					seq[seq_no].pdu_count = pdu_count;
356275970Scy					seq[seq_no].xfer_len = (burstlength +
357275970Scy						(cmd->se_cmd.data_length - offset));
358275970Scy				}
359275970Scy				unsolicited_data_length -=
360275970Scy						(cmd->se_cmd.data_length - offset);
361275970Scy				offset += (cmd->se_cmd.data_length - offset);
362275970Scy				continue;
363275970Scy			}
364275970Scy			if ((offset + mdsl) >=
365275970Scy					conn->sess->sess_ops->FirstBurstLength) {
366275970Scy				if (!datapduinorder) {
367275970Scy					pdu[i].type = PDUTYPE_UNSOLICITED;
368275970Scy					pdu[i++].length =
369275970Scy					   (conn->sess->sess_ops->FirstBurstLength -
370275970Scy						offset);
371275970Scy				}
372275970Scy				if (!datasequenceinorder) {
373275970Scy					seq[seq_no].type = SEQTYPE_UNSOLICITED;
374275970Scy					seq[seq_no].pdu_count = pdu_count;
375275970Scy					seq[seq_no].xfer_len = (burstlength +
376275970Scy					   (conn->sess->sess_ops->FirstBurstLength -
377275970Scy						offset));
378275970Scy				}
379275970Scy				unsolicited_data_length -=
380275970Scy					(conn->sess->sess_ops->FirstBurstLength -
381275970Scy						offset);
382275970Scy				offset += (conn->sess->sess_ops->FirstBurstLength -
383275970Scy						offset);
384275970Scy				burstlength = 0;
385275970Scy				pdu_count = 0;
386275970Scy				seq_no++;
387275970Scy				continue;
388275970Scy			}
389275970Scy
390275970Scy			if (!datapduinorder) {
391275970Scy				pdu[i].type = PDUTYPE_UNSOLICITED;
392275970Scy				pdu[i++].length = mdsl;
393275970Scy			}
394275970Scy			burstlength += mdsl;
395275970Scy			offset += mdsl;
396275970Scy			unsolicited_data_length -= mdsl;
397275970Scy			continue;
398275970Scy		}
399275970Scy		if ((offset + mdsl) >= cmd->se_cmd.data_length) {
400275970Scy			if (!datapduinorder) {
401275970Scy				pdu[i].type = PDUTYPE_NORMAL;
402275970Scy				pdu[i].length = (cmd->se_cmd.data_length - offset);
403275970Scy			}
404275970Scy			if (!datasequenceinorder) {
405275970Scy				seq[seq_no].type = SEQTYPE_NORMAL;
406275970Scy				seq[seq_no].pdu_count = pdu_count;
407275970Scy				seq[seq_no].xfer_len = (burstlength +
408275970Scy					(cmd->se_cmd.data_length - offset));
409275970Scy			}
410275970Scy			offset += (cmd->se_cmd.data_length - offset);
411275970Scy			continue;
412275970Scy		}
413275970Scy		if ((burstlength + mdsl) >=
414275970Scy		     conn->sess->sess_ops->MaxBurstLength) {
415275970Scy			if (!datapduinorder) {
416275970Scy				pdu[i].type = PDUTYPE_NORMAL;
417275970Scy				pdu[i++].length =
418275970Scy					(conn->sess->sess_ops->MaxBurstLength -
419275970Scy						burstlength);
420275970Scy			}
421275970Scy			if (!datasequenceinorder) {
422275970Scy				seq[seq_no].type = SEQTYPE_NORMAL;
423275970Scy				seq[seq_no].pdu_count = pdu_count;
424275970Scy				seq[seq_no].xfer_len = (burstlength +
425275970Scy					(conn->sess->sess_ops->MaxBurstLength -
426275970Scy					burstlength));
427275970Scy			}
428275970Scy			offset += (conn->sess->sess_ops->MaxBurstLength -
429275970Scy					burstlength);
430275970Scy			burstlength = 0;
431275970Scy			pdu_count = 0;
432275970Scy			seq_no++;
433275970Scy			continue;
434275970Scy		}
435275970Scy
436275970Scy		if (!datapduinorder) {
437275970Scy			pdu[i].type = PDUTYPE_NORMAL;
438275970Scy			pdu[i++].length = mdsl;
439275970Scy		}
440275970Scy		burstlength += mdsl;
441275970Scy		offset += mdsl;
442275970Scy	}
443275970Scy
444275970Scy	if (!datasequenceinorder) {
445275970Scy		if (bl->data_direction & ISCSI_PDU_WRITE) {
446275970Scy			if (bl->randomize & RANDOM_R2T_OFFSETS) {
447275970Scy				if (iscsit_randomize_seq_lists(cmd, bl->type)
448275970Scy						< 0)
449275970Scy					return -1;
450275970Scy			} else
451275970Scy				iscsit_ordered_seq_lists(cmd, bl->type);
452275970Scy		} else if (bl->data_direction & ISCSI_PDU_READ) {
453275970Scy			if (bl->randomize & RANDOM_DATAIN_SEQ_OFFSETS) {
454275970Scy				if (iscsit_randomize_seq_lists(cmd, bl->type)
455275970Scy						< 0)
456275970Scy					return -1;
457275970Scy			} else
458275970Scy				iscsit_ordered_seq_lists(cmd, bl->type);
459275970Scy		}
460275970Scy
461275970Scy		iscsit_dump_seq_list(cmd);
462275970Scy	}
463275970Scy	if (!datapduinorder) {
464275970Scy		if (bl->data_direction & ISCSI_PDU_WRITE) {
465275970Scy			if (bl->randomize & RANDOM_DATAOUT_PDU_OFFSETS) {
466275970Scy				if (iscsit_randomize_pdu_lists(cmd, bl->type)
467275970Scy						< 0)
468275970Scy					return -1;
469275970Scy			} else
470275970Scy				iscsit_ordered_pdu_lists(cmd, bl->type);
471275970Scy		} else if (bl->data_direction & ISCSI_PDU_READ) {
472275970Scy			if (bl->randomize & RANDOM_DATAIN_PDU_OFFSETS) {
473275970Scy				if (iscsit_randomize_pdu_lists(cmd, bl->type)
474275970Scy						< 0)
475275970Scy					return -1;
476275970Scy			} else
477275970Scy				iscsit_ordered_pdu_lists(cmd, bl->type);
478275970Scy		}
479275970Scy
480275970Scy		iscsit_dump_pdu_list(cmd);
481275970Scy	}
482275970Scy
483275970Scy	return 0;
484275970Scy}
485275970Scy
486275970Scyint iscsit_build_pdu_and_seq_lists(
487275970Scy	struct iscsit_cmd *cmd,
488275970Scy	u32 immediate_data_length)
489{
490	struct iscsi_build_list bl;
491	u32 pdu_count = 0, seq_count = 1;
492	struct iscsit_conn *conn = cmd->conn;
493	struct iscsi_pdu *pdu = NULL;
494	struct iscsi_seq *seq = NULL;
495
496	struct iscsit_session *sess = conn->sess;
497	struct iscsi_node_attrib *na;
498
499	/*
500	 * Do nothing if no OOO shenanigans
501	 */
502	if (sess->sess_ops->DataSequenceInOrder &&
503	    sess->sess_ops->DataPDUInOrder)
504		return 0;
505
506	if (cmd->data_direction == DMA_NONE)
507		return 0;
508
509	na = iscsit_tpg_get_node_attrib(sess);
510	memset(&bl, 0, sizeof(struct iscsi_build_list));
511
512	if (cmd->data_direction == DMA_FROM_DEVICE) {
513		bl.data_direction = ISCSI_PDU_READ;
514		bl.type = PDULIST_NORMAL;
515		if (na->random_datain_pdu_offsets)
516			bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS;
517		if (na->random_datain_seq_offsets)
518			bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS;
519	} else {
520		bl.data_direction = ISCSI_PDU_WRITE;
521		bl.immediate_data_length = immediate_data_length;
522		if (na->random_r2t_offsets)
523			bl.randomize |= RANDOM_R2T_OFFSETS;
524
525		if (!cmd->immediate_data && !cmd->unsolicited_data)
526			bl.type = PDULIST_NORMAL;
527		else if (cmd->immediate_data && !cmd->unsolicited_data)
528			bl.type = PDULIST_IMMEDIATE;
529		else if (!cmd->immediate_data && cmd->unsolicited_data)
530			bl.type = PDULIST_UNSOLICITED;
531		else if (cmd->immediate_data && cmd->unsolicited_data)
532			bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED;
533	}
534
535	iscsit_determine_counts_for_list(cmd, &bl, &seq_count, &pdu_count);
536
537	if (!conn->sess->sess_ops->DataSequenceInOrder) {
538		seq = kcalloc(seq_count, sizeof(struct iscsi_seq), GFP_ATOMIC);
539		if (!seq) {
540			pr_err("Unable to allocate struct iscsi_seq list\n");
541			return -ENOMEM;
542		}
543		cmd->seq_list = seq;
544		cmd->seq_count = seq_count;
545	}
546
547	if (!conn->sess->sess_ops->DataPDUInOrder) {
548		pdu = kcalloc(pdu_count, sizeof(struct iscsi_pdu), GFP_ATOMIC);
549		if (!pdu) {
550			pr_err("Unable to allocate struct iscsi_pdu list.\n");
551			kfree(seq);
552			return -ENOMEM;
553		}
554		cmd->pdu_list = pdu;
555		cmd->pdu_count = pdu_count;
556	}
557
558	return iscsit_do_build_pdu_and_seq_lists(cmd, &bl);
559}
560
561struct iscsi_pdu *iscsit_get_pdu_holder(
562	struct iscsit_cmd *cmd,
563	u32 offset,
564	u32 length)
565{
566	u32 i;
567	struct iscsi_pdu *pdu = NULL;
568
569	if (!cmd->pdu_list) {
570		pr_err("struct iscsit_cmd->pdu_list is NULL!\n");
571		return NULL;
572	}
573
574	pdu = &cmd->pdu_list[0];
575
576	for (i = 0; i < cmd->pdu_count; i++)
577		if ((pdu[i].offset == offset) && (pdu[i].length == length))
578			return &pdu[i];
579
580	pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
581		" %u, Length: %u\n", cmd->init_task_tag, offset, length);
582	return NULL;
583}
584
585struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(
586	struct iscsit_cmd *cmd,
587	struct iscsi_seq *seq)
588{
589	u32 i;
590	struct iscsit_conn *conn = cmd->conn;
591	struct iscsi_pdu *pdu = NULL;
592
593	if (!cmd->pdu_list) {
594		pr_err("struct iscsit_cmd->pdu_list is NULL!\n");
595		return NULL;
596	}
597
598	if (conn->sess->sess_ops->DataSequenceInOrder) {
599redo:
600		pdu = &cmd->pdu_list[cmd->pdu_start];
601
602		for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) {
603			pr_debug("pdu[i].seq_no: %d, pdu[i].pdu"
604				"_send_order: %d, pdu[i].offset: %d,"
605				" pdu[i].length: %d\n", pdu[i].seq_no,
606				pdu[i].pdu_send_order, pdu[i].offset,
607				pdu[i].length);
608
609			if (pdu[i].pdu_send_order == cmd->pdu_send_order) {
610				cmd->pdu_send_order++;
611				return &pdu[i];
612			}
613		}
614
615		cmd->pdu_start += cmd->pdu_send_order;
616		cmd->pdu_send_order = 0;
617		cmd->seq_no++;
618
619		if (cmd->pdu_start < cmd->pdu_count)
620			goto redo;
621
622		pr_err("Command ITT: 0x%08x unable to locate"
623			" struct iscsi_pdu for cmd->pdu_send_order: %u.\n",
624			cmd->init_task_tag, cmd->pdu_send_order);
625		return NULL;
626	} else {
627		if (!seq) {
628			pr_err("struct iscsi_seq is NULL!\n");
629			return NULL;
630		}
631
632		pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
633			" seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count,
634			seq->seq_no);
635
636		pdu = &cmd->pdu_list[seq->pdu_start];
637
638		if (seq->pdu_send_order == seq->pdu_count) {
639			pr_err("Command ITT: 0x%08x seq->pdu_send"
640				"_order: %u equals seq->pdu_count: %u\n",
641				cmd->init_task_tag, seq->pdu_send_order,
642				seq->pdu_count);
643			return NULL;
644		}
645
646		for (i = 0; i < seq->pdu_count; i++) {
647			if (pdu[i].pdu_send_order == seq->pdu_send_order) {
648				seq->pdu_send_order++;
649				return &pdu[i];
650			}
651		}
652
653		pr_err("Command ITT: 0x%08x unable to locate iscsi"
654			"_pdu_t for seq->pdu_send_order: %u.\n",
655			cmd->init_task_tag, seq->pdu_send_order);
656		return NULL;
657	}
658
659	return NULL;
660}
661
662struct iscsi_seq *iscsit_get_seq_holder(
663	struct iscsit_cmd *cmd,
664	u32 offset,
665	u32 length)
666{
667	u32 i;
668
669	if (!cmd->seq_list) {
670		pr_err("struct iscsit_cmd->seq_list is NULL!\n");
671		return NULL;
672	}
673
674	for (i = 0; i < cmd->seq_count; i++) {
675		pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
676			"xfer_len: %d, seq_list[i].seq_no %u\n",
677			cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len,
678			cmd->seq_list[i].seq_no);
679
680		if ((cmd->seq_list[i].orig_offset +
681				cmd->seq_list[i].xfer_len) >=
682				(offset + length))
683			return &cmd->seq_list[i];
684	}
685
686	pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
687		" Offset: %u, Length: %u\n", cmd->init_task_tag, offset,
688		length);
689	return NULL;
690}
691