blob: fc694082bfc0b310d7db052228f367e95a79e2c9 [file] [log] [blame]
Nicholas Bellingere48354c2011-07-23 06:43:04 +00001/*******************************************************************************
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}