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
21static 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
39static 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
55static void iscsit_dump_seq_list(struct iscsit_cmd *cmd) {}
56static void iscsit_dump_pdu_list(struct iscsit_cmd *cmd) {}
57#endif
58
59static 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
72static 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++) {
79redo:
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 */
94static 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++) {
104redo:
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
119static 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++) {
127redo:
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
169static 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
201static 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 */
285static 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
486int 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
561struct 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
585struct 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) {
599redo:
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
662struct 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

source code of linux/drivers/target/iscsi/iscsi_target_seq_pdu_list.c