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