Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
iscsi_target_datain_values.c
Go to the documentation of this file.
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 <[email protected]>
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"
25 #include "iscsi_target_erl1.h"
26 #include "iscsi_target_util.h"
27 #include "iscsi_target.h"
29 
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 
46 {
47  spin_lock(&cmd->datain_lock);
49  spin_unlock(&cmd->datain_lock);
50 }
51 
53 {
54  spin_lock(&cmd->datain_lock);
56  spin_unlock(&cmd->datain_lock);
57 
59 }
60 
62 {
63  struct iscsi_datain_req *dr, *dr_tmp;
64 
65  spin_lock(&cmd->datain_lock);
69  }
70  spin_unlock(&cmd->datain_lock);
71 }
72 
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,
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) {
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 
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 -
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) {
151  cmd->read_data_done += datain->length;
152  } else {
154  dr->read_data_done += datain->length;
155  }
156 
157  if (!dr->recovery) {
158  if (datain->flags & ISCSI_FLAG_DATA_STATUS)
160 
161  return dr;
162  }
163 
164  if (!dr->runlength) {
165  if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
166  dr->dr_complete =
170  }
171  } else {
172  if ((dr->begrun + dr->runlength) == dr->data_sn) {
173  dr->dr_complete =
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) {
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) {
270  cmd->read_data_done += datain->length;
271  } else {
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)
281 
282  return dr;
283  }
284 
285  if (!dr->runlength) {
286  if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
287  dr->dr_complete =
291  }
292  } else {
293  if ((dr->begrun + dr->runlength) == dr->data_sn) {
294  dr->dr_complete =
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) {
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 
341  if (!pdu)
342  return dr;
343 
344  if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {
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)
380 
381  return dr;
382  }
383 
384  if (!dr->runlength) {
385  if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
386  dr->dr_complete =
390  }
391  } else {
392  if ((dr->begrun + dr->runlength) == dr->data_sn) {
393  dr->dr_complete =
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) {
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)
465 
466  pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
467  if (!dr->recovery) {
469  cmd->read_data_done += pdu->length;
470  } else {
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)
485 
486  return dr;
487  }
488 
489  if (!dr->runlength) {
490  if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
491  dr->dr_complete =
495  }
496  } else {
497  if ((dr->begrun + dr->runlength) == dr->data_sn) {
498  dr->dr_complete =
502  }
503  }
504 
505  return dr;
506 }
507 
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 }