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