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_tpg.h"
28 #include "iscsi_target_seq_pdu_list.h"
30 #define OFFLOAD_BUF_SIZE 32768
33 static void iscsit_dump_seq_list(struct iscsi_cmd
*cmd
)
36 struct iscsi_seq
*seq
;
38 pr_debug("Dumping Sequence List for ITT: 0x%08x:\n",
41 for (i
= 0; i
< cmd
->seq_count
; i
++) {
42 seq
= &cmd
->seq_list
[i
];
43 pr_debug("i: %d, pdu_start: %d, pdu_count: %d,"
44 " offset: %d, xfer_len: %d, seq_send_order: %d,"
45 " seq_no: %d\n", i
, seq
->pdu_start
, seq
->pdu_count
,
46 seq
->offset
, seq
->xfer_len
, seq
->seq_send_order
,
51 static void iscsit_dump_pdu_list(struct iscsi_cmd
*cmd
)
54 struct iscsi_pdu
*pdu
;
56 pr_debug("Dumping PDU List for ITT: 0x%08x:\n",
59 for (i
= 0; i
< cmd
->pdu_count
; i
++) {
60 pdu
= &cmd
->pdu_list
[i
];
61 pr_debug("i: %d, offset: %d, length: %d,"
62 " pdu_send_order: %d, seq_no: %d\n", i
, pdu
->offset
,
63 pdu
->length
, pdu
->pdu_send_order
, pdu
->seq_no
);
67 static void iscsit_dump_seq_list(struct iscsi_cmd
*cmd
) {}
68 static void iscsit_dump_pdu_list(struct iscsi_cmd
*cmd
) {}
71 static void iscsit_ordered_seq_lists(
72 struct iscsi_cmd
*cmd
,
77 for (i
= 0; i
< cmd
->seq_count
; i
++) {
78 if (cmd
->seq_list
[i
].type
!= SEQTYPE_NORMAL
)
80 cmd
->seq_list
[i
].seq_send_order
= seq_count
++;
84 static void iscsit_ordered_pdu_lists(
85 struct iscsi_cmd
*cmd
,
88 u32 i
, pdu_send_order
= 0, seq_no
= 0;
90 for (i
= 0; i
< cmd
->pdu_count
; i
++) {
92 if (cmd
->pdu_list
[i
].seq_no
== seq_no
) {
93 cmd
->pdu_list
[i
].pdu_send_order
= pdu_send_order
++;
103 * Generate count random values into array.
104 * Use 0x80000000 to mark generates valued in array[].
106 static void iscsit_create_random_array(u32
*array
, u32 count
)
115 for (i
= 0; i
< count
; i
++) {
117 get_random_bytes(&j
, sizeof(u32
));
118 j
= (1 + (int) (9999 + 1) - j
) % count
;
119 for (k
= 0; k
< i
+ 1; k
++) {
121 if ((array
[k
] & 0x80000000) && (array
[k
] == j
))
127 for (i
= 0; i
< count
; i
++)
128 array
[i
] &= ~0x80000000;
131 static int iscsit_randomize_pdu_lists(
132 struct iscsi_cmd
*cmd
,
136 u32
*array
, pdu_count
, seq_count
= 0, seq_no
= 0, seq_offset
= 0;
138 for (pdu_count
= 0; pdu_count
< cmd
->pdu_count
; pdu_count
++) {
140 if (cmd
->pdu_list
[pdu_count
].seq_no
== seq_no
) {
144 array
= kcalloc(seq_count
, sizeof(u32
), GFP_KERNEL
);
146 pr_err("Unable to allocate memory"
147 " for random array.\n");
150 iscsit_create_random_array(array
, seq_count
);
152 for (i
= 0; i
< seq_count
; i
++)
153 cmd
->pdu_list
[seq_offset
+i
].pdu_send_order
= array
[i
];
157 seq_offset
+= seq_count
;
164 array
= kcalloc(seq_count
, sizeof(u32
), GFP_KERNEL
);
166 pr_err("Unable to allocate memory for"
170 iscsit_create_random_array(array
, seq_count
);
172 for (i
= 0; i
< seq_count
; i
++)
173 cmd
->pdu_list
[seq_offset
+i
].pdu_send_order
= array
[i
];
181 static int iscsit_randomize_seq_lists(
182 struct iscsi_cmd
*cmd
,
186 u32
*array
, seq_count
= cmd
->seq_count
;
188 if ((type
== PDULIST_IMMEDIATE
) || (type
== PDULIST_UNSOLICITED
))
190 else if (type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
)
196 array
= kcalloc(seq_count
, sizeof(u32
), GFP_KERNEL
);
198 pr_err("Unable to allocate memory for random array.\n");
201 iscsit_create_random_array(array
, seq_count
);
203 for (i
= 0; i
< cmd
->seq_count
; i
++) {
204 if (cmd
->seq_list
[i
].type
!= SEQTYPE_NORMAL
)
206 cmd
->seq_list
[i
].seq_send_order
= array
[j
++];
213 static void iscsit_determine_counts_for_list(
214 struct iscsi_cmd
*cmd
,
215 struct iscsi_build_list
*bl
,
219 int check_immediate
= 0;
220 u32 burstlength
= 0, offset
= 0;
221 u32 unsolicited_data_length
= 0;
223 struct iscsi_conn
*conn
= cmd
->conn
;
225 if (cmd
->se_cmd
.data_direction
== DMA_TO_DEVICE
)
226 mdsl
= cmd
->conn
->conn_ops
->MaxXmitDataSegmentLength
;
228 mdsl
= cmd
->conn
->conn_ops
->MaxRecvDataSegmentLength
;
230 if ((bl
->type
== PDULIST_IMMEDIATE
) ||
231 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
234 if ((bl
->type
== PDULIST_UNSOLICITED
) ||
235 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
236 unsolicited_data_length
= min(cmd
->se_cmd
.data_length
,
237 conn
->sess
->sess_ops
->FirstBurstLength
);
239 while (offset
< cmd
->se_cmd
.data_length
) {
242 if (check_immediate
) {
244 offset
+= bl
->immediate_data_length
;
246 if (unsolicited_data_length
)
247 unsolicited_data_length
-=
248 bl
->immediate_data_length
;
251 if (unsolicited_data_length
> 0) {
252 if ((offset
+ mdsl
) >= cmd
->se_cmd
.data_length
) {
253 unsolicited_data_length
-=
254 (cmd
->se_cmd
.data_length
- offset
);
255 offset
+= (cmd
->se_cmd
.data_length
- offset
);
259 >= conn
->sess
->sess_ops
->FirstBurstLength
) {
260 unsolicited_data_length
-=
261 (conn
->sess
->sess_ops
->FirstBurstLength
-
263 offset
+= (conn
->sess
->sess_ops
->FirstBurstLength
-
271 unsolicited_data_length
-= mdsl
;
274 if ((offset
+ mdsl
) >= cmd
->se_cmd
.data_length
) {
275 offset
+= (cmd
->se_cmd
.data_length
- offset
);
278 if ((burstlength
+ mdsl
) >=
279 conn
->sess
->sess_ops
->MaxBurstLength
) {
280 offset
+= (conn
->sess
->sess_ops
->MaxBurstLength
-
294 * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
295 * or DataPDUInOrder=No.
297 static int iscsit_do_build_pdu_and_seq_lists(
298 struct iscsi_cmd
*cmd
,
299 struct iscsi_build_list
*bl
)
301 int check_immediate
= 0, datapduinorder
, datasequenceinorder
;
302 u32 burstlength
= 0, offset
= 0, i
= 0, mdsl
;
303 u32 pdu_count
= 0, seq_no
= 0, unsolicited_data_length
= 0;
304 struct iscsi_conn
*conn
= cmd
->conn
;
305 struct iscsi_pdu
*pdu
= cmd
->pdu_list
;
306 struct iscsi_seq
*seq
= cmd
->seq_list
;
308 if (cmd
->se_cmd
.data_direction
== DMA_TO_DEVICE
)
309 mdsl
= cmd
->conn
->conn_ops
->MaxXmitDataSegmentLength
;
311 mdsl
= cmd
->conn
->conn_ops
->MaxRecvDataSegmentLength
;
313 datapduinorder
= conn
->sess
->sess_ops
->DataPDUInOrder
;
314 datasequenceinorder
= conn
->sess
->sess_ops
->DataSequenceInOrder
;
316 if ((bl
->type
== PDULIST_IMMEDIATE
) ||
317 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
320 if ((bl
->type
== PDULIST_UNSOLICITED
) ||
321 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
322 unsolicited_data_length
= min(cmd
->se_cmd
.data_length
,
323 conn
->sess
->sess_ops
->FirstBurstLength
);
325 while (offset
< cmd
->se_cmd
.data_length
) {
327 if (!datapduinorder
) {
328 pdu
[i
].offset
= offset
;
329 pdu
[i
].seq_no
= seq_no
;
331 if (!datasequenceinorder
&& (pdu_count
== 1)) {
332 seq
[seq_no
].pdu_start
= i
;
333 seq
[seq_no
].seq_no
= seq_no
;
334 seq
[seq_no
].offset
= offset
;
335 seq
[seq_no
].orig_offset
= offset
;
338 if (check_immediate
) {
340 if (!datapduinorder
) {
341 pdu
[i
].type
= PDUTYPE_IMMEDIATE
;
342 pdu
[i
++].length
= bl
->immediate_data_length
;
344 if (!datasequenceinorder
) {
345 seq
[seq_no
].type
= SEQTYPE_IMMEDIATE
;
346 seq
[seq_no
].pdu_count
= 1;
347 seq
[seq_no
].xfer_len
=
348 bl
->immediate_data_length
;
350 offset
+= bl
->immediate_data_length
;
353 if (unsolicited_data_length
)
354 unsolicited_data_length
-=
355 bl
->immediate_data_length
;
358 if (unsolicited_data_length
> 0) {
359 if ((offset
+ mdsl
) >= cmd
->se_cmd
.data_length
) {
360 if (!datapduinorder
) {
361 pdu
[i
].type
= PDUTYPE_UNSOLICITED
;
363 (cmd
->se_cmd
.data_length
- offset
);
365 if (!datasequenceinorder
) {
366 seq
[seq_no
].type
= SEQTYPE_UNSOLICITED
;
367 seq
[seq_no
].pdu_count
= pdu_count
;
368 seq
[seq_no
].xfer_len
= (burstlength
+
369 (cmd
->se_cmd
.data_length
- offset
));
371 unsolicited_data_length
-=
372 (cmd
->se_cmd
.data_length
- offset
);
373 offset
+= (cmd
->se_cmd
.data_length
- offset
);
376 if ((offset
+ mdsl
) >=
377 conn
->sess
->sess_ops
->FirstBurstLength
) {
378 if (!datapduinorder
) {
379 pdu
[i
].type
= PDUTYPE_UNSOLICITED
;
381 (conn
->sess
->sess_ops
->FirstBurstLength
-
384 if (!datasequenceinorder
) {
385 seq
[seq_no
].type
= SEQTYPE_UNSOLICITED
;
386 seq
[seq_no
].pdu_count
= pdu_count
;
387 seq
[seq_no
].xfer_len
= (burstlength
+
388 (conn
->sess
->sess_ops
->FirstBurstLength
-
391 unsolicited_data_length
-=
392 (conn
->sess
->sess_ops
->FirstBurstLength
-
394 offset
+= (conn
->sess
->sess_ops
->FirstBurstLength
-
402 if (!datapduinorder
) {
403 pdu
[i
].type
= PDUTYPE_UNSOLICITED
;
404 pdu
[i
++].length
= mdsl
;
408 unsolicited_data_length
-= mdsl
;
411 if ((offset
+ mdsl
) >= cmd
->se_cmd
.data_length
) {
412 if (!datapduinorder
) {
413 pdu
[i
].type
= PDUTYPE_NORMAL
;
414 pdu
[i
].length
= (cmd
->se_cmd
.data_length
- offset
);
416 if (!datasequenceinorder
) {
417 seq
[seq_no
].type
= SEQTYPE_NORMAL
;
418 seq
[seq_no
].pdu_count
= pdu_count
;
419 seq
[seq_no
].xfer_len
= (burstlength
+
420 (cmd
->se_cmd
.data_length
- offset
));
422 offset
+= (cmd
->se_cmd
.data_length
- offset
);
425 if ((burstlength
+ mdsl
) >=
426 conn
->sess
->sess_ops
->MaxBurstLength
) {
427 if (!datapduinorder
) {
428 pdu
[i
].type
= PDUTYPE_NORMAL
;
430 (conn
->sess
->sess_ops
->MaxBurstLength
-
433 if (!datasequenceinorder
) {
434 seq
[seq_no
].type
= SEQTYPE_NORMAL
;
435 seq
[seq_no
].pdu_count
= pdu_count
;
436 seq
[seq_no
].xfer_len
= (burstlength
+
437 (conn
->sess
->sess_ops
->MaxBurstLength
-
440 offset
+= (conn
->sess
->sess_ops
->MaxBurstLength
-
448 if (!datapduinorder
) {
449 pdu
[i
].type
= PDUTYPE_NORMAL
;
450 pdu
[i
++].length
= mdsl
;
456 if (!datasequenceinorder
) {
457 if (bl
->data_direction
& ISCSI_PDU_WRITE
) {
458 if (bl
->randomize
& RANDOM_R2T_OFFSETS
) {
459 if (iscsit_randomize_seq_lists(cmd
, bl
->type
)
463 iscsit_ordered_seq_lists(cmd
, bl
->type
);
464 } else if (bl
->data_direction
& ISCSI_PDU_READ
) {
465 if (bl
->randomize
& RANDOM_DATAIN_SEQ_OFFSETS
) {
466 if (iscsit_randomize_seq_lists(cmd
, bl
->type
)
470 iscsit_ordered_seq_lists(cmd
, bl
->type
);
473 iscsit_dump_seq_list(cmd
);
475 if (!datapduinorder
) {
476 if (bl
->data_direction
& ISCSI_PDU_WRITE
) {
477 if (bl
->randomize
& RANDOM_DATAOUT_PDU_OFFSETS
) {
478 if (iscsit_randomize_pdu_lists(cmd
, bl
->type
)
482 iscsit_ordered_pdu_lists(cmd
, bl
->type
);
483 } else if (bl
->data_direction
& ISCSI_PDU_READ
) {
484 if (bl
->randomize
& RANDOM_DATAIN_PDU_OFFSETS
) {
485 if (iscsit_randomize_pdu_lists(cmd
, bl
->type
)
489 iscsit_ordered_pdu_lists(cmd
, bl
->type
);
492 iscsit_dump_pdu_list(cmd
);
498 int iscsit_build_pdu_and_seq_lists(
499 struct iscsi_cmd
*cmd
,
500 u32 immediate_data_length
)
502 struct iscsi_build_list bl
;
503 u32 pdu_count
= 0, seq_count
= 1;
504 struct iscsi_conn
*conn
= cmd
->conn
;
505 struct iscsi_pdu
*pdu
= NULL
;
506 struct iscsi_seq
*seq
= NULL
;
508 struct iscsi_session
*sess
= conn
->sess
;
509 struct iscsi_node_attrib
*na
;
512 * Do nothing if no OOO shenanigans
514 if (sess
->sess_ops
->DataSequenceInOrder
&&
515 sess
->sess_ops
->DataPDUInOrder
)
518 if (cmd
->data_direction
== DMA_NONE
)
521 na
= iscsit_tpg_get_node_attrib(sess
);
522 memset(&bl
, 0, sizeof(struct iscsi_build_list
));
524 if (cmd
->data_direction
== DMA_FROM_DEVICE
) {
525 bl
.data_direction
= ISCSI_PDU_READ
;
526 bl
.type
= PDULIST_NORMAL
;
527 if (na
->random_datain_pdu_offsets
)
528 bl
.randomize
|= RANDOM_DATAIN_PDU_OFFSETS
;
529 if (na
->random_datain_seq_offsets
)
530 bl
.randomize
|= RANDOM_DATAIN_SEQ_OFFSETS
;
532 bl
.data_direction
= ISCSI_PDU_WRITE
;
533 bl
.immediate_data_length
= immediate_data_length
;
534 if (na
->random_r2t_offsets
)
535 bl
.randomize
|= RANDOM_R2T_OFFSETS
;
537 if (!cmd
->immediate_data
&& !cmd
->unsolicited_data
)
538 bl
.type
= PDULIST_NORMAL
;
539 else if (cmd
->immediate_data
&& !cmd
->unsolicited_data
)
540 bl
.type
= PDULIST_IMMEDIATE
;
541 else if (!cmd
->immediate_data
&& cmd
->unsolicited_data
)
542 bl
.type
= PDULIST_UNSOLICITED
;
543 else if (cmd
->immediate_data
&& cmd
->unsolicited_data
)
544 bl
.type
= PDULIST_IMMEDIATE_AND_UNSOLICITED
;
547 iscsit_determine_counts_for_list(cmd
, &bl
, &seq_count
, &pdu_count
);
549 if (!conn
->sess
->sess_ops
->DataSequenceInOrder
) {
550 seq
= kcalloc(seq_count
, sizeof(struct iscsi_seq
), GFP_ATOMIC
);
552 pr_err("Unable to allocate struct iscsi_seq list\n");
556 cmd
->seq_count
= seq_count
;
559 if (!conn
->sess
->sess_ops
->DataPDUInOrder
) {
560 pdu
= kcalloc(pdu_count
, sizeof(struct iscsi_pdu
), GFP_ATOMIC
);
562 pr_err("Unable to allocate struct iscsi_pdu list.\n");
567 cmd
->pdu_count
= pdu_count
;
570 return iscsit_do_build_pdu_and_seq_lists(cmd
, &bl
);
573 struct iscsi_pdu
*iscsit_get_pdu_holder(
574 struct iscsi_cmd
*cmd
,
579 struct iscsi_pdu
*pdu
= NULL
;
581 if (!cmd
->pdu_list
) {
582 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
586 pdu
= &cmd
->pdu_list
[0];
588 for (i
= 0; i
< cmd
->pdu_count
; i
++)
589 if ((pdu
[i
].offset
== offset
) && (pdu
[i
].length
== length
))
592 pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
593 " %u, Length: %u\n", cmd
->init_task_tag
, offset
, length
);
597 struct iscsi_pdu
*iscsit_get_pdu_holder_for_seq(
598 struct iscsi_cmd
*cmd
,
599 struct iscsi_seq
*seq
)
602 struct iscsi_conn
*conn
= cmd
->conn
;
603 struct iscsi_pdu
*pdu
= NULL
;
605 if (!cmd
->pdu_list
) {
606 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
610 if (conn
->sess
->sess_ops
->DataSequenceInOrder
) {
612 pdu
= &cmd
->pdu_list
[cmd
->pdu_start
];
614 for (i
= 0; pdu
[i
].seq_no
!= cmd
->seq_no
; i
++) {
615 pr_debug("pdu[i].seq_no: %d, pdu[i].pdu"
616 "_send_order: %d, pdu[i].offset: %d,"
617 " pdu[i].length: %d\n", pdu
[i
].seq_no
,
618 pdu
[i
].pdu_send_order
, pdu
[i
].offset
,
621 if (pdu
[i
].pdu_send_order
== cmd
->pdu_send_order
) {
622 cmd
->pdu_send_order
++;
627 cmd
->pdu_start
+= cmd
->pdu_send_order
;
628 cmd
->pdu_send_order
= 0;
631 if (cmd
->pdu_start
< cmd
->pdu_count
)
634 pr_err("Command ITT: 0x%08x unable to locate"
635 " struct iscsi_pdu for cmd->pdu_send_order: %u.\n",
636 cmd
->init_task_tag
, cmd
->pdu_send_order
);
640 pr_err("struct iscsi_seq is NULL!\n");
644 pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
645 " seq->seq_no: %d\n", seq
->pdu_start
, seq
->pdu_count
,
648 pdu
= &cmd
->pdu_list
[seq
->pdu_start
];
650 if (seq
->pdu_send_order
== seq
->pdu_count
) {
651 pr_err("Command ITT: 0x%08x seq->pdu_send"
652 "_order: %u equals seq->pdu_count: %u\n",
653 cmd
->init_task_tag
, seq
->pdu_send_order
,
658 for (i
= 0; i
< seq
->pdu_count
; i
++) {
659 if (pdu
[i
].pdu_send_order
== seq
->pdu_send_order
) {
660 seq
->pdu_send_order
++;
665 pr_err("Command ITT: 0x%08x unable to locate iscsi"
666 "_pdu_t for seq->pdu_send_order: %u.\n",
667 cmd
->init_task_tag
, seq
->pdu_send_order
);
674 struct iscsi_seq
*iscsit_get_seq_holder(
675 struct iscsi_cmd
*cmd
,
681 if (!cmd
->seq_list
) {
682 pr_err("struct iscsi_cmd->seq_list is NULL!\n");
686 for (i
= 0; i
< cmd
->seq_count
; i
++) {
687 pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
688 "xfer_len: %d, seq_list[i].seq_no %u\n",
689 cmd
->seq_list
[i
].orig_offset
, cmd
->seq_list
[i
].xfer_len
,
690 cmd
->seq_list
[i
].seq_no
);
692 if ((cmd
->seq_list
[i
].orig_offset
+
693 cmd
->seq_list
[i
].xfer_len
) >=
695 return &cmd
->seq_list
[i
];
698 pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
699 " Offset: %u, Length: %u\n", cmd
->init_task_tag
, offset
,