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
32 static void iscsit_dump_seq_list(struct iscsi_cmd *cmd)
35 struct iscsi_seq *seq;
37 pr_debug("Dumping Sequence List for ITT: 0x%08x:\n",
40 for (i = 0; i < cmd->seq_count; i++) {
41 seq = &cmd->seq_list[i];
42 pr_debug("i: %d, pdu_start: %d, pdu_count: %d,"
43 " offset: %d, xfer_len: %d, seq_send_order: %d,"
44 " seq_no: %d\n", i, seq->pdu_start, seq->pdu_count,
45 seq->offset, seq->xfer_len, seq->seq_send_order,
50 static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd)
53 struct iscsi_pdu *pdu;
55 pr_debug("Dumping PDU List for ITT: 0x%08x:\n",
58 for (i = 0; i < cmd->pdu_count; i++) {
59 pdu = &cmd->pdu_list[i];
60 pr_debug("i: %d, offset: %d, length: %d,"
61 " pdu_send_order: %d, seq_no: %d\n", i, pdu->offset,
62 pdu->length, pdu->pdu_send_order, pdu->seq_no);
66 static void iscsit_dump_seq_list(struct iscsi_cmd *cmd) {}
67 static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) {}
70 static void iscsit_ordered_seq_lists(
71 struct iscsi_cmd *cmd,
76 for (i = 0; i < cmd->seq_count; i++) {
77 if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
79 cmd->seq_list[i].seq_send_order = seq_count++;
83 static void iscsit_ordered_pdu_lists(
84 struct iscsi_cmd *cmd,
87 u32 i, pdu_send_order = 0, seq_no = 0;
89 for (i = 0; i < cmd->pdu_count; i++) {
91 if (cmd->pdu_list[i].seq_no == seq_no) {
92 cmd->pdu_list[i].pdu_send_order = pdu_send_order++;
102 * Generate count random values into array.
103 * Use 0x80000000 to mark generates valued in array[].
105 static void iscsit_create_random_array(u32 *array, u32 count)
114 for (i = 0; i < count; i++) {
116 get_random_bytes(&j, sizeof(u32));
117 j = (1 + (int) (9999 + 1) - j) % count;
118 for (k = 0; k < i + 1; k++) {
120 if ((array[k] & 0x80000000) && (array[k] == j))
126 for (i = 0; i < count; i++)
127 array[i] &= ~0x80000000;
130 static int iscsit_randomize_pdu_lists(
131 struct iscsi_cmd *cmd,
135 u32 *array, pdu_count, seq_count = 0, seq_no = 0, seq_offset = 0;
137 for (pdu_count = 0; pdu_count < cmd->pdu_count; pdu_count++) {
139 if (cmd->pdu_list[pdu_count].seq_no == seq_no) {
143 array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
145 pr_err("Unable to allocate memory"
146 " for random array.\n");
149 iscsit_create_random_array(array, seq_count);
151 for (i = 0; i < seq_count; i++)
152 cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
156 seq_offset += seq_count;
163 array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
165 pr_err("Unable to allocate memory for"
169 iscsit_create_random_array(array, seq_count);
171 for (i = 0; i < seq_count; i++)
172 cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
180 static int iscsit_randomize_seq_lists(
181 struct iscsi_cmd *cmd,
185 u32 *array, seq_count = cmd->seq_count;
187 if ((type == PDULIST_IMMEDIATE) || (type == PDULIST_UNSOLICITED))
189 else if (type == PDULIST_IMMEDIATE_AND_UNSOLICITED)
195 array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
197 pr_err("Unable to allocate memory for random array.\n");
200 iscsit_create_random_array(array, seq_count);
202 for (i = 0; i < cmd->seq_count; i++) {
203 if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
205 cmd->seq_list[i].seq_send_order = array[j++];
212 static void iscsit_determine_counts_for_list(
213 struct iscsi_cmd *cmd,
214 struct iscsi_build_list *bl,
218 int check_immediate = 0;
219 u32 burstlength = 0, offset = 0;
220 u32 unsolicited_data_length = 0;
221 struct iscsi_conn *conn = cmd->conn;
223 if ((bl->type == PDULIST_IMMEDIATE) ||
224 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
227 if ((bl->type == PDULIST_UNSOLICITED) ||
228 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
229 unsolicited_data_length = min(cmd->se_cmd.data_length,
230 conn->sess->sess_ops->FirstBurstLength);
232 while (offset < cmd->se_cmd.data_length) {
235 if (check_immediate) {
237 offset += bl->immediate_data_length;
239 if (unsolicited_data_length)
240 unsolicited_data_length -=
241 bl->immediate_data_length;
244 if (unsolicited_data_length > 0) {
245 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
246 >= cmd->se_cmd.data_length) {
247 unsolicited_data_length -=
248 (cmd->se_cmd.data_length - offset);
249 offset += (cmd->se_cmd.data_length - offset);
252 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
253 >= conn->sess->sess_ops->FirstBurstLength) {
254 unsolicited_data_length -=
255 (conn->sess->sess_ops->FirstBurstLength -
257 offset += (conn->sess->sess_ops->FirstBurstLength -
264 offset += conn->conn_ops->MaxRecvDataSegmentLength;
265 unsolicited_data_length -=
266 conn->conn_ops->MaxRecvDataSegmentLength;
269 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
270 cmd->se_cmd.data_length) {
271 offset += (cmd->se_cmd.data_length - offset);
274 if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
275 conn->sess->sess_ops->MaxBurstLength) {
276 offset += (conn->sess->sess_ops->MaxBurstLength -
283 burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
284 offset += conn->conn_ops->MaxRecvDataSegmentLength;
290 * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
291 * and DataPDUInOrder=No.
293 static int iscsit_build_pdu_and_seq_list(
294 struct iscsi_cmd *cmd,
295 struct iscsi_build_list *bl)
297 int check_immediate = 0, datapduinorder, datasequenceinorder;
298 u32 burstlength = 0, offset = 0, i = 0;
299 u32 pdu_count = 0, seq_no = 0, unsolicited_data_length = 0;
300 struct iscsi_conn *conn = cmd->conn;
301 struct iscsi_pdu *pdu = cmd->pdu_list;
302 struct iscsi_seq *seq = cmd->seq_list;
304 datapduinorder = conn->sess->sess_ops->DataPDUInOrder;
305 datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder;
307 if ((bl->type == PDULIST_IMMEDIATE) ||
308 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
311 if ((bl->type == PDULIST_UNSOLICITED) ||
312 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
313 unsolicited_data_length = min(cmd->se_cmd.data_length,
314 conn->sess->sess_ops->FirstBurstLength);
316 while (offset < cmd->se_cmd.data_length) {
318 if (!datapduinorder) {
319 pdu[i].offset = offset;
320 pdu[i].seq_no = seq_no;
322 if (!datasequenceinorder && (pdu_count == 1)) {
323 seq[seq_no].pdu_start = i;
324 seq[seq_no].seq_no = seq_no;
325 seq[seq_no].offset = offset;
326 seq[seq_no].orig_offset = offset;
329 if (check_immediate) {
331 if (!datapduinorder) {
332 pdu[i].type = PDUTYPE_IMMEDIATE;
333 pdu[i++].length = bl->immediate_data_length;
335 if (!datasequenceinorder) {
336 seq[seq_no].type = SEQTYPE_IMMEDIATE;
337 seq[seq_no].pdu_count = 1;
338 seq[seq_no].xfer_len =
339 bl->immediate_data_length;
341 offset += bl->immediate_data_length;
344 if (unsolicited_data_length)
345 unsolicited_data_length -=
346 bl->immediate_data_length;
349 if (unsolicited_data_length > 0) {
351 conn->conn_ops->MaxRecvDataSegmentLength) >=
352 cmd->se_cmd.data_length) {
353 if (!datapduinorder) {
354 pdu[i].type = PDUTYPE_UNSOLICITED;
356 (cmd->se_cmd.data_length - offset);
358 if (!datasequenceinorder) {
359 seq[seq_no].type = SEQTYPE_UNSOLICITED;
360 seq[seq_no].pdu_count = pdu_count;
361 seq[seq_no].xfer_len = (burstlength +
362 (cmd->se_cmd.data_length - offset));
364 unsolicited_data_length -=
365 (cmd->se_cmd.data_length - offset);
366 offset += (cmd->se_cmd.data_length - offset);
370 conn->conn_ops->MaxRecvDataSegmentLength) >=
371 conn->sess->sess_ops->FirstBurstLength) {
372 if (!datapduinorder) {
373 pdu[i].type = PDUTYPE_UNSOLICITED;
375 (conn->sess->sess_ops->FirstBurstLength -
378 if (!datasequenceinorder) {
379 seq[seq_no].type = SEQTYPE_UNSOLICITED;
380 seq[seq_no].pdu_count = pdu_count;
381 seq[seq_no].xfer_len = (burstlength +
382 (conn->sess->sess_ops->FirstBurstLength -
385 unsolicited_data_length -=
386 (conn->sess->sess_ops->FirstBurstLength -
388 offset += (conn->sess->sess_ops->FirstBurstLength -
396 if (!datapduinorder) {
397 pdu[i].type = PDUTYPE_UNSOLICITED;
399 conn->conn_ops->MaxRecvDataSegmentLength;
401 burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
402 offset += conn->conn_ops->MaxRecvDataSegmentLength;
403 unsolicited_data_length -=
404 conn->conn_ops->MaxRecvDataSegmentLength;
407 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
408 cmd->se_cmd.data_length) {
409 if (!datapduinorder) {
410 pdu[i].type = PDUTYPE_NORMAL;
411 pdu[i].length = (cmd->se_cmd.data_length - offset);
413 if (!datasequenceinorder) {
414 seq[seq_no].type = SEQTYPE_NORMAL;
415 seq[seq_no].pdu_count = pdu_count;
416 seq[seq_no].xfer_len = (burstlength +
417 (cmd->se_cmd.data_length - offset));
419 offset += (cmd->se_cmd.data_length - offset);
422 if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
423 conn->sess->sess_ops->MaxBurstLength) {
424 if (!datapduinorder) {
425 pdu[i].type = PDUTYPE_NORMAL;
427 (conn->sess->sess_ops->MaxBurstLength -
430 if (!datasequenceinorder) {
431 seq[seq_no].type = SEQTYPE_NORMAL;
432 seq[seq_no].pdu_count = pdu_count;
433 seq[seq_no].xfer_len = (burstlength +
434 (conn->sess->sess_ops->MaxBurstLength -
437 offset += (conn->sess->sess_ops->MaxBurstLength -
445 if (!datapduinorder) {
446 pdu[i].type = PDUTYPE_NORMAL;
448 conn->conn_ops->MaxRecvDataSegmentLength;
450 burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
451 offset += conn->conn_ops->MaxRecvDataSegmentLength;
454 if (!datasequenceinorder) {
455 if (bl->data_direction & ISCSI_PDU_WRITE) {
456 if (bl->randomize & RANDOM_R2T_OFFSETS) {
457 if (iscsit_randomize_seq_lists(cmd, bl->type)
461 iscsit_ordered_seq_lists(cmd, bl->type);
462 } else if (bl->data_direction & ISCSI_PDU_READ) {
463 if (bl->randomize & RANDOM_DATAIN_SEQ_OFFSETS) {
464 if (iscsit_randomize_seq_lists(cmd, bl->type)
468 iscsit_ordered_seq_lists(cmd, bl->type);
471 iscsit_dump_seq_list(cmd);
473 if (!datapduinorder) {
474 if (bl->data_direction & ISCSI_PDU_WRITE) {
475 if (bl->randomize & RANDOM_DATAOUT_PDU_OFFSETS) {
476 if (iscsit_randomize_pdu_lists(cmd, bl->type)
480 iscsit_ordered_pdu_lists(cmd, bl->type);
481 } else if (bl->data_direction & ISCSI_PDU_READ) {
482 if (bl->randomize & RANDOM_DATAIN_PDU_OFFSETS) {
483 if (iscsit_randomize_pdu_lists(cmd, bl->type)
487 iscsit_ordered_pdu_lists(cmd, bl->type);
490 iscsit_dump_pdu_list(cmd);
497 * Only called while DataSequenceInOrder=No or DataPDUInOrder=No.
499 int iscsit_do_build_list(
500 struct iscsi_cmd *cmd,
501 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 iscsit_determine_counts_for_list(cmd, bl, &seq_count, &pdu_count);
510 if (!conn->sess->sess_ops->DataSequenceInOrder) {
511 seq = kzalloc(seq_count * sizeof(struct iscsi_seq), GFP_ATOMIC);
513 pr_err("Unable to allocate struct iscsi_seq list\n");
517 cmd->seq_count = seq_count;
520 if (!conn->sess->sess_ops->DataPDUInOrder) {
521 pdu = kzalloc(pdu_count * sizeof(struct iscsi_pdu), GFP_ATOMIC);
523 pr_err("Unable to allocate struct iscsi_pdu list.\n");
528 cmd->pdu_count = pdu_count;
531 return iscsit_build_pdu_and_seq_list(cmd, bl);
534 struct iscsi_pdu *iscsit_get_pdu_holder(
535 struct iscsi_cmd *cmd,
540 struct iscsi_pdu *pdu = NULL;
542 if (!cmd->pdu_list) {
543 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
547 pdu = &cmd->pdu_list[0];
549 for (i = 0; i < cmd->pdu_count; i++)
550 if ((pdu[i].offset == offset) && (pdu[i].length == length))
553 pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
554 " %u, Length: %u\n", cmd->init_task_tag, offset, length);
558 struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(
559 struct iscsi_cmd *cmd,
560 struct iscsi_seq *seq)
563 struct iscsi_conn *conn = cmd->conn;
564 struct iscsi_pdu *pdu = NULL;
566 if (!cmd->pdu_list) {
567 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
571 if (conn->sess->sess_ops->DataSequenceInOrder) {
573 pdu = &cmd->pdu_list[cmd->pdu_start];
575 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++) {
648 pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
649 "xfer_len: %d, seq_list[i].seq_no %u\n",
650 cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len,
651 cmd->seq_list[i].seq_no);
653 if ((cmd->seq_list[i].orig_offset +
654 cmd->seq_list[i].xfer_len) >=
656 return &cmd->seq_list[i];
659 pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
660 " Offset: %u, Length: %u\n", cmd->init_task_tag, offset,