Linux Audio

Check our new training course

Linux kernel drivers training

Mar 31-Apr 9, 2025, special US time zones
Register
Loading...
v3.1
  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
 30struct 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
 45void 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
 52void 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
 61void 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
 73struct 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 */
 91static 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 */
189static 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 */
310static 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 */
409static 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
511struct 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}
v3.5.6
  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
 30struct 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
 45void 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
 52void 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
 61void 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
 73struct 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 */
 88static 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 */
186static 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 */
307static 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 */
406static 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
508struct 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}