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