blob: 85a306e067ba81dd693523683e93d0e5534fb49c [file] [log] [blame]
Nicholas Bellingere48354c2011-07-23 06:43:04 +00001/*******************************************************************************
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"
Andy Grover4334e492012-04-03 15:51:25 -070027#include "iscsi_target_tpg.h"
Nicholas Bellingere48354c2011-07-23 06:43:04 +000028#include "iscsi_target_seq_pdu_list.h"
29
30#define OFFLOAD_BUF_SIZE 32768
31
Andy Grover8b1e1242012-04-03 15:51:12 -070032#ifdef DEBUG
33static void iscsit_dump_seq_list(struct iscsi_cmd *cmd)
Nicholas Bellingere48354c2011-07-23 06:43:04 +000034{
35 int i;
36 struct iscsi_seq *seq;
37
38 pr_debug("Dumping Sequence List for ITT: 0x%08x:\n",
39 cmd->init_task_tag);
40
41 for (i = 0; i < cmd->seq_count; i++) {
42 seq = &cmd->seq_list[i];
43 pr_debug("i: %d, pdu_start: %d, pdu_count: %d,"
44 " offset: %d, xfer_len: %d, seq_send_order: %d,"
45 " seq_no: %d\n", i, seq->pdu_start, seq->pdu_count,
46 seq->offset, seq->xfer_len, seq->seq_send_order,
47 seq->seq_no);
48 }
49}
50
Andy Grover8b1e1242012-04-03 15:51:12 -070051static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd)
Nicholas Bellingere48354c2011-07-23 06:43:04 +000052{
53 int i;
54 struct iscsi_pdu *pdu;
55
56 pr_debug("Dumping PDU List for ITT: 0x%08x:\n",
57 cmd->init_task_tag);
58
59 for (i = 0; i < cmd->pdu_count; i++) {
60 pdu = &cmd->pdu_list[i];
61 pr_debug("i: %d, offset: %d, length: %d,"
62 " pdu_send_order: %d, seq_no: %d\n", i, pdu->offset,
63 pdu->length, pdu->pdu_send_order, pdu->seq_no);
64 }
65}
Andy Grover8b1e1242012-04-03 15:51:12 -070066#else
67static void iscsit_dump_seq_list(struct iscsi_cmd *cmd) {}
68static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) {}
69#endif
Nicholas Bellingere48354c2011-07-23 06:43:04 +000070
71static void iscsit_ordered_seq_lists(
72 struct iscsi_cmd *cmd,
73 u8 type)
74{
75 u32 i, seq_count = 0;
76
77 for (i = 0; i < cmd->seq_count; i++) {
78 if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
79 continue;
80 cmd->seq_list[i].seq_send_order = seq_count++;
81 }
82}
83
84static void iscsit_ordered_pdu_lists(
85 struct iscsi_cmd *cmd,
86 u8 type)
87{
88 u32 i, pdu_send_order = 0, seq_no = 0;
89
90 for (i = 0; i < cmd->pdu_count; i++) {
91redo:
92 if (cmd->pdu_list[i].seq_no == seq_no) {
93 cmd->pdu_list[i].pdu_send_order = pdu_send_order++;
94 continue;
95 }
96 seq_no++;
97 pdu_send_order = 0;
98 goto redo;
99 }
100}
101
102/*
103 * Generate count random values into array.
104 * Use 0x80000000 to mark generates valued in array[].
105 */
106static void iscsit_create_random_array(u32 *array, u32 count)
107{
108 int i, j, k;
109
110 if (count == 1) {
111 array[0] = 0;
112 return;
113 }
114
115 for (i = 0; i < count; i++) {
116redo:
117 get_random_bytes(&j, sizeof(u32));
118 j = (1 + (int) (9999 + 1) - j) % count;
119 for (k = 0; k < i + 1; k++) {
120 j |= 0x80000000;
121 if ((array[k] & 0x80000000) && (array[k] == j))
122 goto redo;
123 }
124 array[i] = j;
125 }
126
127 for (i = 0; i < count; i++)
128 array[i] &= ~0x80000000;
129}
130
131static int iscsit_randomize_pdu_lists(
132 struct iscsi_cmd *cmd,
133 u8 type)
134{
135 int i = 0;
136 u32 *array, pdu_count, seq_count = 0, seq_no = 0, seq_offset = 0;
137
138 for (pdu_count = 0; pdu_count < cmd->pdu_count; pdu_count++) {
139redo:
140 if (cmd->pdu_list[pdu_count].seq_no == seq_no) {
141 seq_count++;
142 continue;
143 }
Dan Carpenter381e3092012-04-17 09:33:59 +0300144 array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000145 if (!array) {
146 pr_err("Unable to allocate memory"
147 " for random array.\n");
Dan Carpenter381e3092012-04-17 09:33:59 +0300148 return -ENOMEM;
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000149 }
150 iscsit_create_random_array(array, seq_count);
151
152 for (i = 0; i < seq_count; i++)
153 cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
154
155 kfree(array);
156
157 seq_offset += seq_count;
158 seq_count = 0;
159 seq_no++;
160 goto redo;
161 }
162
163 if (seq_count) {
Dan Carpenter381e3092012-04-17 09:33:59 +0300164 array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000165 if (!array) {
166 pr_err("Unable to allocate memory for"
167 " random array.\n");
Dan Carpenter381e3092012-04-17 09:33:59 +0300168 return -ENOMEM;
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000169 }
170 iscsit_create_random_array(array, seq_count);
171
172 for (i = 0; i < seq_count; i++)
173 cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
174
175 kfree(array);
176 }
177
178 return 0;
179}
180
181static int iscsit_randomize_seq_lists(
182 struct iscsi_cmd *cmd,
183 u8 type)
184{
185 int i, j = 0;
186 u32 *array, seq_count = cmd->seq_count;
187
188 if ((type == PDULIST_IMMEDIATE) || (type == PDULIST_UNSOLICITED))
189 seq_count--;
190 else if (type == PDULIST_IMMEDIATE_AND_UNSOLICITED)
191 seq_count -= 2;
192
193 if (!seq_count)
194 return 0;
195
Dan Carpenter381e3092012-04-17 09:33:59 +0300196 array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000197 if (!array) {
198 pr_err("Unable to allocate memory for random array.\n");
Dan Carpenter381e3092012-04-17 09:33:59 +0300199 return -ENOMEM;
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000200 }
201 iscsit_create_random_array(array, seq_count);
202
203 for (i = 0; i < cmd->seq_count; i++) {
204 if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
205 continue;
206 cmd->seq_list[i].seq_send_order = array[j++];
207 }
208
209 kfree(array);
210 return 0;
211}
212
213static void iscsit_determine_counts_for_list(
214 struct iscsi_cmd *cmd,
215 struct iscsi_build_list *bl,
216 u32 *seq_count,
217 u32 *pdu_count)
218{
219 int check_immediate = 0;
220 u32 burstlength = 0, offset = 0;
221 u32 unsolicited_data_length = 0;
222 struct iscsi_conn *conn = cmd->conn;
223
224 if ((bl->type == PDULIST_IMMEDIATE) ||
225 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
226 check_immediate = 1;
227
228 if ((bl->type == PDULIST_UNSOLICITED) ||
229 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
Andy Groverebf1d952012-04-03 15:51:24 -0700230 unsolicited_data_length = min(cmd->se_cmd.data_length,
231 conn->sess->sess_ops->FirstBurstLength);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000232
Andy Groverebf1d952012-04-03 15:51:24 -0700233 while (offset < cmd->se_cmd.data_length) {
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000234 *pdu_count += 1;
235
236 if (check_immediate) {
237 check_immediate = 0;
238 offset += bl->immediate_data_length;
239 *seq_count += 1;
240 if (unsolicited_data_length)
241 unsolicited_data_length -=
242 bl->immediate_data_length;
243 continue;
244 }
245 if (unsolicited_data_length > 0) {
246 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
Andy Groverebf1d952012-04-03 15:51:24 -0700247 >= cmd->se_cmd.data_length) {
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000248 unsolicited_data_length -=
Andy Groverebf1d952012-04-03 15:51:24 -0700249 (cmd->se_cmd.data_length - offset);
250 offset += (cmd->se_cmd.data_length - offset);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000251 continue;
252 }
253 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
254 >= conn->sess->sess_ops->FirstBurstLength) {
255 unsolicited_data_length -=
256 (conn->sess->sess_ops->FirstBurstLength -
257 offset);
258 offset += (conn->sess->sess_ops->FirstBurstLength -
259 offset);
260 burstlength = 0;
261 *seq_count += 1;
262 continue;
263 }
264
265 offset += conn->conn_ops->MaxRecvDataSegmentLength;
266 unsolicited_data_length -=
267 conn->conn_ops->MaxRecvDataSegmentLength;
268 continue;
269 }
270 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
Andy Groverebf1d952012-04-03 15:51:24 -0700271 cmd->se_cmd.data_length) {
272 offset += (cmd->se_cmd.data_length - offset);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000273 continue;
274 }
275 if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
276 conn->sess->sess_ops->MaxBurstLength) {
277 offset += (conn->sess->sess_ops->MaxBurstLength -
278 burstlength);
279 burstlength = 0;
280 *seq_count += 1;
281 continue;
282 }
283
284 burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
285 offset += conn->conn_ops->MaxRecvDataSegmentLength;
286 }
287}
288
289
290/*
Andy Grover4334e492012-04-03 15:51:25 -0700291 * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
292 * or DataPDUInOrder=No.
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000293 */
Andy Grover4334e492012-04-03 15:51:25 -0700294static int iscsit_do_build_pdu_and_seq_lists(
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000295 struct iscsi_cmd *cmd,
296 struct iscsi_build_list *bl)
297{
298 int check_immediate = 0, datapduinorder, datasequenceinorder;
299 u32 burstlength = 0, offset = 0, i = 0;
300 u32 pdu_count = 0, seq_no = 0, unsolicited_data_length = 0;
301 struct iscsi_conn *conn = cmd->conn;
302 struct iscsi_pdu *pdu = cmd->pdu_list;
303 struct iscsi_seq *seq = cmd->seq_list;
304
305 datapduinorder = conn->sess->sess_ops->DataPDUInOrder;
306 datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder;
307
308 if ((bl->type == PDULIST_IMMEDIATE) ||
309 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
310 check_immediate = 1;
311
312 if ((bl->type == PDULIST_UNSOLICITED) ||
313 (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
Andy Groverebf1d952012-04-03 15:51:24 -0700314 unsolicited_data_length = min(cmd->se_cmd.data_length,
315 conn->sess->sess_ops->FirstBurstLength);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000316
Andy Groverebf1d952012-04-03 15:51:24 -0700317 while (offset < cmd->se_cmd.data_length) {
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000318 pdu_count++;
319 if (!datapduinorder) {
320 pdu[i].offset = offset;
321 pdu[i].seq_no = seq_no;
322 }
323 if (!datasequenceinorder && (pdu_count == 1)) {
324 seq[seq_no].pdu_start = i;
325 seq[seq_no].seq_no = seq_no;
326 seq[seq_no].offset = offset;
327 seq[seq_no].orig_offset = offset;
328 }
329
330 if (check_immediate) {
331 check_immediate = 0;
332 if (!datapduinorder) {
333 pdu[i].type = PDUTYPE_IMMEDIATE;
334 pdu[i++].length = bl->immediate_data_length;
335 }
336 if (!datasequenceinorder) {
337 seq[seq_no].type = SEQTYPE_IMMEDIATE;
338 seq[seq_no].pdu_count = 1;
339 seq[seq_no].xfer_len =
340 bl->immediate_data_length;
341 }
342 offset += bl->immediate_data_length;
343 pdu_count = 0;
344 seq_no++;
345 if (unsolicited_data_length)
346 unsolicited_data_length -=
347 bl->immediate_data_length;
348 continue;
349 }
350 if (unsolicited_data_length > 0) {
351 if ((offset +
352 conn->conn_ops->MaxRecvDataSegmentLength) >=
Andy Groverebf1d952012-04-03 15:51:24 -0700353 cmd->se_cmd.data_length) {
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000354 if (!datapduinorder) {
355 pdu[i].type = PDUTYPE_UNSOLICITED;
356 pdu[i].length =
Andy Groverebf1d952012-04-03 15:51:24 -0700357 (cmd->se_cmd.data_length - offset);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000358 }
359 if (!datasequenceinorder) {
360 seq[seq_no].type = SEQTYPE_UNSOLICITED;
361 seq[seq_no].pdu_count = pdu_count;
362 seq[seq_no].xfer_len = (burstlength +
Andy Groverebf1d952012-04-03 15:51:24 -0700363 (cmd->se_cmd.data_length - offset));
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000364 }
365 unsolicited_data_length -=
Andy Groverebf1d952012-04-03 15:51:24 -0700366 (cmd->se_cmd.data_length - offset);
367 offset += (cmd->se_cmd.data_length - offset);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000368 continue;
369 }
370 if ((offset +
371 conn->conn_ops->MaxRecvDataSegmentLength) >=
372 conn->sess->sess_ops->FirstBurstLength) {
373 if (!datapduinorder) {
374 pdu[i].type = PDUTYPE_UNSOLICITED;
375 pdu[i++].length =
376 (conn->sess->sess_ops->FirstBurstLength -
377 offset);
378 }
379 if (!datasequenceinorder) {
380 seq[seq_no].type = SEQTYPE_UNSOLICITED;
381 seq[seq_no].pdu_count = pdu_count;
382 seq[seq_no].xfer_len = (burstlength +
383 (conn->sess->sess_ops->FirstBurstLength -
384 offset));
385 }
386 unsolicited_data_length -=
387 (conn->sess->sess_ops->FirstBurstLength -
388 offset);
389 offset += (conn->sess->sess_ops->FirstBurstLength -
390 offset);
391 burstlength = 0;
392 pdu_count = 0;
393 seq_no++;
394 continue;
395 }
396
397 if (!datapduinorder) {
398 pdu[i].type = PDUTYPE_UNSOLICITED;
399 pdu[i++].length =
400 conn->conn_ops->MaxRecvDataSegmentLength;
401 }
402 burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
403 offset += conn->conn_ops->MaxRecvDataSegmentLength;
404 unsolicited_data_length -=
405 conn->conn_ops->MaxRecvDataSegmentLength;
406 continue;
407 }
408 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
Andy Groverebf1d952012-04-03 15:51:24 -0700409 cmd->se_cmd.data_length) {
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000410 if (!datapduinorder) {
411 pdu[i].type = PDUTYPE_NORMAL;
Andy Groverebf1d952012-04-03 15:51:24 -0700412 pdu[i].length = (cmd->se_cmd.data_length - offset);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000413 }
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 +
Andy Groverebf1d952012-04-03 15:51:24 -0700418 (cmd->se_cmd.data_length - offset));
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000419 }
Andy Groverebf1d952012-04-03 15:51:24 -0700420 offset += (cmd->se_cmd.data_length - offset);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000421 continue;
422 }
423 if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
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 =
449 conn->conn_ops->MaxRecvDataSegmentLength;
450 }
451 burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
452 offset += conn->conn_ops->MaxRecvDataSegmentLength;
453 }
454
455 if (!datasequenceinorder) {
456 if (bl->data_direction & ISCSI_PDU_WRITE) {
457 if (bl->randomize & RANDOM_R2T_OFFSETS) {
458 if (iscsit_randomize_seq_lists(cmd, bl->type)
459 < 0)
460 return -1;
461 } else
462 iscsit_ordered_seq_lists(cmd, bl->type);
463 } else if (bl->data_direction & ISCSI_PDU_READ) {
464 if (bl->randomize & RANDOM_DATAIN_SEQ_OFFSETS) {
465 if (iscsit_randomize_seq_lists(cmd, bl->type)
466 < 0)
467 return -1;
468 } else
469 iscsit_ordered_seq_lists(cmd, bl->type);
470 }
Andy Grover8b1e1242012-04-03 15:51:12 -0700471
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000472 iscsit_dump_seq_list(cmd);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000473 }
474 if (!datapduinorder) {
475 if (bl->data_direction & ISCSI_PDU_WRITE) {
476 if (bl->randomize & RANDOM_DATAOUT_PDU_OFFSETS) {
477 if (iscsit_randomize_pdu_lists(cmd, bl->type)
478 < 0)
479 return -1;
480 } else
481 iscsit_ordered_pdu_lists(cmd, bl->type);
482 } else if (bl->data_direction & ISCSI_PDU_READ) {
483 if (bl->randomize & RANDOM_DATAIN_PDU_OFFSETS) {
484 if (iscsit_randomize_pdu_lists(cmd, bl->type)
485 < 0)
486 return -1;
487 } else
488 iscsit_ordered_pdu_lists(cmd, bl->type);
489 }
Andy Grover8b1e1242012-04-03 15:51:12 -0700490
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000491 iscsit_dump_pdu_list(cmd);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000492 }
493
494 return 0;
495}
496
Andy Grover4334e492012-04-03 15:51:25 -0700497int iscsit_build_pdu_and_seq_lists(
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000498 struct iscsi_cmd *cmd,
Andy Grover4334e492012-04-03 15:51:25 -0700499 u32 immediate_data_length)
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000500{
Andy Grover4334e492012-04-03 15:51:25 -0700501 struct iscsi_build_list bl;
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000502 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
Andy Grover4334e492012-04-03 15:51:25 -0700507 struct iscsi_session *sess = conn->sess;
508 struct iscsi_node_attrib *na;
509
510 /*
511 * Do nothing if no OOO shenanigans
512 */
513 if (sess->sess_ops->DataSequenceInOrder &&
514 sess->sess_ops->DataPDUInOrder)
515 return 0;
516
517 if (cmd->data_direction == DMA_NONE)
518 return 0;
519
520 na = iscsit_tpg_get_node_attrib(sess);
521 memset(&bl, 0, sizeof(struct iscsi_build_list));
522
523 if (cmd->data_direction == DMA_FROM_DEVICE) {
524 bl.data_direction = ISCSI_PDU_READ;
525 bl.type = PDULIST_NORMAL;
526 if (na->random_datain_pdu_offsets)
527 bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS;
528 if (na->random_datain_seq_offsets)
529 bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS;
530 } else {
531 bl.data_direction = ISCSI_PDU_WRITE;
532 bl.immediate_data_length = immediate_data_length;
533 if (na->random_r2t_offsets)
534 bl.randomize |= RANDOM_R2T_OFFSETS;
535
536 if (!cmd->immediate_data && !cmd->unsolicited_data)
537 bl.type = PDULIST_NORMAL;
538 else if (cmd->immediate_data && !cmd->unsolicited_data)
539 bl.type = PDULIST_IMMEDIATE;
540 else if (!cmd->immediate_data && cmd->unsolicited_data)
541 bl.type = PDULIST_UNSOLICITED;
542 else if (cmd->immediate_data && cmd->unsolicited_data)
543 bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED;
544 }
545
546 iscsit_determine_counts_for_list(cmd, &bl, &seq_count, &pdu_count);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000547
548 if (!conn->sess->sess_ops->DataSequenceInOrder) {
Dan Carpenter381e3092012-04-17 09:33:59 +0300549 seq = kcalloc(seq_count, sizeof(struct iscsi_seq), GFP_ATOMIC);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000550 if (!seq) {
551 pr_err("Unable to allocate struct iscsi_seq list\n");
Dan Carpenter381e3092012-04-17 09:33:59 +0300552 return -ENOMEM;
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000553 }
554 cmd->seq_list = seq;
555 cmd->seq_count = seq_count;
556 }
557
558 if (!conn->sess->sess_ops->DataPDUInOrder) {
Dan Carpenter381e3092012-04-17 09:33:59 +0300559 pdu = kcalloc(pdu_count, sizeof(struct iscsi_pdu), GFP_ATOMIC);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000560 if (!pdu) {
561 pr_err("Unable to allocate struct iscsi_pdu list.\n");
562 kfree(seq);
Dan Carpenter381e3092012-04-17 09:33:59 +0300563 return -ENOMEM;
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000564 }
565 cmd->pdu_list = pdu;
566 cmd->pdu_count = pdu_count;
567 }
568
Andy Grover4334e492012-04-03 15:51:25 -0700569 return iscsit_do_build_pdu_and_seq_lists(cmd, &bl);
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000570}
571
572struct iscsi_pdu *iscsit_get_pdu_holder(
573 struct iscsi_cmd *cmd,
574 u32 offset,
575 u32 length)
576{
577 u32 i;
578 struct iscsi_pdu *pdu = NULL;
579
580 if (!cmd->pdu_list) {
581 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
582 return NULL;
583 }
584
585 pdu = &cmd->pdu_list[0];
586
587 for (i = 0; i < cmd->pdu_count; i++)
588 if ((pdu[i].offset == offset) && (pdu[i].length == length))
589 return &pdu[i];
590
591 pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
592 " %u, Length: %u\n", cmd->init_task_tag, offset, length);
593 return NULL;
594}
595
596struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(
597 struct iscsi_cmd *cmd,
598 struct iscsi_seq *seq)
599{
600 u32 i;
601 struct iscsi_conn *conn = cmd->conn;
602 struct iscsi_pdu *pdu = NULL;
603
604 if (!cmd->pdu_list) {
605 pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
606 return NULL;
607 }
608
609 if (conn->sess->sess_ops->DataSequenceInOrder) {
610redo:
611 pdu = &cmd->pdu_list[cmd->pdu_start];
612
613 for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) {
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000614 pr_debug("pdu[i].seq_no: %d, pdu[i].pdu"
615 "_send_order: %d, pdu[i].offset: %d,"
616 " pdu[i].length: %d\n", pdu[i].seq_no,
617 pdu[i].pdu_send_order, pdu[i].offset,
618 pdu[i].length);
Andy Grover8b1e1242012-04-03 15:51:12 -0700619
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000620 if (pdu[i].pdu_send_order == cmd->pdu_send_order) {
621 cmd->pdu_send_order++;
622 return &pdu[i];
623 }
624 }
625
626 cmd->pdu_start += cmd->pdu_send_order;
627 cmd->pdu_send_order = 0;
628 cmd->seq_no++;
629
630 if (cmd->pdu_start < cmd->pdu_count)
631 goto redo;
632
633 pr_err("Command ITT: 0x%08x unable to locate"
634 " struct iscsi_pdu for cmd->pdu_send_order: %u.\n",
635 cmd->init_task_tag, cmd->pdu_send_order);
636 return NULL;
637 } else {
638 if (!seq) {
639 pr_err("struct iscsi_seq is NULL!\n");
640 return NULL;
641 }
Andy Grover8b1e1242012-04-03 15:51:12 -0700642
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000643 pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
644 " seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count,
645 seq->seq_no);
Andy Grover8b1e1242012-04-03 15:51:12 -0700646
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000647 pdu = &cmd->pdu_list[seq->pdu_start];
648
649 if (seq->pdu_send_order == seq->pdu_count) {
650 pr_err("Command ITT: 0x%08x seq->pdu_send"
651 "_order: %u equals seq->pdu_count: %u\n",
652 cmd->init_task_tag, seq->pdu_send_order,
653 seq->pdu_count);
654 return NULL;
655 }
656
657 for (i = 0; i < seq->pdu_count; i++) {
658 if (pdu[i].pdu_send_order == seq->pdu_send_order) {
659 seq->pdu_send_order++;
660 return &pdu[i];
661 }
662 }
663
664 pr_err("Command ITT: 0x%08x unable to locate iscsi"
665 "_pdu_t for seq->pdu_send_order: %u.\n",
666 cmd->init_task_tag, seq->pdu_send_order);
667 return NULL;
668 }
669
670 return NULL;
671}
672
673struct iscsi_seq *iscsit_get_seq_holder(
674 struct iscsi_cmd *cmd,
675 u32 offset,
676 u32 length)
677{
678 u32 i;
679
680 if (!cmd->seq_list) {
681 pr_err("struct iscsi_cmd->seq_list is NULL!\n");
682 return NULL;
683 }
684
685 for (i = 0; i < cmd->seq_count; i++) {
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000686 pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
687 "xfer_len: %d, seq_list[i].seq_no %u\n",
688 cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len,
689 cmd->seq_list[i].seq_no);
Andy Grover8b1e1242012-04-03 15:51:12 -0700690
Nicholas Bellingere48354c2011-07-23 06:43:04 +0000691 if ((cmd->seq_list[i].orig_offset +
692 cmd->seq_list[i].xfer_len) >=
693 (offset + length))
694 return &cmd->seq_list[i];
695 }
696
697 pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
698 " Offset: %u, Length: %u\n", cmd->init_task_tag, offset,
699 length);
700 return NULL;
701}