1/*******************************************************************************
2 * This file contains main functions related to iSCSI DataSequenceInOrder=No
3 * and DataPDUInOrder=No.
4 *
5 \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
6 *
7 * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
8 *
9 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 ******************************************************************************/
21
22#include <linux/slab.h>
23#include <linux/random.h>
24
25#include "iscsi_target_core.h"
26#include "iscsi_target_util.h"
27#include "iscsi_target_seq_pdu_list.h"
28
29#define OFFLOAD_BUF_SIZE	32768
30
31void iscsit_dump_seq_list(struct iscsi_cmd *cmd)
32{
33	int i;
34	struct iscsi_seq *seq;
35
36	pr_debug("Dumping Sequence List for ITT: 0x%08x:\n",
37			cmd->init_task_tag);
38
39	for (i = 0; i < cmd->seq_count; i++) {
40		seq = &cmd->seq_list[i];
41		pr_debug("i: %d, pdu_start: %d, pdu_count: %d,"
42			" offset: %d, xfer_len: %d, seq_send_order: %d,"
43			" seq_no: %d\n", i, seq->pdu_start, seq->pdu_count,
44			seq->offset, seq->xfer_len, seq->seq_send_order,
45			seq->seq_no);
46	}
47}
48
49void iscsit_dump_pdu_list(struct iscsi_cmd *cmd)
50{
51	int i;
52	struct iscsi_pdu *pdu;
53
54	pr_debug("Dumping PDU List for ITT: 0x%08x:\n",
55			cmd->init_task_tag);
56
57	for (i = 0; i < cmd->pdu_count; i++) {
58		pdu = &cmd->pdu_list[i];
59		pr_debug("i: %d, offset: %d, length: %d,"
60			" pdu_send_order: %d, seq_no: %d\n", i, pdu->offset,
61			pdu->length, pdu->pdu_send_order, pdu->seq_no);
62	}
63}
64
65static void iscsit_ordered_seq_lists(
66	struct iscsi_cmd *cmd,
67	u8 type)
68{
69	u32 i, seq_count = 0;
70
71	for (i = 0; i < cmd->seq_count; i++) {
72		if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
73			continue;
74		cmd->seq_list[i].seq_send_order = seq_count++;
75	}
76}
77
78static void iscsit_ordered_pdu_lists(
79	struct iscsi_cmd *cmd,
80	u8 type)
81{
82	u32 i, pdu_send_order = 0, seq_no = 0;
83
84	for (i = 0; i < cmd->pdu_count; i++) {
85redo:
86		if (cmd->pdu_list[i].seq_no == seq_no) {
87			cmd->pdu_list[i].pdu_send_order = pdu_send_order++;
88			continue;
89		}
90		seq_no++;
91		pdu_send_order = 0;
92		goto redo;
93	}
94}
95
96/*
97 *	Generate count random values into array.
98 *	Use 0x80000000 to mark generates valued in array[].
99 */
100static void iscsit_create_random_array(u32 *array, u32 count)
101{
102	int i, j, k;
103
104	if (count == 1) {
105		array[0] = 0;
106		return;
107	}
108
109	for (i = 0; i < count; i++) {
110redo:
111		get_random_bytes(&j, sizeof(u32));
112		j = (1 + (int) (9999 + 1) - j) % count;
113		for (k = 0; k < i + 1; k++) {
114			j |= 0x80000000;
115			if ((array[k] & 0x80000000) && (array[k] == j))
116				goto redo;
117		}
118		array[i] = j;
119	}
120
121	for (i = 0; i < count; i++)
122		array[i] &= ~0x80000000;
123}
124
125static int iscsit_randomize_pdu_lists(
126	struct iscsi_cmd *cmd,
127	u8 type)
128{
129	int i = 0;
130	u32 *array, pdu_count, seq_count = 0, seq_no = 0, seq_offset = 0;
131
132	for (pdu_count = 0; pdu_count < cmd->pdu_count; pdu_count++) {
133redo:
134		if (cmd->pdu_list[pdu_count].seq_no == seq_no) {
135			seq_count++;
136			continue;
137		}
138		array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
139		if (!array) {
140			pr_err("Unable to allocate memory"
141				" for random array.\n");
142			return -1;
143		}
144		iscsit_create_random_array(array, seq_count);
145
146		for (i = 0; i < seq_count; i++)
147			cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
148
149		kfree(array);
150
151		seq_offset += seq_count;
152		seq_count = 0;
153		seq_no++;
154		goto redo;
155	}
156
157	if (seq_count) {
158		array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
159		if (!array) {
160			pr_err("Unable to allocate memory for"
161				" random array.\n");
162			return -1;
163		}
164		iscsit_create_random_array(array, seq_count);
165
166		for (i = 0; i < seq_count; i++)
167			cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
168
169		kfree(array);
170	}
171
172	return 0;
173}
174
175static int iscsit_randomize_seq_lists(
176	struct iscsi_cmd *cmd,
177	u8 type)
178{
179	int i, j = 0;
180	u32 *array, seq_count = cmd->seq_count;
181
182	if ((type == PDULIST_IMMEDIATE) || (type == PDULIST_UNSOLICITED))
183		seq_count--;
184	else if (type == PDULIST_IMMEDIATE_AND_UNSOLICITED)
185		seq_count -= 2;
186
187	if (!seq_count)
188		return 0;
189
190	array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
191	if (!array) {
192		pr_err("Unable to allocate memory for random array.\n");
193		return -1;
194	}
195	iscsit_create_random_array(array, seq_count);
196
197	for (i = 0; i < cmd->seq_count; i++) {
198		if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
199			continue;
200		cmd->seq_list[i].seq_send_order = array[j++];
201	}
202
203	kfree(array);
204	return 0;
205}
206
207static void iscsit_determine_counts_for_list(
208	struct iscsi_cmd *cmd,
209	struct iscsi_build_list *bl,
210	u32 *seq_count,
211	u32 *pdu_count)
212{
213	int check_immediate = 0;
214	u32 burstlength = 0, offset = 0;
215	u32 unsolicited_data_length = 0;
216	struct iscsi_conn *conn = cmd->conn;
217
218	if ((bl->type == PDULIST_IMMEDIATE) ||
219	    (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
220		check_immediate = 1;
221
222	if ((bl->type == PDULIST_UNSOLICITED) ||
223	    (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
224		unsolicited_data_length = (cmd->data_length >
225			conn->sess->sess_ops->FirstBurstLength) ?
226			conn->sess->sess_ops->FirstBurstLength : cmd->data_length;
227
228	while (offset < cmd->data_length) {
229		*pdu_count += 1;
230
231		if (check_immediate) {
232			check_immediate = 0;
233			offset += bl->immediate_data_length;
234			*seq_count += 1;
235			if (unsolicited_data_length)
236				unsolicited_data_length -=
237					bl->immediate_data_length;
238			continue;
239		}
240		if (unsolicited_data_length > 0) {
241			if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
242					>= cmd->data_length) {
243				unsolicited_data_length -=
244					(cmd->data_length - offset);
245				offset += (cmd->data_length - offset);
246				continue;
247			}
248			if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
249					>= conn->sess->sess_ops->FirstBurstLength) {
250				unsolicited_data_length -=
251					(conn->sess->sess_ops->FirstBurstLength -
252					offset);
253				offset += (conn->sess->sess_ops->FirstBurstLength -
254					offset);
255				burstlength = 0;
256				*seq_count += 1;
257				continue;
258			}
259
260			offset += conn->conn_ops->MaxRecvDataSegmentLength;
261			unsolicited_data_length -=
262				conn->conn_ops->MaxRecvDataSegmentLength;
263			continue;
264		}
265		if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
266		     cmd->data_length) {
267			offset += (cmd->data_length - offset);
268			continue;
269		}
270		if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
271		     conn->sess->sess_ops->MaxBurstLength) {
272			offset += (conn->sess->sess_ops->MaxBurstLength -
273					burstlength);
274			burstlength = 0;
275			*seq_count += 1;
276			continue;
277		}
278
279		burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
280		offset += conn->conn_ops->MaxRecvDataSegmentLength;
281	}
282}
283
284
285/*
286 *	Builds PDU and/or Sequence list,  called while DataSequenceInOrder=No
287 *	and DataPDUInOrder=No.
288 */
289static int iscsit_build_pdu_and_seq_list(
290	struct iscsi_cmd *cmd,
291	struct iscsi_build_list *bl)
292{
293	int check_immediate = 0, datapduinorder, datasequenceinorder;
294	u32 burstlength = 0, offset = 0, i = 0;
295	u32 pdu_count = 0, seq_no = 0, unsolicited_data_length = 0;
296	struct iscsi_conn *conn = cmd->conn;
297	struct iscsi_pdu *pdu = cmd->pdu_list;
298	struct iscsi_seq *seq = cmd->seq_list;
299
300	datapduinorder = conn->sess->sess_ops->DataPDUInOrder;
301	datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder;
302
303	if ((bl->type == PDULIST_IMMEDIATE) ||
304	    (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
305		check_immediate = 1;
306
307	if ((bl->type == PDULIST_UNSOLICITED) ||
308	    (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
309		unsolicited_data_length = (cmd->data_length >
310			conn->sess->sess_ops->FirstBurstLength) ?
311			conn->sess->sess_ops->FirstBurstLength : cmd->data_length;
312
313	while (offset < cmd->data_length) {
314		pdu_count++;
315		if (!datapduinorder) {
316			pdu[i].offset = offset;
317			pdu[i].seq_no = seq_no;
318		}
319		if (!datasequenceinorder && (pdu_count == 1)) {
320			seq[seq_no].pdu_start = i;
321			seq[seq_no].seq_no = seq_no;
322			seq[seq_no].offset = offset;
323			seq[seq_no].orig_offset = offset;
324		}
325
326		if (check_immediate) {
327			check_immediate = 0;
328			if (!datapduinorder) {
329				pdu[i].type = PDUTYPE_IMMEDIATE;
330				pdu[i++].length = bl->immediate_data_length;
331			}
332			if (!datasequenceinorder) {
333				seq[seq_no].type = SEQTYPE_IMMEDIATE;
334				seq[seq_no].pdu_count = 1;
335				seq[seq_no].xfer_len =
336					bl->immediate_data_length;
337			}
338			offset += bl->immediate_data_length;
339			pdu_count = 0;
340			seq_no++;
341			if (unsolicited_data_length)
342				unsolicited_data_length -=
343					bl->immediate_data_length;
344			continue;
345		}
346		if (unsolicited_data_length > 0) {
347			if ((offset +
348			     conn->conn_ops->MaxRecvDataSegmentLength) >=
349			     cmd->data_length) {
350				if (!datapduinorder) {
351					pdu[i].type = PDUTYPE_UNSOLICITED;
352					pdu[i].length =
353						(cmd->data_length - offset);
354				}
355				if (!datasequenceinorder) {
356					seq[seq_no].type = SEQTYPE_UNSOLICITED;
357					seq[seq_no].pdu_count = pdu_count;
358					seq[seq_no].xfer_len = (burstlength +
359						(cmd->data_length - offset));
360				}
361				unsolicited_data_length -=
362						(cmd->data_length - offset);
363				offset += (cmd->data_length - offset);
364				continue;
365			}
366			if ((offset +
367			     conn->conn_ops->MaxRecvDataSegmentLength) >=
368					conn->sess->sess_ops->FirstBurstLength) {
369				if (!datapduinorder) {
370					pdu[i].type = PDUTYPE_UNSOLICITED;
371					pdu[i++].length =
372					   (conn->sess->sess_ops->FirstBurstLength -
373						offset);
374				}
375				if (!datasequenceinorder) {
376					seq[seq_no].type = SEQTYPE_UNSOLICITED;
377					seq[seq_no].pdu_count = pdu_count;
378					seq[seq_no].xfer_len = (burstlength +
379					   (conn->sess->sess_ops->FirstBurstLength -
380						offset));
381				}
382				unsolicited_data_length -=
383					(conn->sess->sess_ops->FirstBurstLength -
384						offset);
385				offset += (conn->sess->sess_ops->FirstBurstLength -
386						offset);
387				burstlength = 0;
388				pdu_count = 0;
389				seq_no++;
390				continue;
391			}
392
393			if (!datapduinorder) {
394				pdu[i].type = PDUTYPE_UNSOLICITED;
395				pdu[i++].length =
396				     conn->conn_ops->MaxRecvDataSegmentLength;
397			}
398			burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
399			offset += conn->conn_ops->MaxRecvDataSegmentLength;
400			unsolicited_data_length -=
401				conn->conn_ops->MaxRecvDataSegmentLength;
402			continue;
403		}
404		if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
405		     cmd->data_length) {
406			if (!datapduinorder) {
407				pdu[i].type = PDUTYPE_NORMAL;
408				pdu[i].length = (cmd->data_length - offset);
409			}
410			if (!datasequenceinorder) {
411				seq[seq_no].type = SEQTYPE_NORMAL;
412				seq[seq_no].pdu_count = pdu_count;
413				seq[seq_no].xfer_len = (burstlength +
414					(cmd->data_length - offset));
415			}
416			offset += (cmd->data_length - offset);
417			continue;
418		}
419		if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
420		     conn->sess->sess_ops->MaxBurstLength) {
421			if (!datapduinorder) {
422				pdu[i].type = PDUTYPE_NORMAL;
423				pdu[i++].length =
424					(conn->sess->sess_ops->MaxBurstLength -
425						burstlength);
426			}
427			if (!datasequenceinorder) {
428				seq[seq_no].type = SEQTYPE_NORMAL;
429				seq[seq_no].pdu_count = pdu_count;
430				seq[seq_no].xfer_len = (burstlength +
431					(conn->sess->sess_ops->MaxBurstLength -
432					burstlength));
433			}
434			offset += (conn->sess->sess_ops->MaxBurstLength -
435					burstlength);
436			burstlength = 0;
437			pdu_count = 0;
438			seq_no++;
439			continue;
440		}
441
442		if (!datapduinorder) {
443			pdu[i].type = PDUTYPE_NORMAL;
444			pdu[i++].length =
445				conn->conn_ops->MaxRecvDataSegmentLength;
446		}
447		burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
448		offset += conn->conn_ops->MaxRecvDataSegmentLength;
449	}
450
451	if (!datasequenceinorder) {
452		if (bl->data_direction & ISCSI_PDU_WRITE) {
453			if (bl->randomize & RANDOM_R2T_OFFSETS) {
454				if (iscsit_randomize_seq_lists(cmd, bl->type)
455						< 0)
456					return -1;
457			} else
458				iscsit_ordered_seq_lists(cmd, bl->type);
459		} else if (bl->data_direction & ISCSI_PDU_READ) {
460			if (bl->randomize & RANDOM_DATAIN_SEQ_OFFSETS) {
461				if (iscsit_randomize_seq_lists(cmd, bl->type)
462						< 0)
463					return -1;
464			} else
465				iscsit_ordered_seq_lists(cmd, bl->type);
466		}
467#if 0
468		iscsit_dump_seq_list(cmd);
469#endif
470	}
471	if (!datapduinorder) {
472		if (bl->data_direction & ISCSI_PDU_WRITE) {
473			if (bl->randomize & RANDOM_DATAOUT_PDU_OFFSETS) {
474				if (iscsit_randomize_pdu_lists(cmd, bl->type)
475						< 0)
476					return -1;
477			} else
478				iscsit_ordered_pdu_lists(cmd, bl->type);
479		} else if (bl->data_direction & ISCSI_PDU_READ) {
480			if (bl->randomize & RANDOM_DATAIN_PDU_OFFSETS) {
481				if (iscsit_randomize_pdu_lists(cmd, bl->type)
482						< 0)
483					return -1;
484			} else
485				iscsit_ordered_pdu_lists(cmd, bl->type);
486		}
487#if 0
488		iscsit_dump_pdu_list(cmd);
489#endif
490	}
491
492	return 0;
493}
494
495/*
496 *	Only called while DataSequenceInOrder=No or DataPDUInOrder=No.
497 */
498int iscsit_do_build_list(
499	struct iscsi_cmd *cmd,
500	struct iscsi_build_list *bl)
501{
502	u32 pdu_count = 0, seq_count = 1;
503	struct iscsi_conn *conn = cmd->conn;
504	struct iscsi_pdu *pdu = NULL;
505	struct iscsi_seq *seq = NULL;
506
507	iscsit_determine_counts_for_list(cmd, bl, &seq_count, &pdu_count);
508
509	if (!conn->sess->sess_ops->DataSequenceInOrder) {
510		seq = kzalloc(seq_count * sizeof(struct iscsi_seq), GFP_ATOMIC);
511		if (!seq) {
512			pr_err("Unable to allocate struct iscsi_seq list\n");
513			return -1;
514		}
515		cmd->seq_list = seq;
516		cmd->seq_count = seq_count;
517	}
518
519	if (!conn->sess->sess_ops->DataPDUInOrder) {
520		pdu = kzalloc(pdu_count * sizeof(struct iscsi_pdu), GFP_ATOMIC);
521		if (!pdu) {
522			pr_err("Unable to allocate struct iscsi_pdu list.\n");
523			kfree(seq);
524			return -1;
525		}
526		cmd->pdu_list = pdu;
527		cmd->pdu_count = pdu_count;
528	}
529
530	return iscsit_build_pdu_and_seq_list(cmd, bl);
531}
532
533struct iscsi_pdu *iscsit_get_pdu_holder(
534	struct iscsi_cmd *cmd,
535	u32 offset,
536	u32 length)
537{
538	u32 i;
539	struct iscsi_pdu *pdu = NULL;
540
541	if (!cmd->pdu_list) {
542		pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
543		return NULL;
544	}
545
546	pdu = &cmd->pdu_list[0];
547
548	for (i = 0; i < cmd->pdu_count; i++)
549		if ((pdu[i].offset == offset) && (pdu[i].length == length))
550			return &pdu[i];
551
552	pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
553		" %u, Length: %u\n", cmd->init_task_tag, offset, length);
554	return NULL;
555}
556
557struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(
558	struct iscsi_cmd *cmd,
559	struct iscsi_seq *seq)
560{
561	u32 i;
562	struct iscsi_conn *conn = cmd->conn;
563	struct iscsi_pdu *pdu = NULL;
564
565	if (!cmd->pdu_list) {
566		pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
567		return NULL;
568	}
569
570	if (conn->sess->sess_ops->DataSequenceInOrder) {
571redo:
572		pdu = &cmd->pdu_list[cmd->pdu_start];
573
574		for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) {
575#if 0
576			pr_debug("pdu[i].seq_no: %d, pdu[i].pdu"
577				"_send_order: %d, pdu[i].offset: %d,"
578				" pdu[i].length: %d\n", pdu[i].seq_no,
579				pdu[i].pdu_send_order, pdu[i].offset,
580				pdu[i].length);
581#endif
582			if (pdu[i].pdu_send_order == cmd->pdu_send_order) {
583				cmd->pdu_send_order++;
584				return &pdu[i];
585			}
586		}
587
588		cmd->pdu_start += cmd->pdu_send_order;
589		cmd->pdu_send_order = 0;
590		cmd->seq_no++;
591
592		if (cmd->pdu_start < cmd->pdu_count)
593			goto redo;
594
595		pr_err("Command ITT: 0x%08x unable to locate"
596			" struct iscsi_pdu for cmd->pdu_send_order: %u.\n",
597			cmd->init_task_tag, cmd->pdu_send_order);
598		return NULL;
599	} else {
600		if (!seq) {
601			pr_err("struct iscsi_seq is NULL!\n");
602			return NULL;
603		}
604#if 0
605		pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
606			" seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count,
607			seq->seq_no);
608#endif
609		pdu = &cmd->pdu_list[seq->pdu_start];
610
611		if (seq->pdu_send_order == seq->pdu_count) {
612			pr_err("Command ITT: 0x%08x seq->pdu_send"
613				"_order: %u equals seq->pdu_count: %u\n",
614				cmd->init_task_tag, seq->pdu_send_order,
615				seq->pdu_count);
616			return NULL;
617		}
618
619		for (i = 0; i < seq->pdu_count; i++) {
620			if (pdu[i].pdu_send_order == seq->pdu_send_order) {
621				seq->pdu_send_order++;
622				return &pdu[i];
623			}
624		}
625
626		pr_err("Command ITT: 0x%08x unable to locate iscsi"
627			"_pdu_t for seq->pdu_send_order: %u.\n",
628			cmd->init_task_tag, seq->pdu_send_order);
629		return NULL;
630	}
631
632	return NULL;
633}
634
635struct iscsi_seq *iscsit_get_seq_holder(
636	struct iscsi_cmd *cmd,
637	u32 offset,
638	u32 length)
639{
640	u32 i;
641
642	if (!cmd->seq_list) {
643		pr_err("struct iscsi_cmd->seq_list is NULL!\n");
644		return NULL;
645	}
646
647	for (i = 0; i < cmd->seq_count; i++) {
648#if 0
649		pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
650			"xfer_len: %d, seq_list[i].seq_no %u\n",
651			cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len,
652			cmd->seq_list[i].seq_no);
653#endif
654		if ((cmd->seq_list[i].orig_offset +
655				cmd->seq_list[i].xfer_len) >=
656				(offset + length))
657			return &cmd->seq_list[i];
658	}
659
660	pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
661		" Offset: %u, Length: %u\n", cmd->init_task_tag, offset,
662		length);
663	return NULL;
664}
665