1 /*******************************************************************************
2 * This file contains main functions related to iSCSI DataSequenceInOrder=No
3 * and DataPDUInOrder=No.
5 \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
7 * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
9 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
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.
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 ******************************************************************************/
22 #include <linux/slab.h>
23 #include <linux/random.h>
25 #include "iscsi_target_core.h"
26 #include "iscsi_target_util.h"
27 #include "iscsi_target_seq_pdu_list.h"
29 #define OFFLOAD_BUF_SIZE 32768
31 void iscsit_dump_seq_list(struct iscsi_cmd
*cmd
)
34 struct iscsi_seq
*seq
;
36 pr_debug("Dumping Sequence List for ITT: 0x%08x:\n",
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
,
49 void iscsit_dump_pdu_list(struct iscsi_cmd
*cmd
)
52 struct iscsi_pdu
*pdu
;
54 pr_debug("Dumping PDU List for ITT: 0x%08x:\n",
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
);
65 static void iscsit_ordered_seq_lists(
66 struct iscsi_cmd
*cmd
,
71 for (i
= 0; i
< cmd
->seq_count
; i
++) {
72 if (cmd
->seq_list
[i
].type
!= SEQTYPE_NORMAL
)
74 cmd
->seq_list
[i
].seq_send_order
= seq_count
++;
78 static void iscsit_ordered_pdu_lists(
79 struct iscsi_cmd
*cmd
,
82 u32 i
, pdu_send_order
= 0, seq_no
= 0;
84 for (i
= 0; i
< cmd
->pdu_count
; i
++) {
86 if (cmd
->pdu_list
[i
].seq_no
== seq_no
) {
87 cmd
->pdu_list
[i
].pdu_send_order
= pdu_send_order
++;
97 * Generate count random values into array.
98 * Use 0x80000000 to mark generates valued in array[].
100 static void iscsit_create_random_array(u32
*array
, u32 count
)
109 for (i
= 0; i
< count
; i
++) {
111 get_random_bytes(&j
, sizeof(u32
));
112 j
= (1 + (int) (9999 + 1) - j
) % count
;
113 for (k
= 0; k
< i
+ 1; k
++) {
115 if ((array
[k
] & 0x80000000) && (array
[k
] == j
))
121 for (i
= 0; i
< count
; i
++)
122 array
[i
] &= ~0x80000000;
125 static int iscsit_randomize_pdu_lists(
126 struct iscsi_cmd
*cmd
,
130 u32
*array
, pdu_count
, seq_count
= 0, seq_no
= 0, seq_offset
= 0;
132 for (pdu_count
= 0; pdu_count
< cmd
->pdu_count
; pdu_count
++) {
134 if (cmd
->pdu_list
[pdu_count
].seq_no
== seq_no
) {
138 array
= kzalloc(seq_count
* sizeof(u32
), GFP_KERNEL
);
140 pr_err("Unable to allocate memory"
141 " for random array.\n");
144 iscsit_create_random_array(array
, seq_count
);
146 for (i
= 0; i
< seq_count
; i
++)
147 cmd
->pdu_list
[seq_offset
+i
].pdu_send_order
= array
[i
];
151 seq_offset
+= seq_count
;
158 array
= kzalloc(seq_count
* sizeof(u32
), GFP_KERNEL
);
160 pr_err("Unable to allocate memory for"
164 iscsit_create_random_array(array
, seq_count
);
166 for (i
= 0; i
< seq_count
; i
++)
167 cmd
->pdu_list
[seq_offset
+i
].pdu_send_order
= array
[i
];
175 static int iscsit_randomize_seq_lists(
176 struct iscsi_cmd
*cmd
,
180 u32
*array
, seq_count
= cmd
->seq_count
;
182 if ((type
== PDULIST_IMMEDIATE
) || (type
== PDULIST_UNSOLICITED
))
184 else if (type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
)
190 array
= kzalloc(seq_count
* sizeof(u32
), GFP_KERNEL
);
192 pr_err("Unable to allocate memory for random array.\n");
195 iscsit_create_random_array(array
, seq_count
);
197 for (i
= 0; i
< cmd
->seq_count
; i
++) {
198 if (cmd
->seq_list
[i
].type
!= SEQTYPE_NORMAL
)
200 cmd
->seq_list
[i
].seq_send_order
= array
[j
++];
207 static void iscsit_determine_counts_for_list(
208 struct iscsi_cmd
*cmd
,
209 struct iscsi_build_list
*bl
,
213 int check_immediate
= 0;
214 u32 burstlength
= 0, offset
= 0;
215 u32 unsolicited_data_length
= 0;
216 struct iscsi_conn
*conn
= cmd
->conn
;
218 if ((bl
->type
== PDULIST_IMMEDIATE
) ||
219 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
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
;
228 while (offset
< cmd
->data_length
) {
231 if (check_immediate
) {
233 offset
+= bl
->immediate_data_length
;
235 if (unsolicited_data_length
)
236 unsolicited_data_length
-=
237 bl
->immediate_data_length
;
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
);
248 if ((offset
+ conn
->conn_ops
->MaxRecvDataSegmentLength
)
249 >= conn
->sess
->sess_ops
->FirstBurstLength
) {
250 unsolicited_data_length
-=
251 (conn
->sess
->sess_ops
->FirstBurstLength
-
253 offset
+= (conn
->sess
->sess_ops
->FirstBurstLength
-
260 offset
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
261 unsolicited_data_length
-=
262 conn
->conn_ops
->MaxRecvDataSegmentLength
;
265 if ((offset
+ conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
267 offset
+= (cmd
->data_length
- offset
);
270 if ((burstlength
+ conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
271 conn
->sess
->sess_ops
->MaxBurstLength
) {
272 offset
+= (conn
->sess
->sess_ops
->MaxBurstLength
-
279 burstlength
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
280 offset
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
286 * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
287 * and DataPDUInOrder=No.
289 static int iscsit_build_pdu_and_seq_list(
290 struct iscsi_cmd
*cmd
,
291 struct iscsi_build_list
*bl
)
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
;
300 datapduinorder
= conn
->sess
->sess_ops
->DataPDUInOrder
;
301 datasequenceinorder
= conn
->sess
->sess_ops
->DataSequenceInOrder
;
303 if ((bl
->type
== PDULIST_IMMEDIATE
) ||
304 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
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
;
313 while (offset
< cmd
->data_length
) {
315 if (!datapduinorder
) {
316 pdu
[i
].offset
= offset
;
317 pdu
[i
].seq_no
= seq_no
;
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
;
326 if (check_immediate
) {
328 if (!datapduinorder
) {
329 pdu
[i
].type
= PDUTYPE_IMMEDIATE
;
330 pdu
[i
++].length
= bl
->immediate_data_length
;
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
;
338 offset
+= bl
->immediate_data_length
;
341 if (unsolicited_data_length
)
342 unsolicited_data_length
-=
343 bl
->immediate_data_length
;
346 if (unsolicited_data_length
> 0) {
348 conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
350 if (!datapduinorder
) {
351 pdu
[i
].type
= PDUTYPE_UNSOLICITED
;
353 (cmd
->data_length
- offset
);
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
));
361 unsolicited_data_length
-=
362 (cmd
->data_length
- offset
);
363 offset
+= (cmd
->data_length
- offset
);
367 conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
368 conn
->sess
->sess_ops
->FirstBurstLength
) {
369 if (!datapduinorder
) {
370 pdu
[i
].type
= PDUTYPE_UNSOLICITED
;
372 (conn
->sess
->sess_ops
->FirstBurstLength
-
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
-
382 unsolicited_data_length
-=
383 (conn
->sess
->sess_ops
->FirstBurstLength
-
385 offset
+= (conn
->sess
->sess_ops
->FirstBurstLength
-
393 if (!datapduinorder
) {
394 pdu
[i
].type
= PDUTYPE_UNSOLICITED
;
396 conn
->conn_ops
->MaxRecvDataSegmentLength
;
398 burstlength
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
399 offset
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
400 unsolicited_data_length
-=
401 conn
->conn_ops
->MaxRecvDataSegmentLength
;
404 if ((offset
+ conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
406 if (!datapduinorder
) {
407 pdu
[i
].type
= PDUTYPE_NORMAL
;
408 pdu
[i
].length
= (cmd
->data_length
- offset
);
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
));
416 offset
+= (cmd
->data_length
- offset
);
419 if ((burstlength
+ conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
420 conn
->sess
->sess_ops
->MaxBurstLength
) {
421 if (!datapduinorder
) {
422 pdu
[i
].type
= PDUTYPE_NORMAL
;
424 (conn
->sess
->sess_ops
->MaxBurstLength
-
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
-
434 offset
+= (conn
->sess
->sess_ops
->MaxBurstLength
-
442 if (!datapduinorder
) {
443 pdu
[i
].type
= PDUTYPE_NORMAL
;
445 conn
->conn_ops
->MaxRecvDataSegmentLength
;
447 burstlength
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
448 offset
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
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
)
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
)
465 iscsit_ordered_seq_lists(cmd
, bl
->type
);
468 iscsit_dump_seq_list(cmd
);
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
)
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
)
485 iscsit_ordered_pdu_lists(cmd
, bl
->type
);
488 iscsit_dump_pdu_list(cmd
);
496 * Only called while DataSequenceInOrder=No or DataPDUInOrder=No.
498 int iscsit_do_build_list(
499 struct iscsi_cmd
*cmd
,
500 struct iscsi_build_list
*bl
)
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
;
507 iscsit_determine_counts_for_list(cmd
, bl
, &seq_count
, &pdu_count
);
509 if (!conn
->sess
->sess_ops
->DataSequenceInOrder
) {
510 seq
= kzalloc(seq_count
* sizeof(struct iscsi_seq
), GFP_ATOMIC
);
512 pr_err("Unable to allocate struct iscsi_seq list\n");
516 cmd
->seq_count
= seq_count
;
519 if (!conn
->sess
->sess_ops
->DataPDUInOrder
) {
520 pdu
= kzalloc(pdu_count
* sizeof(struct iscsi_pdu
), GFP_ATOMIC
);
522 pr_err("Unable to allocate struct iscsi_pdu list.\n");
527 cmd
->pdu_count
= pdu_count
;
530 return iscsit_build_pdu_and_seq_list(cmd
, bl
);
533 struct iscsi_pdu
*iscsit_get_pdu_holder(
534 struct iscsi_cmd
*cmd
,
539 struct iscsi_pdu
*pdu
= NULL
;
541 if (!cmd
->pdu_list
) {
542 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
546 pdu
= &cmd
->pdu_list
[0];
548 for (i
= 0; i
< cmd
->pdu_count
; i
++)
549 if ((pdu
[i
].offset
== offset
) && (pdu
[i
].length
== length
))
552 pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
553 " %u, Length: %u\n", cmd
->init_task_tag
, offset
, length
);
557 struct iscsi_pdu
*iscsit_get_pdu_holder_for_seq(
558 struct iscsi_cmd
*cmd
,
559 struct iscsi_seq
*seq
)
562 struct iscsi_conn
*conn
= cmd
->conn
;
563 struct iscsi_pdu
*pdu
= NULL
;
565 if (!cmd
->pdu_list
) {
566 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
570 if (conn
->sess
->sess_ops
->DataSequenceInOrder
) {
572 pdu
= &cmd
->pdu_list
[cmd
->pdu_start
];
574 for (i
= 0; pdu
[i
].seq_no
!= cmd
->seq_no
; i
++) {
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
,
582 if (pdu
[i
].pdu_send_order
== cmd
->pdu_send_order
) {
583 cmd
->pdu_send_order
++;
588 cmd
->pdu_start
+= cmd
->pdu_send_order
;
589 cmd
->pdu_send_order
= 0;
592 if (cmd
->pdu_start
< cmd
->pdu_count
)
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
);
601 pr_err("struct iscsi_seq is NULL!\n");
605 pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
606 " seq->seq_no: %d\n", seq
->pdu_start
, seq
->pdu_count
,
609 pdu
= &cmd
->pdu_list
[seq
->pdu_start
];
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
,
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
++;
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
);
635 struct iscsi_seq
*iscsit_get_seq_holder(
636 struct iscsi_cmd
*cmd
,
642 if (!cmd
->seq_list
) {
643 pr_err("struct iscsi_cmd->seq_list is NULL!\n");
647 for (i
= 0; i
< cmd
->seq_count
; i
++) {
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
);
654 if ((cmd
->seq_list
[i
].orig_offset
+
655 cmd
->seq_list
[i
].xfer_len
) >=
657 return &cmd
->seq_list
[i
];
660 pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
661 " Offset: %u, Length: %u\n", cmd
->init_task_tag
, offset
,