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;
222 struct iscsi_conn
*conn
= cmd
->conn
;
224 if ((bl
->type
== PDULIST_IMMEDIATE
) ||
225 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
228 if ((bl
->type
== PDULIST_UNSOLICITED
) ||
229 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
230 unsolicited_data_length
= min(cmd
->se_cmd
.data_length
,
231 conn
->sess
->sess_ops
->FirstBurstLength
);
233 while (offset
< cmd
->se_cmd
.data_length
) {
236 if (check_immediate
) {
238 offset
+= bl
->immediate_data_length
;
240 if (unsolicited_data_length
)
241 unsolicited_data_length
-=
242 bl
->immediate_data_length
;
245 if (unsolicited_data_length
> 0) {
246 if ((offset
+ conn
->conn_ops
->MaxRecvDataSegmentLength
)
247 >= cmd
->se_cmd
.data_length
) {
248 unsolicited_data_length
-=
249 (cmd
->se_cmd
.data_length
- offset
);
250 offset
+= (cmd
->se_cmd
.data_length
- offset
);
253 if ((offset
+ conn
->conn_ops
->MaxRecvDataSegmentLength
)
254 >= conn
->sess
->sess_ops
->FirstBurstLength
) {
255 unsolicited_data_length
-=
256 (conn
->sess
->sess_ops
->FirstBurstLength
-
258 offset
+= (conn
->sess
->sess_ops
->FirstBurstLength
-
265 offset
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
266 unsolicited_data_length
-=
267 conn
->conn_ops
->MaxRecvDataSegmentLength
;
270 if ((offset
+ conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
271 cmd
->se_cmd
.data_length
) {
272 offset
+= (cmd
->se_cmd
.data_length
- offset
);
275 if ((burstlength
+ conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
276 conn
->sess
->sess_ops
->MaxBurstLength
) {
277 offset
+= (conn
->sess
->sess_ops
->MaxBurstLength
-
284 burstlength
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
285 offset
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
291 * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
292 * or DataPDUInOrder=No.
294 static int iscsit_do_build_pdu_and_seq_lists(
295 struct iscsi_cmd
*cmd
,
296 struct iscsi_build_list
*bl
)
298 int check_immediate
= 0, datapduinorder
, datasequenceinorder
;
299 u32 burstlength
= 0, offset
= 0, i
= 0;
300 u32 pdu_count
= 0, seq_no
= 0, unsolicited_data_length
= 0;
301 struct iscsi_conn
*conn
= cmd
->conn
;
302 struct iscsi_pdu
*pdu
= cmd
->pdu_list
;
303 struct iscsi_seq
*seq
= cmd
->seq_list
;
305 datapduinorder
= conn
->sess
->sess_ops
->DataPDUInOrder
;
306 datasequenceinorder
= conn
->sess
->sess_ops
->DataSequenceInOrder
;
308 if ((bl
->type
== PDULIST_IMMEDIATE
) ||
309 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
312 if ((bl
->type
== PDULIST_UNSOLICITED
) ||
313 (bl
->type
== PDULIST_IMMEDIATE_AND_UNSOLICITED
))
314 unsolicited_data_length
= min(cmd
->se_cmd
.data_length
,
315 conn
->sess
->sess_ops
->FirstBurstLength
);
317 while (offset
< cmd
->se_cmd
.data_length
) {
319 if (!datapduinorder
) {
320 pdu
[i
].offset
= offset
;
321 pdu
[i
].seq_no
= seq_no
;
323 if (!datasequenceinorder
&& (pdu_count
== 1)) {
324 seq
[seq_no
].pdu_start
= i
;
325 seq
[seq_no
].seq_no
= seq_no
;
326 seq
[seq_no
].offset
= offset
;
327 seq
[seq_no
].orig_offset
= offset
;
330 if (check_immediate
) {
332 if (!datapduinorder
) {
333 pdu
[i
].type
= PDUTYPE_IMMEDIATE
;
334 pdu
[i
++].length
= bl
->immediate_data_length
;
336 if (!datasequenceinorder
) {
337 seq
[seq_no
].type
= SEQTYPE_IMMEDIATE
;
338 seq
[seq_no
].pdu_count
= 1;
339 seq
[seq_no
].xfer_len
=
340 bl
->immediate_data_length
;
342 offset
+= bl
->immediate_data_length
;
345 if (unsolicited_data_length
)
346 unsolicited_data_length
-=
347 bl
->immediate_data_length
;
350 if (unsolicited_data_length
> 0) {
352 conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
353 cmd
->se_cmd
.data_length
) {
354 if (!datapduinorder
) {
355 pdu
[i
].type
= PDUTYPE_UNSOLICITED
;
357 (cmd
->se_cmd
.data_length
- offset
);
359 if (!datasequenceinorder
) {
360 seq
[seq_no
].type
= SEQTYPE_UNSOLICITED
;
361 seq
[seq_no
].pdu_count
= pdu_count
;
362 seq
[seq_no
].xfer_len
= (burstlength
+
363 (cmd
->se_cmd
.data_length
- offset
));
365 unsolicited_data_length
-=
366 (cmd
->se_cmd
.data_length
- offset
);
367 offset
+= (cmd
->se_cmd
.data_length
- offset
);
371 conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
372 conn
->sess
->sess_ops
->FirstBurstLength
) {
373 if (!datapduinorder
) {
374 pdu
[i
].type
= PDUTYPE_UNSOLICITED
;
376 (conn
->sess
->sess_ops
->FirstBurstLength
-
379 if (!datasequenceinorder
) {
380 seq
[seq_no
].type
= SEQTYPE_UNSOLICITED
;
381 seq
[seq_no
].pdu_count
= pdu_count
;
382 seq
[seq_no
].xfer_len
= (burstlength
+
383 (conn
->sess
->sess_ops
->FirstBurstLength
-
386 unsolicited_data_length
-=
387 (conn
->sess
->sess_ops
->FirstBurstLength
-
389 offset
+= (conn
->sess
->sess_ops
->FirstBurstLength
-
397 if (!datapduinorder
) {
398 pdu
[i
].type
= PDUTYPE_UNSOLICITED
;
400 conn
->conn_ops
->MaxRecvDataSegmentLength
;
402 burstlength
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
403 offset
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
404 unsolicited_data_length
-=
405 conn
->conn_ops
->MaxRecvDataSegmentLength
;
408 if ((offset
+ conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
409 cmd
->se_cmd
.data_length
) {
410 if (!datapduinorder
) {
411 pdu
[i
].type
= PDUTYPE_NORMAL
;
412 pdu
[i
].length
= (cmd
->se_cmd
.data_length
- offset
);
414 if (!datasequenceinorder
) {
415 seq
[seq_no
].type
= SEQTYPE_NORMAL
;
416 seq
[seq_no
].pdu_count
= pdu_count
;
417 seq
[seq_no
].xfer_len
= (burstlength
+
418 (cmd
->se_cmd
.data_length
- offset
));
420 offset
+= (cmd
->se_cmd
.data_length
- offset
);
423 if ((burstlength
+ conn
->conn_ops
->MaxRecvDataSegmentLength
) >=
424 conn
->sess
->sess_ops
->MaxBurstLength
) {
425 if (!datapduinorder
) {
426 pdu
[i
].type
= PDUTYPE_NORMAL
;
428 (conn
->sess
->sess_ops
->MaxBurstLength
-
431 if (!datasequenceinorder
) {
432 seq
[seq_no
].type
= SEQTYPE_NORMAL
;
433 seq
[seq_no
].pdu_count
= pdu_count
;
434 seq
[seq_no
].xfer_len
= (burstlength
+
435 (conn
->sess
->sess_ops
->MaxBurstLength
-
438 offset
+= (conn
->sess
->sess_ops
->MaxBurstLength
-
446 if (!datapduinorder
) {
447 pdu
[i
].type
= PDUTYPE_NORMAL
;
449 conn
->conn_ops
->MaxRecvDataSegmentLength
;
451 burstlength
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
452 offset
+= conn
->conn_ops
->MaxRecvDataSegmentLength
;
455 if (!datasequenceinorder
) {
456 if (bl
->data_direction
& ISCSI_PDU_WRITE
) {
457 if (bl
->randomize
& RANDOM_R2T_OFFSETS
) {
458 if (iscsit_randomize_seq_lists(cmd
, bl
->type
)
462 iscsit_ordered_seq_lists(cmd
, bl
->type
);
463 } else if (bl
->data_direction
& ISCSI_PDU_READ
) {
464 if (bl
->randomize
& RANDOM_DATAIN_SEQ_OFFSETS
) {
465 if (iscsit_randomize_seq_lists(cmd
, bl
->type
)
469 iscsit_ordered_seq_lists(cmd
, bl
->type
);
472 iscsit_dump_seq_list(cmd
);
474 if (!datapduinorder
) {
475 if (bl
->data_direction
& ISCSI_PDU_WRITE
) {
476 if (bl
->randomize
& RANDOM_DATAOUT_PDU_OFFSETS
) {
477 if (iscsit_randomize_pdu_lists(cmd
, bl
->type
)
481 iscsit_ordered_pdu_lists(cmd
, bl
->type
);
482 } else if (bl
->data_direction
& ISCSI_PDU_READ
) {
483 if (bl
->randomize
& RANDOM_DATAIN_PDU_OFFSETS
) {
484 if (iscsit_randomize_pdu_lists(cmd
, bl
->type
)
488 iscsit_ordered_pdu_lists(cmd
, bl
->type
);
491 iscsit_dump_pdu_list(cmd
);
497 int iscsit_build_pdu_and_seq_lists(
498 struct iscsi_cmd
*cmd
,
499 u32 immediate_data_length
)
501 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 struct iscsi_session
*sess
= conn
->sess
;
508 struct iscsi_node_attrib
*na
;
511 * Do nothing if no OOO shenanigans
513 if (sess
->sess_ops
->DataSequenceInOrder
&&
514 sess
->sess_ops
->DataPDUInOrder
)
517 if (cmd
->data_direction
== DMA_NONE
)
520 na
= iscsit_tpg_get_node_attrib(sess
);
521 memset(&bl
, 0, sizeof(struct iscsi_build_list
));
523 if (cmd
->data_direction
== DMA_FROM_DEVICE
) {
524 bl
.data_direction
= ISCSI_PDU_READ
;
525 bl
.type
= PDULIST_NORMAL
;
526 if (na
->random_datain_pdu_offsets
)
527 bl
.randomize
|= RANDOM_DATAIN_PDU_OFFSETS
;
528 if (na
->random_datain_seq_offsets
)
529 bl
.randomize
|= RANDOM_DATAIN_SEQ_OFFSETS
;
531 bl
.data_direction
= ISCSI_PDU_WRITE
;
532 bl
.immediate_data_length
= immediate_data_length
;
533 if (na
->random_r2t_offsets
)
534 bl
.randomize
|= RANDOM_R2T_OFFSETS
;
536 if (!cmd
->immediate_data
&& !cmd
->unsolicited_data
)
537 bl
.type
= PDULIST_NORMAL
;
538 else if (cmd
->immediate_data
&& !cmd
->unsolicited_data
)
539 bl
.type
= PDULIST_IMMEDIATE
;
540 else if (!cmd
->immediate_data
&& cmd
->unsolicited_data
)
541 bl
.type
= PDULIST_UNSOLICITED
;
542 else if (cmd
->immediate_data
&& cmd
->unsolicited_data
)
543 bl
.type
= PDULIST_IMMEDIATE_AND_UNSOLICITED
;
546 iscsit_determine_counts_for_list(cmd
, &bl
, &seq_count
, &pdu_count
);
548 if (!conn
->sess
->sess_ops
->DataSequenceInOrder
) {
549 seq
= kcalloc(seq_count
, sizeof(struct iscsi_seq
), GFP_ATOMIC
);
551 pr_err("Unable to allocate struct iscsi_seq list\n");
555 cmd
->seq_count
= seq_count
;
558 if (!conn
->sess
->sess_ops
->DataPDUInOrder
) {
559 pdu
= kcalloc(pdu_count
, sizeof(struct iscsi_pdu
), GFP_ATOMIC
);
561 pr_err("Unable to allocate struct iscsi_pdu list.\n");
566 cmd
->pdu_count
= pdu_count
;
569 return iscsit_do_build_pdu_and_seq_lists(cmd
, &bl
);
572 struct iscsi_pdu
*iscsit_get_pdu_holder(
573 struct iscsi_cmd
*cmd
,
578 struct iscsi_pdu
*pdu
= NULL
;
580 if (!cmd
->pdu_list
) {
581 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
585 pdu
= &cmd
->pdu_list
[0];
587 for (i
= 0; i
< cmd
->pdu_count
; i
++)
588 if ((pdu
[i
].offset
== offset
) && (pdu
[i
].length
== length
))
591 pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
592 " %u, Length: %u\n", cmd
->init_task_tag
, offset
, length
);
596 struct iscsi_pdu
*iscsit_get_pdu_holder_for_seq(
597 struct iscsi_cmd
*cmd
,
598 struct iscsi_seq
*seq
)
601 struct iscsi_conn
*conn
= cmd
->conn
;
602 struct iscsi_pdu
*pdu
= NULL
;
604 if (!cmd
->pdu_list
) {
605 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
609 if (conn
->sess
->sess_ops
->DataSequenceInOrder
) {
611 pdu
= &cmd
->pdu_list
[cmd
->pdu_start
];
613 for (i
= 0; pdu
[i
].seq_no
!= cmd
->seq_no
; i
++) {
614 pr_debug("pdu[i].seq_no: %d, pdu[i].pdu"
615 "_send_order: %d, pdu[i].offset: %d,"
616 " pdu[i].length: %d\n", pdu
[i
].seq_no
,
617 pdu
[i
].pdu_send_order
, pdu
[i
].offset
,
620 if (pdu
[i
].pdu_send_order
== cmd
->pdu_send_order
) {
621 cmd
->pdu_send_order
++;
626 cmd
->pdu_start
+= cmd
->pdu_send_order
;
627 cmd
->pdu_send_order
= 0;
630 if (cmd
->pdu_start
< cmd
->pdu_count
)
633 pr_err("Command ITT: 0x%08x unable to locate"
634 " struct iscsi_pdu for cmd->pdu_send_order: %u.\n",
635 cmd
->init_task_tag
, cmd
->pdu_send_order
);
639 pr_err("struct iscsi_seq is NULL!\n");
643 pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
644 " seq->seq_no: %d\n", seq
->pdu_start
, seq
->pdu_count
,
647 pdu
= &cmd
->pdu_list
[seq
->pdu_start
];
649 if (seq
->pdu_send_order
== seq
->pdu_count
) {
650 pr_err("Command ITT: 0x%08x seq->pdu_send"
651 "_order: %u equals seq->pdu_count: %u\n",
652 cmd
->init_task_tag
, seq
->pdu_send_order
,
657 for (i
= 0; i
< seq
->pdu_count
; i
++) {
658 if (pdu
[i
].pdu_send_order
== seq
->pdu_send_order
) {
659 seq
->pdu_send_order
++;
664 pr_err("Command ITT: 0x%08x unable to locate iscsi"
665 "_pdu_t for seq->pdu_send_order: %u.\n",
666 cmd
->init_task_tag
, seq
->pdu_send_order
);
673 struct iscsi_seq
*iscsit_get_seq_holder(
674 struct iscsi_cmd
*cmd
,
680 if (!cmd
->seq_list
) {
681 pr_err("struct iscsi_cmd->seq_list is NULL!\n");
685 for (i
= 0; i
< cmd
->seq_count
; i
++) {
686 pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
687 "xfer_len: %d, seq_list[i].seq_no %u\n",
688 cmd
->seq_list
[i
].orig_offset
, cmd
->seq_list
[i
].xfer_len
,
689 cmd
->seq_list
[i
].seq_no
);
691 if ((cmd
->seq_list
[i
].orig_offset
+
692 cmd
->seq_list
[i
].xfer_len
) >=
694 return &cmd
->seq_list
[i
];
697 pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
698 " Offset: %u, Length: %u\n", cmd
->init_task_tag
, offset
,