linux/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
<<
>>
Prefs
   1/*******************************************************************************
   2 * This file contains main functions related to iSCSI DataSequenceInOrder=No
   3 * and DataPDUInOrder=No.
   4 *
   5 * (c) Copyright 2007-2013 Datera, Inc.
   6 *
   7 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 ******************************************************************************/
  19
  20#include <linux/slab.h>
  21#include <linux/random.h>
  22
  23#include <target/iscsi/iscsi_target_core.h>
  24#include "iscsi_target_util.h"
  25#include "iscsi_target_tpg.h"
  26#include "iscsi_target_seq_pdu_list.h"
  27
  28#ifdef DEBUG
  29static void iscsit_dump_seq_list(struct iscsi_cmd *cmd)
  30{
  31        int i;
  32        struct iscsi_seq *seq;
  33
  34        pr_debug("Dumping Sequence List for ITT: 0x%08x:\n",
  35                        cmd->init_task_tag);
  36
  37        for (i = 0; i < cmd->seq_count; i++) {
  38                seq = &cmd->seq_list[i];
  39                pr_debug("i: %d, pdu_start: %d, pdu_count: %d,"
  40                        " offset: %d, xfer_len: %d, seq_send_order: %d,"
  41                        " seq_no: %d\n", i, seq->pdu_start, seq->pdu_count,
  42                        seq->offset, seq->xfer_len, seq->seq_send_order,
  43                        seq->seq_no);
  44        }
  45}
  46
  47static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd)
  48{
  49        int i;
  50        struct iscsi_pdu *pdu;
  51
  52        pr_debug("Dumping PDU List for ITT: 0x%08x:\n",
  53                        cmd->init_task_tag);
  54
  55        for (i = 0; i < cmd->pdu_count; i++) {
  56                pdu = &cmd->pdu_list[i];
  57                pr_debug("i: %d, offset: %d, length: %d,"
  58                        " pdu_send_order: %d, seq_no: %d\n", i, pdu->offset,
  59                        pdu->length, pdu->pdu_send_order, pdu->seq_no);
  60        }
  61}
  62#else
  63static void iscsit_dump_seq_list(struct iscsi_cmd *cmd) {}
  64static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) {}
  65#endif
  66
  67static void iscsit_ordered_seq_lists(
  68        struct iscsi_cmd *cmd,
  69        u8 type)
  70{
  71        u32 i, seq_count = 0;
  72
  73        for (i = 0; i < cmd->seq_count; i++) {
  74                if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
  75                        continue;
  76                cmd->seq_list[i].seq_send_order = seq_count++;
  77        }
  78}
  79
  80static void iscsit_ordered_pdu_lists(
  81        struct iscsi_cmd *cmd,
  82        u8 type)
  83{
  84        u32 i, pdu_send_order = 0, seq_no = 0;
  85
  86        for (i = 0; i < cmd->pdu_count; i++) {
  87redo:
  88                if (cmd->pdu_list[i].seq_no == seq_no) {
  89                        cmd->pdu_list[i].pdu_send_order = pdu_send_order++;
  90                        continue;
  91                }
  92                seq_no++;
  93                pdu_send_order = 0;
  94                goto redo;
  95        }
  96}
  97
  98/*
  99 *      Generate count random values into array.
 100 *      Use 0x80000000 to mark generates valued in array[].
 101 */
 102static void iscsit_create_random_array(u32 *array, u32 count)
 103{
 104        int i, j, k;
 105
 106        if (count == 1) {
 107                array[0] = 0;
 108                return;
 109        }
 110
 111        for (i = 0; i < count; i++) {
 112redo:
 113                get_random_bytes(&j, sizeof(u32));
 114                j = (1 + (int) (9999 + 1) - j) % count;
 115                for (k = 0; k < i + 1; k++) {
 116                        j |= 0x80000000;
 117                        if ((array[k] & 0x80000000) && (array[k] == j))
 118                                goto redo;
 119                }
 120                array[i] = j;
 121        }
 122
 123        for (i = 0; i < count; i++)
 124                array[i] &= ~0x80000000;
 125}
 126
 127static int iscsit_randomize_pdu_lists(
 128        struct iscsi_cmd *cmd,
 129        u8 type)
 130{
 131        int i = 0;
 132        u32 *array, pdu_count, seq_count = 0, seq_no = 0, seq_offset = 0;
 133
 134        for (pdu_count = 0; pdu_count < cmd->pdu_count; pdu_count++) {
 135redo:
 136                if (cmd->pdu_list[pdu_count].seq_no == seq_no) {
 137                        seq_count++;
 138                        continue;
 139                }
 140                array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
 141                if (!array) {
 142                        pr_err("Unable to allocate memory"
 143                                " for random array.\n");
 144                        return -ENOMEM;
 145                }
 146                iscsit_create_random_array(array, seq_count);
 147
 148                for (i = 0; i < seq_count; i++)
 149                        cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
 150
 151                kfree(array);
 152
 153                seq_offset += seq_count;
 154                seq_count = 0;
 155                seq_no++;
 156                goto redo;
 157        }
 158
 159        if (seq_count) {
 160                array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
 161                if (!array) {
 162                        pr_err("Unable to allocate memory for"
 163                                " random array.\n");
 164                        return -ENOMEM;
 165                }
 166                iscsit_create_random_array(array, seq_count);
 167
 168                for (i = 0; i < seq_count; i++)
 169                        cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
 170
 171                kfree(array);
 172        }
 173
 174        return 0;
 175}
 176
 177static int iscsit_randomize_seq_lists(
 178        struct iscsi_cmd *cmd,
 179        u8 type)
 180{
 181        int i, j = 0;
 182        u32 *array, seq_count = cmd->seq_count;
 183
 184        if ((type == PDULIST_IMMEDIATE) || (type == PDULIST_UNSOLICITED))
 185                seq_count--;
 186        else if (type == PDULIST_IMMEDIATE_AND_UNSOLICITED)
 187                seq_count -= 2;
 188
 189        if (!seq_count)
 190                return 0;
 191
 192        array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
 193        if (!array) {
 194                pr_err("Unable to allocate memory for random array.\n");
 195                return -ENOMEM;
 196        }
 197        iscsit_create_random_array(array, seq_count);
 198
 199        for (i = 0; i < cmd->seq_count; i++) {
 200                if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
 201                        continue;
 202                cmd->seq_list[i].seq_send_order = array[j++];
 203        }
 204
 205        kfree(array);
 206        return 0;
 207}
 208
 209static void iscsit_determine_counts_for_list(
 210        struct iscsi_cmd *cmd,
 211        struct iscsi_build_list *bl,
 212        u32 *seq_count,
 213        u32 *pdu_count)
 214{
 215        int check_immediate = 0;
 216        u32 burstlength = 0, offset = 0;
 217        u32 unsolicited_data_length = 0;
 218        u32 mdsl;
 219        struct iscsi_conn *conn = cmd->conn;
 220
 221        if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
 222                mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
 223        else
 224                mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
 225
 226        if ((bl->type == PDULIST_IMMEDIATE) ||
 227            (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
 228                check_immediate = 1;
 229
 230        if ((bl->type == PDULIST_UNSOLICITED) ||
 231            (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
 232                unsolicited_data_length = min(cmd->se_cmd.data_length,
 233                        conn->sess->sess_ops->FirstBurstLength);
 234
 235        while (offset < cmd->se_cmd.data_length) {
 236                *pdu_count += 1;
 237
 238                if (check_immediate) {
 239                        check_immediate = 0;
 240                        offset += bl->immediate_data_length;
 241                        *seq_count += 1;
 242                        if (unsolicited_data_length)
 243                                unsolicited_data_length -=
 244                                        bl->immediate_data_length;
 245                        continue;
 246                }
 247                if (unsolicited_data_length > 0) {
 248                        if ((offset + mdsl) >= cmd->se_cmd.data_length) {
 249                                unsolicited_data_length -=
 250                                        (cmd->se_cmd.data_length - offset);
 251                                offset += (cmd->se_cmd.data_length - offset);
 252                                continue;
 253                        }
 254                        if ((offset + mdsl)
 255                                        >= conn->sess->sess_ops->FirstBurstLength) {
 256                                unsolicited_data_length -=
 257                                        (conn->sess->sess_ops->FirstBurstLength -
 258                                        offset);
 259                                offset += (conn->sess->sess_ops->FirstBurstLength -
 260                                        offset);
 261                                burstlength = 0;
 262                                *seq_count += 1;
 263                                continue;
 264                        }
 265
 266                        offset += mdsl;
 267                        unsolicited_data_length -= mdsl;
 268                        continue;
 269                }
 270                if ((offset + mdsl) >= cmd->se_cmd.data_length) {
 271                        offset += (cmd->se_cmd.data_length - offset);
 272                        continue;
 273                }
 274                if ((burstlength + mdsl) >=
 275                     conn->sess->sess_ops->MaxBurstLength) {
 276                        offset += (conn->sess->sess_ops->MaxBurstLength -
 277                                        burstlength);
 278                        burstlength = 0;
 279                        *seq_count += 1;
 280                        continue;
 281                }
 282
 283                burstlength += mdsl;
 284                offset += mdsl;
 285        }
 286}
 287
 288
 289/*
 290 *      Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
 291 *      or DataPDUInOrder=No.
 292 */
 293static int iscsit_do_build_pdu_and_seq_lists(
 294        struct iscsi_cmd *cmd,
 295        struct iscsi_build_list *bl)
 296{
 297        int check_immediate = 0, datapduinorder, datasequenceinorder;
 298        u32 burstlength = 0, offset = 0, i = 0, mdsl;
 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;
 303
 304        if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
 305                mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
 306        else
 307                mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
 308
 309        datapduinorder = conn->sess->sess_ops->DataPDUInOrder;
 310        datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder;
 311
 312        if ((bl->type == PDULIST_IMMEDIATE) ||
 313            (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
 314                check_immediate = 1;
 315
 316        if ((bl->type == PDULIST_UNSOLICITED) ||
 317            (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
 318                unsolicited_data_length = min(cmd->se_cmd.data_length,
 319                        conn->sess->sess_ops->FirstBurstLength);
 320
 321        while (offset < cmd->se_cmd.data_length) {
 322                pdu_count++;
 323                if (!datapduinorder) {
 324                        pdu[i].offset = offset;
 325                        pdu[i].seq_no = seq_no;
 326                }
 327                if (!datasequenceinorder && (pdu_count == 1)) {
 328                        seq[seq_no].pdu_start = i;
 329                        seq[seq_no].seq_no = seq_no;
 330                        seq[seq_no].offset = offset;
 331                        seq[seq_no].orig_offset = offset;
 332                }
 333
 334                if (check_immediate) {
 335                        check_immediate = 0;
 336                        if (!datapduinorder) {
 337                                pdu[i].type = PDUTYPE_IMMEDIATE;
 338                                pdu[i++].length = bl->immediate_data_length;
 339                        }
 340                        if (!datasequenceinorder) {
 341                                seq[seq_no].type = SEQTYPE_IMMEDIATE;
 342                                seq[seq_no].pdu_count = 1;
 343                                seq[seq_no].xfer_len =
 344                                        bl->immediate_data_length;
 345                        }
 346                        offset += bl->immediate_data_length;
 347                        pdu_count = 0;
 348                        seq_no++;
 349                        if (unsolicited_data_length)
 350                                unsolicited_data_length -=
 351                                        bl->immediate_data_length;
 352                        continue;
 353                }
 354                if (unsolicited_data_length > 0) {
 355                        if ((offset + mdsl) >= cmd->se_cmd.data_length) {
 356                                if (!datapduinorder) {
 357                                        pdu[i].type = PDUTYPE_UNSOLICITED;
 358                                        pdu[i].length =
 359                                                (cmd->se_cmd.data_length - offset);
 360                                }
 361                                if (!datasequenceinorder) {
 362                                        seq[seq_no].type = SEQTYPE_UNSOLICITED;
 363                                        seq[seq_no].pdu_count = pdu_count;
 364                                        seq[seq_no].xfer_len = (burstlength +
 365                                                (cmd->se_cmd.data_length - offset));
 366                                }
 367                                unsolicited_data_length -=
 368                                                (cmd->se_cmd.data_length - offset);
 369                                offset += (cmd->se_cmd.data_length - offset);
 370                                continue;
 371                        }
 372                        if ((offset + mdsl) >=
 373                                        conn->sess->sess_ops->FirstBurstLength) {
 374                                if (!datapduinorder) {
 375                                        pdu[i].type = PDUTYPE_UNSOLICITED;
 376                                        pdu[i++].length =
 377                                           (conn->sess->sess_ops->FirstBurstLength -
 378                                                offset);
 379                                }
 380                                if (!datasequenceinorder) {
 381                                        seq[seq_no].type = SEQTYPE_UNSOLICITED;
 382                                        seq[seq_no].pdu_count = pdu_count;
 383                                        seq[seq_no].xfer_len = (burstlength +
 384                                           (conn->sess->sess_ops->FirstBurstLength -
 385                                                offset));
 386                                }
 387                                unsolicited_data_length -=
 388                                        (conn->sess->sess_ops->FirstBurstLength -
 389                                                offset);
 390                                offset += (conn->sess->sess_ops->FirstBurstLength -
 391                                                offset);
 392                                burstlength = 0;
 393                                pdu_count = 0;
 394                                seq_no++;
 395                                continue;
 396                        }
 397
 398                        if (!datapduinorder) {
 399                                pdu[i].type = PDUTYPE_UNSOLICITED;
 400                                pdu[i++].length = mdsl;
 401                        }
 402                        burstlength += mdsl;
 403                        offset += mdsl;
 404                        unsolicited_data_length -= mdsl;
 405                        continue;
 406                }
 407                if ((offset + mdsl) >= cmd->se_cmd.data_length) {
 408                        if (!datapduinorder) {
 409                                pdu[i].type = PDUTYPE_NORMAL;
 410                                pdu[i].length = (cmd->se_cmd.data_length - offset);
 411                        }
 412                        if (!datasequenceinorder) {
 413                                seq[seq_no].type = SEQTYPE_NORMAL;
 414                                seq[seq_no].pdu_count = pdu_count;
 415                                seq[seq_no].xfer_len = (burstlength +
 416                                        (cmd->se_cmd.data_length - offset));
 417                        }
 418                        offset += (cmd->se_cmd.data_length - offset);
 419                        continue;
 420                }
 421                if ((burstlength + mdsl) >=
 422                     conn->sess->sess_ops->MaxBurstLength) {
 423                        if (!datapduinorder) {
 424                                pdu[i].type = PDUTYPE_NORMAL;
 425                                pdu[i++].length =
 426                                        (conn->sess->sess_ops->MaxBurstLength -
 427                                                burstlength);
 428                        }
 429                        if (!datasequenceinorder) {
 430                                seq[seq_no].type = SEQTYPE_NORMAL;
 431                                seq[seq_no].pdu_count = pdu_count;
 432                                seq[seq_no].xfer_len = (burstlength +
 433                                        (conn->sess->sess_ops->MaxBurstLength -
 434                                        burstlength));
 435                        }
 436                        offset += (conn->sess->sess_ops->MaxBurstLength -
 437                                        burstlength);
 438                        burstlength = 0;
 439                        pdu_count = 0;
 440                        seq_no++;
 441                        continue;
 442                }
 443
 444                if (!datapduinorder) {
 445                        pdu[i].type = PDUTYPE_NORMAL;
 446                        pdu[i++].length = mdsl;
 447                }
 448                burstlength += mdsl;
 449                offset += mdsl;
 450        }
 451
 452        if (!datasequenceinorder) {
 453                if (bl->data_direction & ISCSI_PDU_WRITE) {
 454                        if (bl->randomize & RANDOM_R2T_OFFSETS) {
 455                                if (iscsit_randomize_seq_lists(cmd, bl->type)
 456                                                < 0)
 457                                        return -1;
 458                        } else
 459                                iscsit_ordered_seq_lists(cmd, bl->type);
 460                } else if (bl->data_direction & ISCSI_PDU_READ) {
 461                        if (bl->randomize & RANDOM_DATAIN_SEQ_OFFSETS) {
 462                                if (iscsit_randomize_seq_lists(cmd, bl->type)
 463                                                < 0)
 464                                        return -1;
 465                        } else
 466                                iscsit_ordered_seq_lists(cmd, bl->type);
 467                }
 468
 469                iscsit_dump_seq_list(cmd);
 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
 488                iscsit_dump_pdu_list(cmd);
 489        }
 490
 491        return 0;
 492}
 493
 494int iscsit_build_pdu_and_seq_lists(
 495        struct iscsi_cmd *cmd,
 496        u32 immediate_data_length)
 497{
 498        struct iscsi_build_list bl;
 499        u32 pdu_count = 0, seq_count = 1;
 500        struct iscsi_conn *conn = cmd->conn;
 501        struct iscsi_pdu *pdu = NULL;
 502        struct iscsi_seq *seq = NULL;
 503
 504        struct iscsi_session *sess = conn->sess;
 505        struct iscsi_node_attrib *na;
 506
 507        /*
 508         * Do nothing if no OOO shenanigans
 509         */
 510        if (sess->sess_ops->DataSequenceInOrder &&
 511            sess->sess_ops->DataPDUInOrder)
 512                return 0;
 513
 514        if (cmd->data_direction == DMA_NONE)
 515                return 0;
 516
 517        na = iscsit_tpg_get_node_attrib(sess);
 518        memset(&bl, 0, sizeof(struct iscsi_build_list));
 519
 520        if (cmd->data_direction == DMA_FROM_DEVICE) {
 521                bl.data_direction = ISCSI_PDU_READ;
 522                bl.type = PDULIST_NORMAL;
 523                if (na->random_datain_pdu_offsets)
 524                        bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS;
 525                if (na->random_datain_seq_offsets)
 526                        bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS;
 527        } else {
 528                bl.data_direction = ISCSI_PDU_WRITE;
 529                bl.immediate_data_length = immediate_data_length;
 530                if (na->random_r2t_offsets)
 531                        bl.randomize |= RANDOM_R2T_OFFSETS;
 532
 533                if (!cmd->immediate_data && !cmd->unsolicited_data)
 534                        bl.type = PDULIST_NORMAL;
 535                else if (cmd->immediate_data && !cmd->unsolicited_data)
 536                        bl.type = PDULIST_IMMEDIATE;
 537                else if (!cmd->immediate_data && cmd->unsolicited_data)
 538                        bl.type = PDULIST_UNSOLICITED;
 539                else if (cmd->immediate_data && cmd->unsolicited_data)
 540                        bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED;
 541        }
 542
 543        iscsit_determine_counts_for_list(cmd, &bl, &seq_count, &pdu_count);
 544
 545        if (!conn->sess->sess_ops->DataSequenceInOrder) {
 546                seq = kcalloc(seq_count, sizeof(struct iscsi_seq), GFP_ATOMIC);
 547                if (!seq) {
 548                        pr_err("Unable to allocate struct iscsi_seq list\n");
 549                        return -ENOMEM;
 550                }
 551                cmd->seq_list = seq;
 552                cmd->seq_count = seq_count;
 553        }
 554
 555        if (!conn->sess->sess_ops->DataPDUInOrder) {
 556                pdu = kcalloc(pdu_count, sizeof(struct iscsi_pdu), GFP_ATOMIC);
 557                if (!pdu) {
 558                        pr_err("Unable to allocate struct iscsi_pdu list.\n");
 559                        kfree(seq);
 560                        return -ENOMEM;
 561                }
 562                cmd->pdu_list = pdu;
 563                cmd->pdu_count = pdu_count;
 564        }
 565
 566        return iscsit_do_build_pdu_and_seq_lists(cmd, &bl);
 567}
 568
 569struct iscsi_pdu *iscsit_get_pdu_holder(
 570        struct iscsi_cmd *cmd,
 571        u32 offset,
 572        u32 length)
 573{
 574        u32 i;
 575        struct iscsi_pdu *pdu = NULL;
 576
 577        if (!cmd->pdu_list) {
 578                pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
 579                return NULL;
 580        }
 581
 582        pdu = &cmd->pdu_list[0];
 583
 584        for (i = 0; i < cmd->pdu_count; i++)
 585                if ((pdu[i].offset == offset) && (pdu[i].length == length))
 586                        return &pdu[i];
 587
 588        pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
 589                " %u, Length: %u\n", cmd->init_task_tag, offset, length);
 590        return NULL;
 591}
 592
 593struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(
 594        struct iscsi_cmd *cmd,
 595        struct iscsi_seq *seq)
 596{
 597        u32 i;
 598        struct iscsi_conn *conn = cmd->conn;
 599        struct iscsi_pdu *pdu = NULL;
 600
 601        if (!cmd->pdu_list) {
 602                pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
 603                return NULL;
 604        }
 605
 606        if (conn->sess->sess_ops->DataSequenceInOrder) {
 607redo:
 608                pdu = &cmd->pdu_list[cmd->pdu_start];
 609
 610                for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) {
 611                        pr_debug("pdu[i].seq_no: %d, pdu[i].pdu"
 612                                "_send_order: %d, pdu[i].offset: %d,"
 613                                " pdu[i].length: %d\n", pdu[i].seq_no,
 614                                pdu[i].pdu_send_order, pdu[i].offset,
 615                                pdu[i].length);
 616
 617                        if (pdu[i].pdu_send_order == cmd->pdu_send_order) {
 618                                cmd->pdu_send_order++;
 619                                return &pdu[i];
 620                        }
 621                }
 622
 623                cmd->pdu_start += cmd->pdu_send_order;
 624                cmd->pdu_send_order = 0;
 625                cmd->seq_no++;
 626
 627                if (cmd->pdu_start < cmd->pdu_count)
 628                        goto redo;
 629
 630                pr_err("Command ITT: 0x%08x unable to locate"
 631                        " struct iscsi_pdu for cmd->pdu_send_order: %u.\n",
 632                        cmd->init_task_tag, cmd->pdu_send_order);
 633                return NULL;
 634        } else {
 635                if (!seq) {
 636                        pr_err("struct iscsi_seq is NULL!\n");
 637                        return NULL;
 638                }
 639
 640                pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
 641                        " seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count,
 642                        seq->seq_no);
 643
 644                pdu = &cmd->pdu_list[seq->pdu_start];
 645
 646                if (seq->pdu_send_order == seq->pdu_count) {
 647                        pr_err("Command ITT: 0x%08x seq->pdu_send"
 648                                "_order: %u equals seq->pdu_count: %u\n",
 649                                cmd->init_task_tag, seq->pdu_send_order,
 650                                seq->pdu_count);
 651                        return NULL;
 652                }
 653
 654                for (i = 0; i < seq->pdu_count; i++) {
 655                        if (pdu[i].pdu_send_order == seq->pdu_send_order) {
 656                                seq->pdu_send_order++;
 657                                return &pdu[i];
 658                        }
 659                }
 660
 661                pr_err("Command ITT: 0x%08x unable to locate iscsi"
 662                        "_pdu_t for seq->pdu_send_order: %u.\n",
 663                        cmd->init_task_tag, seq->pdu_send_order);
 664                return NULL;
 665        }
 666
 667        return NULL;
 668}
 669
 670struct iscsi_seq *iscsit_get_seq_holder(
 671        struct iscsi_cmd *cmd,
 672        u32 offset,
 673        u32 length)
 674{
 675        u32 i;
 676
 677        if (!cmd->seq_list) {
 678                pr_err("struct iscsi_cmd->seq_list is NULL!\n");
 679                return NULL;
 680        }
 681
 682        for (i = 0; i < cmd->seq_count; i++) {
 683                pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
 684                        "xfer_len: %d, seq_list[i].seq_no %u\n",
 685                        cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len,
 686                        cmd->seq_list[i].seq_no);
 687
 688                if ((cmd->seq_list[i].orig_offset +
 689                                cmd->seq_list[i].xfer_len) >=
 690                                (offset + length))
 691                        return &cmd->seq_list[i];
 692        }
 693
 694        pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
 695                " Offset: %u, Length: %u\n", cmd->init_task_tag, offset,
 696                length);
 697        return NULL;
 698}
 699