Linux Audio

Check our new training course

Loading...
v5.14.15
  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
 20struct 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
 35void 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
 42void 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
 51void 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
 63struct 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 */
 78static 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 */
176static 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 */
297static 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 */
396static 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
498struct 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}
519EXPORT_SYMBOL(iscsit_get_datain_values);
v3.15
 
  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 <scsi/iscsi_proto.h>
 20
 21#include "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
 28struct 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
 43void 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
 50void 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
 59void 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
 71struct 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 */
 86static 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 */
184static 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 */
305static 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 */
404static 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
506struct 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}