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 29 static 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 47 static 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 63 static void iscsit_dump_seq_list(struct iscsi_cmd *cmd) {} 64 static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) {} 65 #endif 66 67 static 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 80 static 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++) { 87 redo: 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 */ 102 static 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++) { 112 redo: 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 127 static 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++) { 135 redo: 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 177 static 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 209 static 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 */ 293 static 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 494 int 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 569 struct 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 593 struct 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) { 607 redo: 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 670 struct 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