]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/target/iscsi/iscsi_target_datain_values.c
iscsi-target: Bump default TCP listen backlog to 256
[mirror_ubuntu-zesty-kernel.git] / drivers / target / iscsi / iscsi_target_datain_values.c
CommitLineData
e48354ce
NB
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 }
8b1e1244 40 INIT_LIST_HEAD(&dr->cmd_datain_node);
e48354ce
NB
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);
8b1e1244 48 list_add_tail(&dr->cmd_datain_node, &cmd->datain_list);
e48354ce
NB
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);
8b1e1244 55 list_del(&dr->cmd_datain_node);
e48354ce
NB
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);
8b1e1244
AG
66 list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) {
67 list_del(&dr->cmd_datain_node);
e48354ce
NB
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{
e48354ce
NB
75 if (list_empty(&cmd->datain_list)) {
76 pr_err("cmd->datain_list is empty for ITT:"
77 " 0x%08x\n", cmd->init_task_tag);
78 return NULL;
79 }
e48354ce 80
8b1e1244
AG
81 return list_first_entry(&cmd->datain_list, struct iscsi_datain_req,
82 cmd_datain_node);
e48354ce
NB
83}
84
85/*
86 * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.
87 */
88static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(
89 struct iscsi_cmd *cmd,
90 struct iscsi_datain *datain)
91{
92 u32 next_burst_len, read_data_done, read_data_left;
93 struct iscsi_conn *conn = cmd->conn;
94 struct iscsi_datain_req *dr;
95
96 dr = iscsit_get_datain_req(cmd);
97 if (!dr)
98 return NULL;
99
100 if (dr->recovery && dr->generate_recovery_values) {
101 if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
102 cmd, dr) < 0)
103 return NULL;
104
105 dr->generate_recovery_values = 0;
106 }
107
108 next_burst_len = (!dr->recovery) ?
109 cmd->next_burst_len : dr->next_burst_len;
110 read_data_done = (!dr->recovery) ?
111 cmd->read_data_done : dr->read_data_done;
112
ebf1d95c 113 read_data_left = (cmd->se_cmd.data_length - read_data_done);
e48354ce
NB
114 if (!read_data_left) {
115 pr_err("ITT: 0x%08x read_data_left is zero!\n",
116 cmd->init_task_tag);
117 return NULL;
118 }
119
120 if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) &&
121 (read_data_left <= (conn->sess->sess_ops->MaxBurstLength -
122 next_burst_len))) {
123 datain->length = read_data_left;
124
125 datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
126 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
127 datain->flags |= ISCSI_FLAG_DATA_ACK;
128 } else {
129 if ((next_burst_len +
130 conn->conn_ops->MaxRecvDataSegmentLength) <
131 conn->sess->sess_ops->MaxBurstLength) {
132 datain->length =
133 conn->conn_ops->MaxRecvDataSegmentLength;
134 next_burst_len += datain->length;
135 } else {
136 datain->length = (conn->sess->sess_ops->MaxBurstLength -
137 next_burst_len);
138 next_burst_len = 0;
139
140 datain->flags |= ISCSI_FLAG_CMD_FINAL;
141 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
142 datain->flags |= ISCSI_FLAG_DATA_ACK;
143 }
144 }
145
146 datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
147 datain->offset = read_data_done;
148
149 if (!dr->recovery) {
150 cmd->next_burst_len = next_burst_len;
151 cmd->read_data_done += datain->length;
152 } else {
153 dr->next_burst_len = next_burst_len;
154 dr->read_data_done += datain->length;
155 }
156
157 if (!dr->recovery) {
158 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
159 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
160
161 return dr;
162 }
163
164 if (!dr->runlength) {
165 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
166 dr->dr_complete =
167 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
168 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
169 DATAIN_COMPLETE_CONNECTION_RECOVERY;
170 }
171 } else {
172 if ((dr->begrun + dr->runlength) == dr->data_sn) {
173 dr->dr_complete =
174 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
175 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
176 DATAIN_COMPLETE_CONNECTION_RECOVERY;
177 }
178 }
179
180 return dr;
181}
182
183/*
184 * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes.
185 */
186static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
187 struct iscsi_cmd *cmd,
188 struct iscsi_datain *datain)
189{
190 u32 offset, read_data_done, read_data_left, seq_send_order;
191 struct iscsi_conn *conn = cmd->conn;
192 struct iscsi_datain_req *dr;
193 struct iscsi_seq *seq;
194
195 dr = iscsit_get_datain_req(cmd);
196 if (!dr)
197 return NULL;
198
199 if (dr->recovery && dr->generate_recovery_values) {
200 if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
201 cmd, dr) < 0)
202 return NULL;
203
204 dr->generate_recovery_values = 0;
205 }
206
207 read_data_done = (!dr->recovery) ?
208 cmd->read_data_done : dr->read_data_done;
209 seq_send_order = (!dr->recovery) ?
210 cmd->seq_send_order : dr->seq_send_order;
211
ebf1d95c 212 read_data_left = (cmd->se_cmd.data_length - read_data_done);
e48354ce
NB
213 if (!read_data_left) {
214 pr_err("ITT: 0x%08x read_data_left is zero!\n",
215 cmd->init_task_tag);
216 return NULL;
217 }
218
219 seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
220 if (!seq)
221 return NULL;
222
223 seq->sent = 1;
224
225 if (!dr->recovery && !seq->next_burst_len)
226 seq->first_datasn = cmd->data_sn;
227
228 offset = (seq->offset + seq->next_burst_len);
229
230 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
ebf1d95c
AG
231 cmd->se_cmd.data_length) {
232 datain->length = (cmd->se_cmd.data_length - offset);
e48354ce
NB
233 datain->offset = offset;
234
235 datain->flags |= ISCSI_FLAG_CMD_FINAL;
236 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
237 datain->flags |= ISCSI_FLAG_DATA_ACK;
238
239 seq->next_burst_len = 0;
240 seq_send_order++;
241 } else {
242 if ((seq->next_burst_len +
243 conn->conn_ops->MaxRecvDataSegmentLength) <
244 conn->sess->sess_ops->MaxBurstLength) {
245 datain->length =
246 conn->conn_ops->MaxRecvDataSegmentLength;
247 datain->offset = (seq->offset + seq->next_burst_len);
248
249 seq->next_burst_len += datain->length;
250 } else {
251 datain->length = (conn->sess->sess_ops->MaxBurstLength -
252 seq->next_burst_len);
253 datain->offset = (seq->offset + seq->next_burst_len);
254
255 datain->flags |= ISCSI_FLAG_CMD_FINAL;
256 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
257 datain->flags |= ISCSI_FLAG_DATA_ACK;
258
259 seq->next_burst_len = 0;
260 seq_send_order++;
261 }
262 }
263
ebf1d95c 264 if ((read_data_done + datain->length) == cmd->se_cmd.data_length)
e48354ce
NB
265 datain->flags |= ISCSI_FLAG_DATA_STATUS;
266
267 datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
268 if (!dr->recovery) {
269 cmd->seq_send_order = seq_send_order;
270 cmd->read_data_done += datain->length;
271 } else {
272 dr->seq_send_order = seq_send_order;
273 dr->read_data_done += datain->length;
274 }
275
276 if (!dr->recovery) {
277 if (datain->flags & ISCSI_FLAG_CMD_FINAL)
278 seq->last_datasn = datain->data_sn;
279 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
280 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
281
282 return dr;
283 }
284
285 if (!dr->runlength) {
286 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
287 dr->dr_complete =
288 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
289 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
290 DATAIN_COMPLETE_CONNECTION_RECOVERY;
291 }
292 } else {
293 if ((dr->begrun + dr->runlength) == dr->data_sn) {
294 dr->dr_complete =
295 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
296 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
297 DATAIN_COMPLETE_CONNECTION_RECOVERY;
298 }
299 }
300
301 return dr;
302}
303
304/*
305 * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No.
306 */
307static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
308 struct iscsi_cmd *cmd,
309 struct iscsi_datain *datain)
310{
311 u32 next_burst_len, read_data_done, read_data_left;
312 struct iscsi_conn *conn = cmd->conn;
313 struct iscsi_datain_req *dr;
314 struct iscsi_pdu *pdu;
315
316 dr = iscsit_get_datain_req(cmd);
317 if (!dr)
318 return NULL;
319
320 if (dr->recovery && dr->generate_recovery_values) {
321 if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
322 cmd, dr) < 0)
323 return NULL;
324
325 dr->generate_recovery_values = 0;
326 }
327
328 next_burst_len = (!dr->recovery) ?
329 cmd->next_burst_len : dr->next_burst_len;
330 read_data_done = (!dr->recovery) ?
331 cmd->read_data_done : dr->read_data_done;
332
ebf1d95c 333 read_data_left = (cmd->se_cmd.data_length - read_data_done);
e48354ce
NB
334 if (!read_data_left) {
335 pr_err("ITT: 0x%08x read_data_left is zero!\n",
336 cmd->init_task_tag);
337 return dr;
338 }
339
340 pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL);
341 if (!pdu)
342 return dr;
343
ebf1d95c 344 if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {
e48354ce
NB
345 pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
346 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
347 pdu->flags |= ISCSI_FLAG_DATA_ACK;
348
349 next_burst_len = 0;
350 } else {
351 if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) <
352 conn->sess->sess_ops->MaxBurstLength)
353 next_burst_len += pdu->length;
354 else {
355 pdu->flags |= ISCSI_FLAG_CMD_FINAL;
356 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
357 pdu->flags |= ISCSI_FLAG_DATA_ACK;
358
359 next_burst_len = 0;
360 }
361 }
362
363 pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
364 if (!dr->recovery) {
365 cmd->next_burst_len = next_burst_len;
366 cmd->read_data_done += pdu->length;
367 } else {
368 dr->next_burst_len = next_burst_len;
369 dr->read_data_done += pdu->length;
370 }
371
372 datain->flags = pdu->flags;
373 datain->length = pdu->length;
374 datain->offset = pdu->offset;
375 datain->data_sn = pdu->data_sn;
376
377 if (!dr->recovery) {
378 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
379 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
380
381 return dr;
382 }
383
384 if (!dr->runlength) {
385 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
386 dr->dr_complete =
387 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
388 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
389 DATAIN_COMPLETE_CONNECTION_RECOVERY;
390 }
391 } else {
392 if ((dr->begrun + dr->runlength) == dr->data_sn) {
393 dr->dr_complete =
394 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
395 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
396 DATAIN_COMPLETE_CONNECTION_RECOVERY;
397 }
398 }
399
400 return dr;
401}
402
403/*
404 * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No.
405 */
406static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
407 struct iscsi_cmd *cmd,
408 struct iscsi_datain *datain)
409{
410 u32 read_data_done, read_data_left, seq_send_order;
411 struct iscsi_conn *conn = cmd->conn;
412 struct iscsi_datain_req *dr;
413 struct iscsi_pdu *pdu;
414 struct iscsi_seq *seq = NULL;
415
416 dr = iscsit_get_datain_req(cmd);
417 if (!dr)
418 return NULL;
419
420 if (dr->recovery && dr->generate_recovery_values) {
421 if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
422 cmd, dr) < 0)
423 return NULL;
424
425 dr->generate_recovery_values = 0;
426 }
427
428 read_data_done = (!dr->recovery) ?
429 cmd->read_data_done : dr->read_data_done;
430 seq_send_order = (!dr->recovery) ?
431 cmd->seq_send_order : dr->seq_send_order;
432
ebf1d95c 433 read_data_left = (cmd->se_cmd.data_length - read_data_done);
e48354ce
NB
434 if (!read_data_left) {
435 pr_err("ITT: 0x%08x read_data_left is zero!\n",
436 cmd->init_task_tag);
437 return NULL;
438 }
439
440 seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
441 if (!seq)
442 return NULL;
443
444 seq->sent = 1;
445
446 if (!dr->recovery && !seq->next_burst_len)
447 seq->first_datasn = cmd->data_sn;
448
449 pdu = iscsit_get_pdu_holder_for_seq(cmd, seq);
450 if (!pdu)
451 return NULL;
452
453 if (seq->pdu_send_order == seq->pdu_count) {
454 pdu->flags |= ISCSI_FLAG_CMD_FINAL;
455 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
456 pdu->flags |= ISCSI_FLAG_DATA_ACK;
457
458 seq->next_burst_len = 0;
459 seq_send_order++;
460 } else
461 seq->next_burst_len += pdu->length;
462
ebf1d95c 463 if ((read_data_done + pdu->length) == cmd->se_cmd.data_length)
e48354ce
NB
464 pdu->flags |= ISCSI_FLAG_DATA_STATUS;
465
466 pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
467 if (!dr->recovery) {
468 cmd->seq_send_order = seq_send_order;
469 cmd->read_data_done += pdu->length;
470 } else {
471 dr->seq_send_order = seq_send_order;
472 dr->read_data_done += pdu->length;
473 }
474
475 datain->flags = pdu->flags;
476 datain->length = pdu->length;
477 datain->offset = pdu->offset;
478 datain->data_sn = pdu->data_sn;
479
480 if (!dr->recovery) {
481 if (datain->flags & ISCSI_FLAG_CMD_FINAL)
482 seq->last_datasn = datain->data_sn;
483 if (datain->flags & ISCSI_FLAG_DATA_STATUS)
484 dr->dr_complete = DATAIN_COMPLETE_NORMAL;
485
486 return dr;
487 }
488
489 if (!dr->runlength) {
490 if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
491 dr->dr_complete =
492 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
493 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
494 DATAIN_COMPLETE_CONNECTION_RECOVERY;
495 }
496 } else {
497 if ((dr->begrun + dr->runlength) == dr->data_sn) {
498 dr->dr_complete =
499 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
500 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
501 DATAIN_COMPLETE_CONNECTION_RECOVERY;
502 }
503 }
504
505 return dr;
506}
507
508struct iscsi_datain_req *iscsit_get_datain_values(
509 struct iscsi_cmd *cmd,
510 struct iscsi_datain *datain)
511{
512 struct iscsi_conn *conn = cmd->conn;
513
514 if (conn->sess->sess_ops->DataSequenceInOrder &&
515 conn->sess->sess_ops->DataPDUInOrder)
516 return iscsit_set_datain_values_yes_and_yes(cmd, datain);
517 else if (!conn->sess->sess_ops->DataSequenceInOrder &&
518 conn->sess->sess_ops->DataPDUInOrder)
519 return iscsit_set_datain_values_no_and_yes(cmd, datain);
520 else if (conn->sess->sess_ops->DataSequenceInOrder &&
521 !conn->sess->sess_ops->DataPDUInOrder)
522 return iscsit_set_datain_values_yes_and_no(cmd, datain);
523 else if (!conn->sess->sess_ops->DataSequenceInOrder &&
524 !conn->sess->sess_ops->DataPDUInOrder)
525 return iscsit_set_datain_values_no_and_no(cmd, datain);
526
527 return NULL;
528}