1/******************************************************************************* 2 * This file contains main functions related to iSCSI DataSequenceInOrder=No 3 * and DataPDUInOrder=No. 4 * 5 \u00a9 Copyright 2007-2011 RisingTide Systems LLC. 6 * 7 * Licensed to the Linux Foundation under the General Public License (GPL) version 2. 8 * 9 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> 10 * 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. 15 * 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 ******************************************************************************/ 21 22#include <linux/slab.h> 23#include <linux/random.h> 24 25#include "iscsi_target_core.h" 26#include "iscsi_target_util.h" 27#include "iscsi_target_seq_pdu_list.h" 28 29#define OFFLOAD_BUF_SIZE 32768 30 31void 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 49void 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 65static void iscsit_ordered_seq_lists( 66 struct iscsi_cmd *cmd, 67 u8 type) 68{ 69 u32 i, seq_count = 0; 70 71 for (i = 0; i < cmd->seq_count; i++) { 72 if (cmd->seq_list[i].type != SEQTYPE_NORMAL) 73 continue; 74 cmd->seq_list[i].seq_send_order = seq_count++; 75 } 76} 77 78static void iscsit_ordered_pdu_lists( 79 struct iscsi_cmd *cmd, 80 u8 type) 81{ 82 u32 i, pdu_send_order = 0, seq_no = 0; 83 84 for (i = 0; i < cmd->pdu_count; i++) { 85redo: 86 if (cmd->pdu_list[i].seq_no == seq_no) { 87 cmd->pdu_list[i].pdu_send_order = pdu_send_order++; 88 continue; 89 } 90 seq_no++; 91 pdu_send_order = 0; 92 goto redo; 93 } 94} 95 96/* 97 * Generate count random values into array. 98 * Use 0x80000000 to mark generates valued in array[]. 99 */ 100static void iscsit_create_random_array(u32 *array, u32 count) 101{ 102 int i, j, k; 103 104 if (count == 1) { 105 array[0] = 0; 106 return; 107 } 108 109 for (i = 0; i < count; i++) { 110redo: 111 get_random_bytes(&j, sizeof(u32)); 112 j = (1 + (int) (9999 + 1) - j) % count; 113 for (k = 0; k < i + 1; k++) { 114 j |= 0x80000000; 115 if ((array[k] & 0x80000000) && (array[k] == j)) 116 goto redo; 117 } 118 array[i] = j; 119 } 120 121 for (i = 0; i < count; i++) 122 array[i] &= ~0x80000000; 123} 124 125static int iscsit_randomize_pdu_lists( 126 struct iscsi_cmd *cmd, 127 u8 type) 128{ 129 int i = 0; 130 u32 *array, pdu_count, seq_count = 0, seq_no = 0, seq_offset = 0; 131 132 for (pdu_count = 0; pdu_count < cmd->pdu_count; pdu_count++) { 133redo: 134 if (cmd->pdu_list[pdu_count].seq_no == seq_no) { 135 seq_count++; 136 continue; 137 } 138 array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL); 139 if (!array) { 140 pr_err("Unable to allocate memory" 141 " for random array.\n"); 142 return -1; 143 } 144 iscsit_create_random_array(array, seq_count); 145 146 for (i = 0; i < seq_count; i++) 147 cmd->pdu_list[seq_offset+i].pdu_send_order = array[i]; 148 149 kfree(array); 150 151 seq_offset += seq_count; 152 seq_count = 0; 153 seq_no++; 154 goto redo; 155 } 156 157 if (seq_count) { 158 array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL); 159 if (!array) { 160 pr_err("Unable to allocate memory for" 161 " random array.\n"); 162 return -1; 163 } 164 iscsit_create_random_array(array, seq_count); 165 166 for (i = 0; i < seq_count; i++) 167 cmd->pdu_list[seq_offset+i].pdu_send_order = array[i]; 168 169 kfree(array); 170 } 171 172 return 0; 173} 174 175static int iscsit_randomize_seq_lists( 176 struct iscsi_cmd *cmd, 177 u8 type) 178{ 179 int i, j = 0; 180 u32 *array, seq_count = cmd->seq_count; 181 182 if ((type == PDULIST_IMMEDIATE) || (type == PDULIST_UNSOLICITED)) 183 seq_count--; 184 else if (type == PDULIST_IMMEDIATE_AND_UNSOLICITED) 185 seq_count -= 2; 186 187 if (!seq_count) 188 return 0; 189 190 array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL); 191 if (!array) { 192 pr_err("Unable to allocate memory for random array.\n"); 193 return -1; 194 } 195 iscsit_create_random_array(array, seq_count); 196 197 for (i = 0; i < cmd->seq_count; i++) { 198 if (cmd->seq_list[i].type != SEQTYPE_NORMAL) 199 continue; 200 cmd->seq_list[i].seq_send_order = array[j++]; 201 } 202 203 kfree(array); 204 return 0; 205} 206 207static void iscsit_determine_counts_for_list( 208 struct iscsi_cmd *cmd, 209 struct iscsi_build_list *bl, 210 u32 *seq_count, 211 u32 *pdu_count) 212{ 213 int check_immediate = 0; 214 u32 burstlength = 0, offset = 0; 215 u32 unsolicited_data_length = 0; 216 struct iscsi_conn *conn = cmd->conn; 217 218 if ((bl->type == PDULIST_IMMEDIATE) || 219 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED)) 220 check_immediate = 1; 221 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; 227 228 while (offset < cmd->data_length) { 229 *pdu_count += 1; 230 231 if (check_immediate) { 232 check_immediate = 0; 233 offset += bl->immediate_data_length; 234 *seq_count += 1; 235 if (unsolicited_data_length) 236 unsolicited_data_length -= 237 bl->immediate_data_length; 238 continue; 239 } 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); 246 continue; 247 } 248 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) 249 >= conn->sess->sess_ops->FirstBurstLength) { 250 unsolicited_data_length -= 251 (conn->sess->sess_ops->FirstBurstLength - 252 offset); 253 offset += (conn->sess->sess_ops->FirstBurstLength - 254 offset); 255 burstlength = 0; 256 *seq_count += 1; 257 continue; 258 } 259 260 offset += conn->conn_ops->MaxRecvDataSegmentLength; 261 unsolicited_data_length -= 262 conn->conn_ops->MaxRecvDataSegmentLength; 263 continue; 264 } 265 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= 266 cmd->data_length) { 267 offset += (cmd->data_length - offset); 268 continue; 269 } 270 if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >= 271 conn->sess->sess_ops->MaxBurstLength) { 272 offset += (conn->sess->sess_ops->MaxBurstLength - 273 burstlength); 274 burstlength = 0; 275 *seq_count += 1; 276 continue; 277 } 278 279 burstlength += conn->conn_ops->MaxRecvDataSegmentLength; 280 offset += conn->conn_ops->MaxRecvDataSegmentLength; 281 } 282} 283 284 285/* 286 * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No 287 * and DataPDUInOrder=No. 288 */ 289static int iscsit_build_pdu_and_seq_list( 290 struct iscsi_cmd *cmd, 291 struct iscsi_build_list *bl) 292{ 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; 299 300 datapduinorder = conn->sess->sess_ops->DataPDUInOrder; 301 datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder; 302 303 if ((bl->type == PDULIST_IMMEDIATE) || 304 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED)) 305 check_immediate = 1; 306 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; 312 313 while (offset < cmd->data_length) { 314 pdu_count++; 315 if (!datapduinorder) { 316 pdu[i].offset = offset; 317 pdu[i].seq_no = seq_no; 318 } 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; 324 } 325 326 if (check_immediate) { 327 check_immediate = 0; 328 if (!datapduinorder) { 329 pdu[i].type = PDUTYPE_IMMEDIATE; 330 pdu[i++].length = bl->immediate_data_length; 331 } 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; 337 } 338 offset += bl->immediate_data_length; 339 pdu_count = 0; 340 seq_no++; 341 if (unsolicited_data_length) 342 unsolicited_data_length -= 343 bl->immediate_data_length; 344 continue; 345 } 346 if (unsolicited_data_length > 0) { 347 if ((offset + 348 conn->conn_ops->MaxRecvDataSegmentLength) >= 349 cmd->data_length) { 350 if (!datapduinorder) { 351 pdu[i].type = PDUTYPE_UNSOLICITED; 352 pdu[i].length = 353 (cmd->data_length - offset); 354 } 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)); 360 } 361 unsolicited_data_length -= 362 (cmd->data_length - offset); 363 offset += (cmd->data_length - offset); 364 continue; 365 } 366 if ((offset + 367 conn->conn_ops->MaxRecvDataSegmentLength) >= 368 conn->sess->sess_ops->FirstBurstLength) { 369 if (!datapduinorder) { 370 pdu[i].type = PDUTYPE_UNSOLICITED; 371 pdu[i++].length = 372 (conn->sess->sess_ops->FirstBurstLength - 373 offset); 374 } 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 - 380 offset)); 381 } 382 unsolicited_data_length -= 383 (conn->sess->sess_ops->FirstBurstLength - 384 offset); 385 offset += (conn->sess->sess_ops->FirstBurstLength - 386 offset); 387 burstlength = 0; 388 pdu_count = 0; 389 seq_no++; 390 continue; 391 } 392 393 if (!datapduinorder) { 394 pdu[i].type = PDUTYPE_UNSOLICITED; 395 pdu[i++].length = 396 conn->conn_ops->MaxRecvDataSegmentLength; 397 } 398 burstlength += conn->conn_ops->MaxRecvDataSegmentLength; 399 offset += conn->conn_ops->MaxRecvDataSegmentLength; 400 unsolicited_data_length -= 401 conn->conn_ops->MaxRecvDataSegmentLength; 402 continue; 403 } 404 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= 405 cmd->data_length) { 406 if (!datapduinorder) { 407 pdu[i].type = PDUTYPE_NORMAL; 408 pdu[i].length = (cmd->data_length - offset); 409 } 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)); 415 } 416 offset += (cmd->data_length - offset); 417 continue; 418 } 419 if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >= 420 conn->sess->sess_ops->MaxBurstLength) { 421 if (!datapduinorder) { 422 pdu[i].type = PDUTYPE_NORMAL; 423 pdu[i++].length = 424 (conn->sess->sess_ops->MaxBurstLength - 425 burstlength); 426 } 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 - 432 burstlength)); 433 } 434 offset += (conn->sess->sess_ops->MaxBurstLength - 435 burstlength); 436 burstlength = 0; 437 pdu_count = 0; 438 seq_no++; 439 continue; 440 } 441 442 if (!datapduinorder) { 443 pdu[i].type = PDUTYPE_NORMAL; 444 pdu[i++].length = 445 conn->conn_ops->MaxRecvDataSegmentLength; 446 } 447 burstlength += conn->conn_ops->MaxRecvDataSegmentLength; 448 offset += conn->conn_ops->MaxRecvDataSegmentLength; 449 } 450 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) 455 < 0) 456 return -1; 457 } else 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) 462 < 0) 463 return -1; 464 } else 465 iscsit_ordered_seq_lists(cmd, bl->type); 466 } 467#if 0 468 iscsit_dump_seq_list(cmd); 469#endif 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#if 0 488 iscsit_dump_pdu_list(cmd); 489#endif 490 } 491 492 return 0; 493} 494 495/* 496 * Only called while DataSequenceInOrder=No or DataPDUInOrder=No. 497 */ 498int iscsit_do_build_list( 499 struct iscsi_cmd *cmd, 500 struct iscsi_build_list *bl) 501{ 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; 506 507 iscsit_determine_counts_for_list(cmd, bl, &seq_count, &pdu_count); 508 509 if (!conn->sess->sess_ops->DataSequenceInOrder) { 510 seq = kzalloc(seq_count * sizeof(struct iscsi_seq), GFP_ATOMIC); 511 if (!seq) { 512 pr_err("Unable to allocate struct iscsi_seq list\n"); 513 return -1; 514 } 515 cmd->seq_list = seq; 516 cmd->seq_count = seq_count; 517 } 518 519 if (!conn->sess->sess_ops->DataPDUInOrder) { 520 pdu = kzalloc(pdu_count * sizeof(struct iscsi_pdu), GFP_ATOMIC); 521 if (!pdu) { 522 pr_err("Unable to allocate struct iscsi_pdu list.\n"); 523 kfree(seq); 524 return -1; 525 } 526 cmd->pdu_list = pdu; 527 cmd->pdu_count = pdu_count; 528 } 529 530 return iscsit_build_pdu_and_seq_list(cmd, bl); 531} 532 533struct iscsi_pdu *iscsit_get_pdu_holder( 534 struct iscsi_cmd *cmd, 535 u32 offset, 536 u32 length) 537{ 538 u32 i; 539 struct iscsi_pdu *pdu = NULL; 540 541 if (!cmd->pdu_list) { 542 pr_err("struct iscsi_cmd->pdu_list is NULL!\n"); 543 return NULL; 544 } 545 546 pdu = &cmd->pdu_list[0]; 547 548 for (i = 0; i < cmd->pdu_count; i++) 549 if ((pdu[i].offset == offset) && (pdu[i].length == length)) 550 return &pdu[i]; 551 552 pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:" 553 " %u, Length: %u\n", cmd->init_task_tag, offset, length); 554 return NULL; 555} 556 557struct iscsi_pdu *iscsit_get_pdu_holder_for_seq( 558 struct iscsi_cmd *cmd, 559 struct iscsi_seq *seq) 560{ 561 u32 i; 562 struct iscsi_conn *conn = cmd->conn; 563 struct iscsi_pdu *pdu = NULL; 564 565 if (!cmd->pdu_list) { 566 pr_err("struct iscsi_cmd->pdu_list is NULL!\n"); 567 return NULL; 568 } 569 570 if (conn->sess->sess_ops->DataSequenceInOrder) { 571redo: 572 pdu = &cmd->pdu_list[cmd->pdu_start]; 573 574 for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) { 575#if 0 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, 580 pdu[i].length); 581#endif 582 if (pdu[i].pdu_send_order == cmd->pdu_send_order) { 583 cmd->pdu_send_order++; 584 return &pdu[i]; 585 } 586 } 587 588 cmd->pdu_start += cmd->pdu_send_order; 589 cmd->pdu_send_order = 0; 590 cmd->seq_no++; 591 592 if (cmd->pdu_start < cmd->pdu_count) 593 goto redo; 594 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); 598 return NULL; 599 } else { 600 if (!seq) { 601 pr_err("struct iscsi_seq is NULL!\n"); 602 return NULL; 603 } 604#if 0 605 pr_debug("seq->pdu_start: %d, seq->pdu_count: %d," 606 " seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count, 607 seq->seq_no); 608#endif 609 pdu = &cmd->pdu_list[seq->pdu_start]; 610 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, 615 seq->pdu_count); 616 return NULL; 617 } 618 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++; 622 return &pdu[i]; 623 } 624 } 625 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); 629 return NULL; 630 } 631 632 return NULL; 633} 634 635struct iscsi_seq *iscsit_get_seq_holder( 636 struct iscsi_cmd *cmd, 637 u32 offset, 638 u32 length) 639{ 640 u32 i; 641 642 if (!cmd->seq_list) { 643 pr_err("struct iscsi_cmd->seq_list is NULL!\n"); 644 return NULL; 645 } 646 647 for (i = 0; i < cmd->seq_count; i++) { 648#if 0 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); 653#endif 654 if ((cmd->seq_list[i].orig_offset + 655 cmd->seq_list[i].xfer_len) >= 656 (offset + length)) 657 return &cmd->seq_list[i]; 658 } 659 660 pr_err("Unable to locate Sequence holder for ITT: 0x%08x," 661 " Offset: %u, Length: %u\n", cmd->init_task_tag, offset, 662 length); 663 return NULL; 664} 665