1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
29static 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
47static 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
63static void iscsit_dump_seq_list(struct iscsi_cmd *cmd) {}
64static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) {}
65#endif
66
67static 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
80static 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++) {
87redo:
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
100
101
102static 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++) {
112redo:
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
127static 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++) {
135redo:
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
177static 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
209static 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
291
292
293static 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
494int 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
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
569struct 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
593struct 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) {
607redo:
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
670struct 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