Loading...
1/*******************************************************************************
2 * This file contains the iSCSI Target DataIN value generation functions.
3 *
4 * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
5 *
6 * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
7 *
8 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 ******************************************************************************/
20
21#include <scsi/iscsi_proto.h>
22
23#include "iscsi_target_core.h"
24#include "iscsi_target_seq_pdu_list.h"
25#include "iscsi_target_erl1.h"
26#include "iscsi_target_util.h"
27#include "iscsi_target.h"
28#include "iscsi_target_datain_values.h"
29
30struct iscsi_datain_req *iscsit_allocate_datain_req(void)
31{
32 struct iscsi_datain_req *dr;
33
34 dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC);
35 if (!dr) {
36 pr_err("Unable to allocate memory for"
37 " struct iscsi_datain_req\n");
38 return NULL;
39 }
40 INIT_LIST_HEAD(&dr->dr_list);
41
42 return dr;
43}
44
45void iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
46{
47 spin_lock(&cmd->datain_lock);
48 list_add_tail(&dr->dr_list, &cmd->datain_list);
49 spin_unlock(&cmd->datain_lock);
50}
51
52void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
53{
54 spin_lock(&cmd->datain_lock);
55 list_del(&dr->dr_list);
56 spin_unlock(&cmd->datain_lock);
57
58 kmem_cache_free(lio_dr_cache, dr);
59}
60
61void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd)
62{
63 struct iscsi_datain_req *dr, *dr_tmp;
64
65 spin_lock(&cmd->datain_lock);
66 list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, dr_list) {
67 list_del(&dr->dr_list);
68 kmem_cache_free(lio_dr_cache, dr);
69 }
70 spin_unlock(&cmd->datain_lock);
71}
72
73struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd)
74{
75 struct iscsi_datain_req *dr;
76
77 if (list_empty(&cmd->datain_list)) {
78 pr_err("cmd->datain_list is empty for ITT:"
79 " 0x%08x\n", cmd->init_task_tag);
80 return NULL;
81 }
82 list_for_each_entry(dr, &cmd->datain_list, dr_list)
83 break;
84
85 return dr;
86}
87
88/*
89 * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.
90 */
91static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(
92 struct iscsi_cmd *cmd,
93 struct iscsi_datain *datain)
94{
95 u32 next_burst_len, read_data_done, read_data_left;
96 struct iscsi_conn *conn = cmd->conn;
97 struct iscsi_datain_req *dr;
98
99 dr = iscsit_get_datain_req(cmd);
100 if (!dr)
101 return NULL;
102
103 if (dr->recovery && dr->generate_recovery_values) {
104 if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
105 cmd, dr) < 0)
106 return NULL;
107
108 dr->generate_recovery_values = 0;
109 }
110
111 next_burst_len = (!dr->recovery) ?
112 cmd->next_burst_len : dr->next_burst_len;
113 read_data_done = (!dr->recovery) ?
114 cmd->read_data_done : dr->read_data_done;
115
116 read_data_left = (cmd->data_length - read_data_done);
117 if (!read_data_left) {
118 pr_err("ITT: 0x%08x read_data_left is zero!\n",
119 cmd->init_task_tag);
120 return NULL;
121 }
122
123 if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) &&
124 (read_data_left <= (conn->sess->sess_ops->MaxBurstLength -
125 next_burst_len))) {
126 datain->length = read_data_left;
127
128 datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
129 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
130 datain->flags |= ISCSI_FLAG_DATA_ACK;
131 } else {
132 if ((next_burst_len +
133 conn->conn_ops->MaxRecvDataSegmentLength) <
134 conn->sess->sess_ops->MaxBurstLength) {
135 datain->length =
136 conn->conn_ops->MaxRecvDataSegmentLength;
137 next_burst_len += datain->length;
138 } else {
139 datain->length = (conn->sess->sess_ops->MaxBurstLength -
140 next_burst_len);
141 next_burst_len = 0;
142
143 datain->flags |= ISCSI_FLAG_CMD_FINAL;
144 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
145 datain->flags |= ISCSI_FLAG_DATA_ACK;
146 }
147 }
148
149 datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
150 datain->offset = read_data_done;
151
152 if (!dr->recovery) {
153 cmd->next_burst_len = next_burst_len;
154 cmd->read_data_done += datain->length;
155 } else {
156 dr->next_burst_len = next_burst_len;
157 dr->read_data_done += datain->length;
158 }
159
160 if (!dr->recovery) {
161 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
162 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
163
164 return dr;
165 }
166
167 if (!dr->runlength) {
168 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
169 dr->dr_complete =
170 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
171 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
172 DATAIN_COMPLETE_CONNECTION_RECOVERY;
173 }
174 } else {
175 if ((dr->begrun + dr->runlength) == dr->data_sn) {
176 dr->dr_complete =
177 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
178 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
179 DATAIN_COMPLETE_CONNECTION_RECOVERY;
180 }
181 }
182
183 return dr;
184}
185
186/*
187 * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes.
188 */
189static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
190 struct iscsi_cmd *cmd,
191 struct iscsi_datain *datain)
192{
193 u32 offset, read_data_done, read_data_left, seq_send_order;
194 struct iscsi_conn *conn = cmd->conn;
195 struct iscsi_datain_req *dr;
196 struct iscsi_seq *seq;
197
198 dr = iscsit_get_datain_req(cmd);
199 if (!dr)
200 return NULL;
201
202 if (dr->recovery && dr->generate_recovery_values) {
203 if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
204 cmd, dr) < 0)
205 return NULL;
206
207 dr->generate_recovery_values = 0;
208 }
209
210 read_data_done = (!dr->recovery) ?
211 cmd->read_data_done : dr->read_data_done;
212 seq_send_order = (!dr->recovery) ?
213 cmd->seq_send_order : dr->seq_send_order;
214
215 read_data_left = (cmd->data_length - read_data_done);
216 if (!read_data_left) {
217 pr_err("ITT: 0x%08x read_data_left is zero!\n",
218 cmd->init_task_tag);
219 return NULL;
220 }
221
222 seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
223 if (!seq)
224 return NULL;
225
226 seq->sent = 1;
227
228 if (!dr->recovery && !seq->next_burst_len)
229 seq->first_datasn = cmd->data_sn;
230
231 offset = (seq->offset + seq->next_burst_len);
232
233 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
234 cmd->data_length) {
235 datain->length = (cmd->data_length - offset);
236 datain->offset = offset;
237
238 datain->flags |= ISCSI_FLAG_CMD_FINAL;
239 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
240 datain->flags |= ISCSI_FLAG_DATA_ACK;
241
242 seq->next_burst_len = 0;
243 seq_send_order++;
244 } else {
245 if ((seq->next_burst_len +
246 conn->conn_ops->MaxRecvDataSegmentLength) <
247 conn->sess->sess_ops->MaxBurstLength) {
248 datain->length =
249 conn->conn_ops->MaxRecvDataSegmentLength;
250 datain->offset = (seq->offset + seq->next_burst_len);
251
252 seq->next_burst_len += datain->length;
253 } else {
254 datain->length = (conn->sess->sess_ops->MaxBurstLength -
255 seq->next_burst_len);
256 datain->offset = (seq->offset + seq->next_burst_len);
257
258 datain->flags |= ISCSI_FLAG_CMD_FINAL;
259 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
260 datain->flags |= ISCSI_FLAG_DATA_ACK;
261
262 seq->next_burst_len = 0;
263 seq_send_order++;
264 }
265 }
266
267 if ((read_data_done + datain->length) == cmd->data_length)
268 datain->flags |= ISCSI_FLAG_DATA_STATUS;
269
270 datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
271 if (!dr->recovery) {
272 cmd->seq_send_order = seq_send_order;
273 cmd->read_data_done += datain->length;
274 } else {
275 dr->seq_send_order = seq_send_order;
276 dr->read_data_done += datain->length;
277 }
278
279 if (!dr->recovery) {
280 if (datain->flags & ISCSI_FLAG_CMD_FINAL)
281 seq->last_datasn = datain->data_sn;
282 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
283 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
284
285 return dr;
286 }
287
288 if (!dr->runlength) {
289 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
290 dr->dr_complete =
291 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
292 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
293 DATAIN_COMPLETE_CONNECTION_RECOVERY;
294 }
295 } else {
296 if ((dr->begrun + dr->runlength) == dr->data_sn) {
297 dr->dr_complete =
298 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
299 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
300 DATAIN_COMPLETE_CONNECTION_RECOVERY;
301 }
302 }
303
304 return dr;
305}
306
307/*
308 * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No.
309 */
310static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
311 struct iscsi_cmd *cmd,
312 struct iscsi_datain *datain)
313{
314 u32 next_burst_len, read_data_done, read_data_left;
315 struct iscsi_conn *conn = cmd->conn;
316 struct iscsi_datain_req *dr;
317 struct iscsi_pdu *pdu;
318
319 dr = iscsit_get_datain_req(cmd);
320 if (!dr)
321 return NULL;
322
323 if (dr->recovery && dr->generate_recovery_values) {
324 if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
325 cmd, dr) < 0)
326 return NULL;
327
328 dr->generate_recovery_values = 0;
329 }
330
331 next_burst_len = (!dr->recovery) ?
332 cmd->next_burst_len : dr->next_burst_len;
333 read_data_done = (!dr->recovery) ?
334 cmd->read_data_done : dr->read_data_done;
335
336 read_data_left = (cmd->data_length - read_data_done);
337 if (!read_data_left) {
338 pr_err("ITT: 0x%08x read_data_left is zero!\n",
339 cmd->init_task_tag);
340 return dr;
341 }
342
343 pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL);
344 if (!pdu)
345 return dr;
346
347 if ((read_data_done + pdu->length) == cmd->data_length) {
348 pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
349 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
350 pdu->flags |= ISCSI_FLAG_DATA_ACK;
351
352 next_burst_len = 0;
353 } else {
354 if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) <
355 conn->sess->sess_ops->MaxBurstLength)
356 next_burst_len += pdu->length;
357 else {
358 pdu->flags |= ISCSI_FLAG_CMD_FINAL;
359 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
360 pdu->flags |= ISCSI_FLAG_DATA_ACK;
361
362 next_burst_len = 0;
363 }
364 }
365
366 pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
367 if (!dr->recovery) {
368 cmd->next_burst_len = next_burst_len;
369 cmd->read_data_done += pdu->length;
370 } else {
371 dr->next_burst_len = next_burst_len;
372 dr->read_data_done += pdu->length;
373 }
374
375 datain->flags = pdu->flags;
376 datain->length = pdu->length;
377 datain->offset = pdu->offset;
378 datain->data_sn = pdu->data_sn;
379
380 if (!dr->recovery) {
381 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
382 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
383
384 return dr;
385 }
386
387 if (!dr->runlength) {
388 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
389 dr->dr_complete =
390 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
391 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
392 DATAIN_COMPLETE_CONNECTION_RECOVERY;
393 }
394 } else {
395 if ((dr->begrun + dr->runlength) == dr->data_sn) {
396 dr->dr_complete =
397 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
398 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
399 DATAIN_COMPLETE_CONNECTION_RECOVERY;
400 }
401 }
402
403 return dr;
404}
405
406/*
407 * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No.
408 */
409static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
410 struct iscsi_cmd *cmd,
411 struct iscsi_datain *datain)
412{
413 u32 read_data_done, read_data_left, seq_send_order;
414 struct iscsi_conn *conn = cmd->conn;
415 struct iscsi_datain_req *dr;
416 struct iscsi_pdu *pdu;
417 struct iscsi_seq *seq = NULL;
418
419 dr = iscsit_get_datain_req(cmd);
420 if (!dr)
421 return NULL;
422
423 if (dr->recovery && dr->generate_recovery_values) {
424 if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
425 cmd, dr) < 0)
426 return NULL;
427
428 dr->generate_recovery_values = 0;
429 }
430
431 read_data_done = (!dr->recovery) ?
432 cmd->read_data_done : dr->read_data_done;
433 seq_send_order = (!dr->recovery) ?
434 cmd->seq_send_order : dr->seq_send_order;
435
436 read_data_left = (cmd->data_length - read_data_done);
437 if (!read_data_left) {
438 pr_err("ITT: 0x%08x read_data_left is zero!\n",
439 cmd->init_task_tag);
440 return NULL;
441 }
442
443 seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
444 if (!seq)
445 return NULL;
446
447 seq->sent = 1;
448
449 if (!dr->recovery && !seq->next_burst_len)
450 seq->first_datasn = cmd->data_sn;
451
452 pdu = iscsit_get_pdu_holder_for_seq(cmd, seq);
453 if (!pdu)
454 return NULL;
455
456 if (seq->pdu_send_order == seq->pdu_count) {
457 pdu->flags |= ISCSI_FLAG_CMD_FINAL;
458 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
459 pdu->flags |= ISCSI_FLAG_DATA_ACK;
460
461 seq->next_burst_len = 0;
462 seq_send_order++;
463 } else
464 seq->next_burst_len += pdu->length;
465
466 if ((read_data_done + pdu->length) == cmd->data_length)
467 pdu->flags |= ISCSI_FLAG_DATA_STATUS;
468
469 pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
470 if (!dr->recovery) {
471 cmd->seq_send_order = seq_send_order;
472 cmd->read_data_done += pdu->length;
473 } else {
474 dr->seq_send_order = seq_send_order;
475 dr->read_data_done += pdu->length;
476 }
477
478 datain->flags = pdu->flags;
479 datain->length = pdu->length;
480 datain->offset = pdu->offset;
481 datain->data_sn = pdu->data_sn;
482
483 if (!dr->recovery) {
484 if (datain->flags & ISCSI_FLAG_CMD_FINAL)
485 seq->last_datasn = datain->data_sn;
486 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
487 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
488
489 return dr;
490 }
491
492 if (!dr->runlength) {
493 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
494 dr->dr_complete =
495 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
496 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
497 DATAIN_COMPLETE_CONNECTION_RECOVERY;
498 }
499 } else {
500 if ((dr->begrun + dr->runlength) == dr->data_sn) {
501 dr->dr_complete =
502 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
503 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
504 DATAIN_COMPLETE_CONNECTION_RECOVERY;
505 }
506 }
507
508 return dr;
509}
510
511struct iscsi_datain_req *iscsit_get_datain_values(
512 struct iscsi_cmd *cmd,
513 struct iscsi_datain *datain)
514{
515 struct iscsi_conn *conn = cmd->conn;
516
517 if (conn->sess->sess_ops->DataSequenceInOrder &&
518 conn->sess->sess_ops->DataPDUInOrder)
519 return iscsit_set_datain_values_yes_and_yes(cmd, datain);
520 else if (!conn->sess->sess_ops->DataSequenceInOrder &&
521 conn->sess->sess_ops->DataPDUInOrder)
522 return iscsit_set_datain_values_no_and_yes(cmd, datain);
523 else if (conn->sess->sess_ops->DataSequenceInOrder &&
524 !conn->sess->sess_ops->DataPDUInOrder)
525 return iscsit_set_datain_values_yes_and_no(cmd, datain);
526 else if (!conn->sess->sess_ops->DataSequenceInOrder &&
527 !conn->sess->sess_ops->DataPDUInOrder)
528 return iscsit_set_datain_values_no_and_no(cmd, datain);
529
530 return NULL;
531}
1/*******************************************************************************
2 * This file contains the iSCSI Target DataIN value generation functions.
3 *
4 * (c) Copyright 2007-2013 Datera, Inc.
5 *
6 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 ******************************************************************************/
18
19#include <scsi/iscsi_proto.h>
20
21#include "iscsi_target_core.h"
22#include "iscsi_target_seq_pdu_list.h"
23#include "iscsi_target_erl1.h"
24#include "iscsi_target_util.h"
25#include "iscsi_target.h"
26#include "iscsi_target_datain_values.h"
27
28struct iscsi_datain_req *iscsit_allocate_datain_req(void)
29{
30 struct iscsi_datain_req *dr;
31
32 dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC);
33 if (!dr) {
34 pr_err("Unable to allocate memory for"
35 " struct iscsi_datain_req\n");
36 return NULL;
37 }
38 INIT_LIST_HEAD(&dr->cmd_datain_node);
39
40 return dr;
41}
42
43void iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
44{
45 spin_lock(&cmd->datain_lock);
46 list_add_tail(&dr->cmd_datain_node, &cmd->datain_list);
47 spin_unlock(&cmd->datain_lock);
48}
49
50void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
51{
52 spin_lock(&cmd->datain_lock);
53 list_del(&dr->cmd_datain_node);
54 spin_unlock(&cmd->datain_lock);
55
56 kmem_cache_free(lio_dr_cache, dr);
57}
58
59void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd)
60{
61 struct iscsi_datain_req *dr, *dr_tmp;
62
63 spin_lock(&cmd->datain_lock);
64 list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) {
65 list_del(&dr->cmd_datain_node);
66 kmem_cache_free(lio_dr_cache, dr);
67 }
68 spin_unlock(&cmd->datain_lock);
69}
70
71struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd)
72{
73 if (list_empty(&cmd->datain_list)) {
74 pr_err("cmd->datain_list is empty for ITT:"
75 " 0x%08x\n", cmd->init_task_tag);
76 return NULL;
77 }
78
79 return list_first_entry(&cmd->datain_list, struct iscsi_datain_req,
80 cmd_datain_node);
81}
82
83/*
84 * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.
85 */
86static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(
87 struct iscsi_cmd *cmd,
88 struct iscsi_datain *datain)
89{
90 u32 next_burst_len, read_data_done, read_data_left;
91 struct iscsi_conn *conn = cmd->conn;
92 struct iscsi_datain_req *dr;
93
94 dr = iscsit_get_datain_req(cmd);
95 if (!dr)
96 return NULL;
97
98 if (dr->recovery && dr->generate_recovery_values) {
99 if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
100 cmd, dr) < 0)
101 return NULL;
102
103 dr->generate_recovery_values = 0;
104 }
105
106 next_burst_len = (!dr->recovery) ?
107 cmd->next_burst_len : dr->next_burst_len;
108 read_data_done = (!dr->recovery) ?
109 cmd->read_data_done : dr->read_data_done;
110
111 read_data_left = (cmd->se_cmd.data_length - read_data_done);
112 if (!read_data_left) {
113 pr_err("ITT: 0x%08x read_data_left is zero!\n",
114 cmd->init_task_tag);
115 return NULL;
116 }
117
118 if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) &&
119 (read_data_left <= (conn->sess->sess_ops->MaxBurstLength -
120 next_burst_len))) {
121 datain->length = read_data_left;
122
123 datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
124 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
125 datain->flags |= ISCSI_FLAG_DATA_ACK;
126 } else {
127 if ((next_burst_len +
128 conn->conn_ops->MaxRecvDataSegmentLength) <
129 conn->sess->sess_ops->MaxBurstLength) {
130 datain->length =
131 conn->conn_ops->MaxRecvDataSegmentLength;
132 next_burst_len += datain->length;
133 } else {
134 datain->length = (conn->sess->sess_ops->MaxBurstLength -
135 next_burst_len);
136 next_burst_len = 0;
137
138 datain->flags |= ISCSI_FLAG_CMD_FINAL;
139 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
140 datain->flags |= ISCSI_FLAG_DATA_ACK;
141 }
142 }
143
144 datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
145 datain->offset = read_data_done;
146
147 if (!dr->recovery) {
148 cmd->next_burst_len = next_burst_len;
149 cmd->read_data_done += datain->length;
150 } else {
151 dr->next_burst_len = next_burst_len;
152 dr->read_data_done += datain->length;
153 }
154
155 if (!dr->recovery) {
156 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
157 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
158
159 return dr;
160 }
161
162 if (!dr->runlength) {
163 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
164 dr->dr_complete =
165 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
166 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
167 DATAIN_COMPLETE_CONNECTION_RECOVERY;
168 }
169 } else {
170 if ((dr->begrun + dr->runlength) == dr->data_sn) {
171 dr->dr_complete =
172 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
173 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
174 DATAIN_COMPLETE_CONNECTION_RECOVERY;
175 }
176 }
177
178 return dr;
179}
180
181/*
182 * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes.
183 */
184static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
185 struct iscsi_cmd *cmd,
186 struct iscsi_datain *datain)
187{
188 u32 offset, read_data_done, read_data_left, seq_send_order;
189 struct iscsi_conn *conn = cmd->conn;
190 struct iscsi_datain_req *dr;
191 struct iscsi_seq *seq;
192
193 dr = iscsit_get_datain_req(cmd);
194 if (!dr)
195 return NULL;
196
197 if (dr->recovery && dr->generate_recovery_values) {
198 if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
199 cmd, dr) < 0)
200 return NULL;
201
202 dr->generate_recovery_values = 0;
203 }
204
205 read_data_done = (!dr->recovery) ?
206 cmd->read_data_done : dr->read_data_done;
207 seq_send_order = (!dr->recovery) ?
208 cmd->seq_send_order : dr->seq_send_order;
209
210 read_data_left = (cmd->se_cmd.data_length - read_data_done);
211 if (!read_data_left) {
212 pr_err("ITT: 0x%08x read_data_left is zero!\n",
213 cmd->init_task_tag);
214 return NULL;
215 }
216
217 seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
218 if (!seq)
219 return NULL;
220
221 seq->sent = 1;
222
223 if (!dr->recovery && !seq->next_burst_len)
224 seq->first_datasn = cmd->data_sn;
225
226 offset = (seq->offset + seq->next_burst_len);
227
228 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
229 cmd->se_cmd.data_length) {
230 datain->length = (cmd->se_cmd.data_length - offset);
231 datain->offset = offset;
232
233 datain->flags |= ISCSI_FLAG_CMD_FINAL;
234 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
235 datain->flags |= ISCSI_FLAG_DATA_ACK;
236
237 seq->next_burst_len = 0;
238 seq_send_order++;
239 } else {
240 if ((seq->next_burst_len +
241 conn->conn_ops->MaxRecvDataSegmentLength) <
242 conn->sess->sess_ops->MaxBurstLength) {
243 datain->length =
244 conn->conn_ops->MaxRecvDataSegmentLength;
245 datain->offset = (seq->offset + seq->next_burst_len);
246
247 seq->next_burst_len += datain->length;
248 } else {
249 datain->length = (conn->sess->sess_ops->MaxBurstLength -
250 seq->next_burst_len);
251 datain->offset = (seq->offset + seq->next_burst_len);
252
253 datain->flags |= ISCSI_FLAG_CMD_FINAL;
254 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
255 datain->flags |= ISCSI_FLAG_DATA_ACK;
256
257 seq->next_burst_len = 0;
258 seq_send_order++;
259 }
260 }
261
262 if ((read_data_done + datain->length) == cmd->se_cmd.data_length)
263 datain->flags |= ISCSI_FLAG_DATA_STATUS;
264
265 datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
266 if (!dr->recovery) {
267 cmd->seq_send_order = seq_send_order;
268 cmd->read_data_done += datain->length;
269 } else {
270 dr->seq_send_order = seq_send_order;
271 dr->read_data_done += datain->length;
272 }
273
274 if (!dr->recovery) {
275 if (datain->flags & ISCSI_FLAG_CMD_FINAL)
276 seq->last_datasn = datain->data_sn;
277 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
278 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
279
280 return dr;
281 }
282
283 if (!dr->runlength) {
284 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
285 dr->dr_complete =
286 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
287 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
288 DATAIN_COMPLETE_CONNECTION_RECOVERY;
289 }
290 } else {
291 if ((dr->begrun + dr->runlength) == dr->data_sn) {
292 dr->dr_complete =
293 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
294 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
295 DATAIN_COMPLETE_CONNECTION_RECOVERY;
296 }
297 }
298
299 return dr;
300}
301
302/*
303 * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No.
304 */
305static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
306 struct iscsi_cmd *cmd,
307 struct iscsi_datain *datain)
308{
309 u32 next_burst_len, read_data_done, read_data_left;
310 struct iscsi_conn *conn = cmd->conn;
311 struct iscsi_datain_req *dr;
312 struct iscsi_pdu *pdu;
313
314 dr = iscsit_get_datain_req(cmd);
315 if (!dr)
316 return NULL;
317
318 if (dr->recovery && dr->generate_recovery_values) {
319 if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
320 cmd, dr) < 0)
321 return NULL;
322
323 dr->generate_recovery_values = 0;
324 }
325
326 next_burst_len = (!dr->recovery) ?
327 cmd->next_burst_len : dr->next_burst_len;
328 read_data_done = (!dr->recovery) ?
329 cmd->read_data_done : dr->read_data_done;
330
331 read_data_left = (cmd->se_cmd.data_length - read_data_done);
332 if (!read_data_left) {
333 pr_err("ITT: 0x%08x read_data_left is zero!\n",
334 cmd->init_task_tag);
335 return dr;
336 }
337
338 pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL);
339 if (!pdu)
340 return dr;
341
342 if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {
343 pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
344 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
345 pdu->flags |= ISCSI_FLAG_DATA_ACK;
346
347 next_burst_len = 0;
348 } else {
349 if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) <
350 conn->sess->sess_ops->MaxBurstLength)
351 next_burst_len += pdu->length;
352 else {
353 pdu->flags |= ISCSI_FLAG_CMD_FINAL;
354 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
355 pdu->flags |= ISCSI_FLAG_DATA_ACK;
356
357 next_burst_len = 0;
358 }
359 }
360
361 pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
362 if (!dr->recovery) {
363 cmd->next_burst_len = next_burst_len;
364 cmd->read_data_done += pdu->length;
365 } else {
366 dr->next_burst_len = next_burst_len;
367 dr->read_data_done += pdu->length;
368 }
369
370 datain->flags = pdu->flags;
371 datain->length = pdu->length;
372 datain->offset = pdu->offset;
373 datain->data_sn = pdu->data_sn;
374
375 if (!dr->recovery) {
376 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
377 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
378
379 return dr;
380 }
381
382 if (!dr->runlength) {
383 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
384 dr->dr_complete =
385 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
386 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
387 DATAIN_COMPLETE_CONNECTION_RECOVERY;
388 }
389 } else {
390 if ((dr->begrun + dr->runlength) == dr->data_sn) {
391 dr->dr_complete =
392 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
393 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
394 DATAIN_COMPLETE_CONNECTION_RECOVERY;
395 }
396 }
397
398 return dr;
399}
400
401/*
402 * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No.
403 */
404static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
405 struct iscsi_cmd *cmd,
406 struct iscsi_datain *datain)
407{
408 u32 read_data_done, read_data_left, seq_send_order;
409 struct iscsi_conn *conn = cmd->conn;
410 struct iscsi_datain_req *dr;
411 struct iscsi_pdu *pdu;
412 struct iscsi_seq *seq = NULL;
413
414 dr = iscsit_get_datain_req(cmd);
415 if (!dr)
416 return NULL;
417
418 if (dr->recovery && dr->generate_recovery_values) {
419 if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
420 cmd, dr) < 0)
421 return NULL;
422
423 dr->generate_recovery_values = 0;
424 }
425
426 read_data_done = (!dr->recovery) ?
427 cmd->read_data_done : dr->read_data_done;
428 seq_send_order = (!dr->recovery) ?
429 cmd->seq_send_order : dr->seq_send_order;
430
431 read_data_left = (cmd->se_cmd.data_length - read_data_done);
432 if (!read_data_left) {
433 pr_err("ITT: 0x%08x read_data_left is zero!\n",
434 cmd->init_task_tag);
435 return NULL;
436 }
437
438 seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
439 if (!seq)
440 return NULL;
441
442 seq->sent = 1;
443
444 if (!dr->recovery && !seq->next_burst_len)
445 seq->first_datasn = cmd->data_sn;
446
447 pdu = iscsit_get_pdu_holder_for_seq(cmd, seq);
448 if (!pdu)
449 return NULL;
450
451 if (seq->pdu_send_order == seq->pdu_count) {
452 pdu->flags |= ISCSI_FLAG_CMD_FINAL;
453 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
454 pdu->flags |= ISCSI_FLAG_DATA_ACK;
455
456 seq->next_burst_len = 0;
457 seq_send_order++;
458 } else
459 seq->next_burst_len += pdu->length;
460
461 if ((read_data_done + pdu->length) == cmd->se_cmd.data_length)
462 pdu->flags |= ISCSI_FLAG_DATA_STATUS;
463
464 pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
465 if (!dr->recovery) {
466 cmd->seq_send_order = seq_send_order;
467 cmd->read_data_done += pdu->length;
468 } else {
469 dr->seq_send_order = seq_send_order;
470 dr->read_data_done += pdu->length;
471 }
472
473 datain->flags = pdu->flags;
474 datain->length = pdu->length;
475 datain->offset = pdu->offset;
476 datain->data_sn = pdu->data_sn;
477
478 if (!dr->recovery) {
479 if (datain->flags & ISCSI_FLAG_CMD_FINAL)
480 seq->last_datasn = datain->data_sn;
481 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
482 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
483
484 return dr;
485 }
486
487 if (!dr->runlength) {
488 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
489 dr->dr_complete =
490 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
491 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
492 DATAIN_COMPLETE_CONNECTION_RECOVERY;
493 }
494 } else {
495 if ((dr->begrun + dr->runlength) == dr->data_sn) {
496 dr->dr_complete =
497 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
498 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
499 DATAIN_COMPLETE_CONNECTION_RECOVERY;
500 }
501 }
502
503 return dr;
504}
505
506struct iscsi_datain_req *iscsit_get_datain_values(
507 struct iscsi_cmd *cmd,
508 struct iscsi_datain *datain)
509{
510 struct iscsi_conn *conn = cmd->conn;
511
512 if (conn->sess->sess_ops->DataSequenceInOrder &&
513 conn->sess->sess_ops->DataPDUInOrder)
514 return iscsit_set_datain_values_yes_and_yes(cmd, datain);
515 else if (!conn->sess->sess_ops->DataSequenceInOrder &&
516 conn->sess->sess_ops->DataPDUInOrder)
517 return iscsit_set_datain_values_no_and_yes(cmd, datain);
518 else if (conn->sess->sess_ops->DataSequenceInOrder &&
519 !conn->sess->sess_ops->DataPDUInOrder)
520 return iscsit_set_datain_values_yes_and_no(cmd, datain);
521 else if (!conn->sess->sess_ops->DataSequenceInOrder &&
522 !conn->sess->sess_ops->DataPDUInOrder)
523 return iscsit_set_datain_values_no_and_no(cmd, datain);
524
525 return NULL;
526}