GNU Linux-libre 4.19.263-gnu1
[releases.git] / drivers / target / iscsi / iscsi_target_datain_values.c
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 <linux/slab.h>
20 #include <scsi/iscsi_proto.h>
21 #include <target/iscsi/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
28 struct 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
43 void 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
50 void 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
59 void 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
71 struct 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  */
86 static 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  */
184 static 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  */
305 static 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  */
404 static 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
506 struct 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 }
527 EXPORT_SYMBOL(iscsit_get_datain_values);