]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/target/iscsi/iscsi_target_datain_values.c
jfs: fix error path in ialloc
[karo-tx-linux.git] / drivers / target / iscsi / iscsi_target_datain_values.c
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
30 struct 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->cmd_datain_node);
41
42         return dr;
43 }
44
45 void 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->cmd_datain_node, &cmd->datain_list);
49         spin_unlock(&cmd->datain_lock);
50 }
51
52 void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
53 {
54         spin_lock(&cmd->datain_lock);
55         list_del(&dr->cmd_datain_node);
56         spin_unlock(&cmd->datain_lock);
57
58         kmem_cache_free(lio_dr_cache, dr);
59 }
60
61 void 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, cmd_datain_node) {
67                 list_del(&dr->cmd_datain_node);
68                 kmem_cache_free(lio_dr_cache, dr);
69         }
70         spin_unlock(&cmd->datain_lock);
71 }
72
73 struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd)
74 {
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         }
80
81         return list_first_entry(&cmd->datain_list, struct iscsi_datain_req,
82                                 cmd_datain_node);
83 }
84
85 /*
86  *      For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.
87  */
88 static 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
113         read_data_left = (cmd->se_cmd.data_length - read_data_done);
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  */
186 static 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
212         read_data_left = (cmd->se_cmd.data_length - read_data_done);
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) >=
231              cmd->se_cmd.data_length) {
232                 datain->length = (cmd->se_cmd.data_length - offset);
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
264         if ((read_data_done + datain->length) == cmd->se_cmd.data_length)
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  */
307 static 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
333         read_data_left = (cmd->se_cmd.data_length - read_data_done);
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
344         if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {
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  */
406 static 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
433         read_data_left = (cmd->se_cmd.data_length - read_data_done);
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
463         if ((read_data_done + pdu->length) == cmd->se_cmd.data_length)
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
508 struct 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 }