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