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,