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