1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*******************************************************************************
3*4882a593Smuzhiyun * This file contains the iSCSI Target DataIN value generation functions.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * (c) Copyright 2007-2013 Datera, Inc.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun ******************************************************************************/
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <scsi/iscsi_proto.h>
13*4882a593Smuzhiyun #include <target/iscsi/iscsi_target_core.h>
14*4882a593Smuzhiyun #include "iscsi_target_seq_pdu_list.h"
15*4882a593Smuzhiyun #include "iscsi_target_erl1.h"
16*4882a593Smuzhiyun #include "iscsi_target_util.h"
17*4882a593Smuzhiyun #include "iscsi_target.h"
18*4882a593Smuzhiyun #include "iscsi_target_datain_values.h"
19*4882a593Smuzhiyun
iscsit_allocate_datain_req(void)20*4882a593Smuzhiyun struct iscsi_datain_req *iscsit_allocate_datain_req(void)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun struct iscsi_datain_req *dr;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC);
25*4882a593Smuzhiyun if (!dr) {
26*4882a593Smuzhiyun pr_err("Unable to allocate memory for"
27*4882a593Smuzhiyun " struct iscsi_datain_req\n");
28*4882a593Smuzhiyun return NULL;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun INIT_LIST_HEAD(&dr->cmd_datain_node);
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun return dr;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
iscsit_attach_datain_req(struct iscsi_cmd * cmd,struct iscsi_datain_req * dr)35*4882a593Smuzhiyun void iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun spin_lock(&cmd->datain_lock);
38*4882a593Smuzhiyun list_add_tail(&dr->cmd_datain_node, &cmd->datain_list);
39*4882a593Smuzhiyun spin_unlock(&cmd->datain_lock);
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
iscsit_free_datain_req(struct iscsi_cmd * cmd,struct iscsi_datain_req * dr)42*4882a593Smuzhiyun void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun spin_lock(&cmd->datain_lock);
45*4882a593Smuzhiyun list_del(&dr->cmd_datain_node);
46*4882a593Smuzhiyun spin_unlock(&cmd->datain_lock);
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun kmem_cache_free(lio_dr_cache, dr);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
iscsit_free_all_datain_reqs(struct iscsi_cmd * cmd)51*4882a593Smuzhiyun void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun struct iscsi_datain_req *dr, *dr_tmp;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun spin_lock(&cmd->datain_lock);
56*4882a593Smuzhiyun list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) {
57*4882a593Smuzhiyun list_del(&dr->cmd_datain_node);
58*4882a593Smuzhiyun kmem_cache_free(lio_dr_cache, dr);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun spin_unlock(&cmd->datain_lock);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
iscsit_get_datain_req(struct iscsi_cmd * cmd)63*4882a593Smuzhiyun struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun if (list_empty(&cmd->datain_list)) {
66*4882a593Smuzhiyun pr_err("cmd->datain_list is empty for ITT:"
67*4882a593Smuzhiyun " 0x%08x\n", cmd->init_task_tag);
68*4882a593Smuzhiyun return NULL;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun return list_first_entry(&cmd->datain_list, struct iscsi_datain_req,
72*4882a593Smuzhiyun cmd_datain_node);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /*
76*4882a593Smuzhiyun * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.
77*4882a593Smuzhiyun */
iscsit_set_datain_values_yes_and_yes(struct iscsi_cmd * cmd,struct iscsi_datain * datain)78*4882a593Smuzhiyun static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(
79*4882a593Smuzhiyun struct iscsi_cmd *cmd,
80*4882a593Smuzhiyun struct iscsi_datain *datain)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun u32 next_burst_len, read_data_done, read_data_left;
83*4882a593Smuzhiyun struct iscsi_conn *conn = cmd->conn;
84*4882a593Smuzhiyun struct iscsi_datain_req *dr;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun dr = iscsit_get_datain_req(cmd);
87*4882a593Smuzhiyun if (!dr)
88*4882a593Smuzhiyun return NULL;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun if (dr->recovery && dr->generate_recovery_values) {
91*4882a593Smuzhiyun if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
92*4882a593Smuzhiyun cmd, dr) < 0)
93*4882a593Smuzhiyun return NULL;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun dr->generate_recovery_values = 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun next_burst_len = (!dr->recovery) ?
99*4882a593Smuzhiyun cmd->next_burst_len : dr->next_burst_len;
100*4882a593Smuzhiyun read_data_done = (!dr->recovery) ?
101*4882a593Smuzhiyun cmd->read_data_done : dr->read_data_done;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun read_data_left = (cmd->se_cmd.data_length - read_data_done);
104*4882a593Smuzhiyun if (!read_data_left) {
105*4882a593Smuzhiyun pr_err("ITT: 0x%08x read_data_left is zero!\n",
106*4882a593Smuzhiyun cmd->init_task_tag);
107*4882a593Smuzhiyun return NULL;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) &&
111*4882a593Smuzhiyun (read_data_left <= (conn->sess->sess_ops->MaxBurstLength -
112*4882a593Smuzhiyun next_burst_len))) {
113*4882a593Smuzhiyun datain->length = read_data_left;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
116*4882a593Smuzhiyun if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
117*4882a593Smuzhiyun datain->flags |= ISCSI_FLAG_DATA_ACK;
118*4882a593Smuzhiyun } else {
119*4882a593Smuzhiyun if ((next_burst_len +
120*4882a593Smuzhiyun conn->conn_ops->MaxRecvDataSegmentLength) <
121*4882a593Smuzhiyun conn->sess->sess_ops->MaxBurstLength) {
122*4882a593Smuzhiyun datain->length =
123*4882a593Smuzhiyun conn->conn_ops->MaxRecvDataSegmentLength;
124*4882a593Smuzhiyun next_burst_len += datain->length;
125*4882a593Smuzhiyun } else {
126*4882a593Smuzhiyun datain->length = (conn->sess->sess_ops->MaxBurstLength -
127*4882a593Smuzhiyun next_burst_len);
128*4882a593Smuzhiyun next_burst_len = 0;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun datain->flags |= ISCSI_FLAG_CMD_FINAL;
131*4882a593Smuzhiyun if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
132*4882a593Smuzhiyun datain->flags |= ISCSI_FLAG_DATA_ACK;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
137*4882a593Smuzhiyun datain->offset = read_data_done;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (!dr->recovery) {
140*4882a593Smuzhiyun cmd->next_burst_len = next_burst_len;
141*4882a593Smuzhiyun cmd->read_data_done += datain->length;
142*4882a593Smuzhiyun } else {
143*4882a593Smuzhiyun dr->next_burst_len = next_burst_len;
144*4882a593Smuzhiyun dr->read_data_done += datain->length;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun if (!dr->recovery) {
148*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_DATA_STATUS)
149*4882a593Smuzhiyun dr->dr_complete = DATAIN_COMPLETE_NORMAL;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun return dr;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun if (!dr->runlength) {
155*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
156*4882a593Smuzhiyun dr->dr_complete =
157*4882a593Smuzhiyun (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
158*4882a593Smuzhiyun DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
159*4882a593Smuzhiyun DATAIN_COMPLETE_CONNECTION_RECOVERY;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun } else {
162*4882a593Smuzhiyun if ((dr->begrun + dr->runlength) == dr->data_sn) {
163*4882a593Smuzhiyun dr->dr_complete =
164*4882a593Smuzhiyun (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
165*4882a593Smuzhiyun DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
166*4882a593Smuzhiyun DATAIN_COMPLETE_CONNECTION_RECOVERY;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun return dr;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /*
174*4882a593Smuzhiyun * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes.
175*4882a593Smuzhiyun */
iscsit_set_datain_values_no_and_yes(struct iscsi_cmd * cmd,struct iscsi_datain * datain)176*4882a593Smuzhiyun static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
177*4882a593Smuzhiyun struct iscsi_cmd *cmd,
178*4882a593Smuzhiyun struct iscsi_datain *datain)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun u32 offset, read_data_done, read_data_left, seq_send_order;
181*4882a593Smuzhiyun struct iscsi_conn *conn = cmd->conn;
182*4882a593Smuzhiyun struct iscsi_datain_req *dr;
183*4882a593Smuzhiyun struct iscsi_seq *seq;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun dr = iscsit_get_datain_req(cmd);
186*4882a593Smuzhiyun if (!dr)
187*4882a593Smuzhiyun return NULL;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun if (dr->recovery && dr->generate_recovery_values) {
190*4882a593Smuzhiyun if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
191*4882a593Smuzhiyun cmd, dr) < 0)
192*4882a593Smuzhiyun return NULL;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun dr->generate_recovery_values = 0;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun read_data_done = (!dr->recovery) ?
198*4882a593Smuzhiyun cmd->read_data_done : dr->read_data_done;
199*4882a593Smuzhiyun seq_send_order = (!dr->recovery) ?
200*4882a593Smuzhiyun cmd->seq_send_order : dr->seq_send_order;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun read_data_left = (cmd->se_cmd.data_length - read_data_done);
203*4882a593Smuzhiyun if (!read_data_left) {
204*4882a593Smuzhiyun pr_err("ITT: 0x%08x read_data_left is zero!\n",
205*4882a593Smuzhiyun cmd->init_task_tag);
206*4882a593Smuzhiyun return NULL;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
210*4882a593Smuzhiyun if (!seq)
211*4882a593Smuzhiyun return NULL;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun seq->sent = 1;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (!dr->recovery && !seq->next_burst_len)
216*4882a593Smuzhiyun seq->first_datasn = cmd->data_sn;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun offset = (seq->offset + seq->next_burst_len);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
221*4882a593Smuzhiyun cmd->se_cmd.data_length) {
222*4882a593Smuzhiyun datain->length = (cmd->se_cmd.data_length - offset);
223*4882a593Smuzhiyun datain->offset = offset;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun datain->flags |= ISCSI_FLAG_CMD_FINAL;
226*4882a593Smuzhiyun if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
227*4882a593Smuzhiyun datain->flags |= ISCSI_FLAG_DATA_ACK;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun seq->next_burst_len = 0;
230*4882a593Smuzhiyun seq_send_order++;
231*4882a593Smuzhiyun } else {
232*4882a593Smuzhiyun if ((seq->next_burst_len +
233*4882a593Smuzhiyun conn->conn_ops->MaxRecvDataSegmentLength) <
234*4882a593Smuzhiyun conn->sess->sess_ops->MaxBurstLength) {
235*4882a593Smuzhiyun datain->length =
236*4882a593Smuzhiyun conn->conn_ops->MaxRecvDataSegmentLength;
237*4882a593Smuzhiyun datain->offset = (seq->offset + seq->next_burst_len);
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun seq->next_burst_len += datain->length;
240*4882a593Smuzhiyun } else {
241*4882a593Smuzhiyun datain->length = (conn->sess->sess_ops->MaxBurstLength -
242*4882a593Smuzhiyun seq->next_burst_len);
243*4882a593Smuzhiyun datain->offset = (seq->offset + seq->next_burst_len);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun datain->flags |= ISCSI_FLAG_CMD_FINAL;
246*4882a593Smuzhiyun if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
247*4882a593Smuzhiyun datain->flags |= ISCSI_FLAG_DATA_ACK;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun seq->next_burst_len = 0;
250*4882a593Smuzhiyun seq_send_order++;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun if ((read_data_done + datain->length) == cmd->se_cmd.data_length)
255*4882a593Smuzhiyun datain->flags |= ISCSI_FLAG_DATA_STATUS;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
258*4882a593Smuzhiyun if (!dr->recovery) {
259*4882a593Smuzhiyun cmd->seq_send_order = seq_send_order;
260*4882a593Smuzhiyun cmd->read_data_done += datain->length;
261*4882a593Smuzhiyun } else {
262*4882a593Smuzhiyun dr->seq_send_order = seq_send_order;
263*4882a593Smuzhiyun dr->read_data_done += datain->length;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if (!dr->recovery) {
267*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_CMD_FINAL)
268*4882a593Smuzhiyun seq->last_datasn = datain->data_sn;
269*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_DATA_STATUS)
270*4882a593Smuzhiyun dr->dr_complete = DATAIN_COMPLETE_NORMAL;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun return dr;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun if (!dr->runlength) {
276*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
277*4882a593Smuzhiyun dr->dr_complete =
278*4882a593Smuzhiyun (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
279*4882a593Smuzhiyun DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
280*4882a593Smuzhiyun DATAIN_COMPLETE_CONNECTION_RECOVERY;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun } else {
283*4882a593Smuzhiyun if ((dr->begrun + dr->runlength) == dr->data_sn) {
284*4882a593Smuzhiyun dr->dr_complete =
285*4882a593Smuzhiyun (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
286*4882a593Smuzhiyun DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
287*4882a593Smuzhiyun DATAIN_COMPLETE_CONNECTION_RECOVERY;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun return dr;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun /*
295*4882a593Smuzhiyun * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No.
296*4882a593Smuzhiyun */
iscsit_set_datain_values_yes_and_no(struct iscsi_cmd * cmd,struct iscsi_datain * datain)297*4882a593Smuzhiyun static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
298*4882a593Smuzhiyun struct iscsi_cmd *cmd,
299*4882a593Smuzhiyun struct iscsi_datain *datain)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun u32 next_burst_len, read_data_done, read_data_left;
302*4882a593Smuzhiyun struct iscsi_conn *conn = cmd->conn;
303*4882a593Smuzhiyun struct iscsi_datain_req *dr;
304*4882a593Smuzhiyun struct iscsi_pdu *pdu;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun dr = iscsit_get_datain_req(cmd);
307*4882a593Smuzhiyun if (!dr)
308*4882a593Smuzhiyun return NULL;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun if (dr->recovery && dr->generate_recovery_values) {
311*4882a593Smuzhiyun if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
312*4882a593Smuzhiyun cmd, dr) < 0)
313*4882a593Smuzhiyun return NULL;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun dr->generate_recovery_values = 0;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun next_burst_len = (!dr->recovery) ?
319*4882a593Smuzhiyun cmd->next_burst_len : dr->next_burst_len;
320*4882a593Smuzhiyun read_data_done = (!dr->recovery) ?
321*4882a593Smuzhiyun cmd->read_data_done : dr->read_data_done;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun read_data_left = (cmd->se_cmd.data_length - read_data_done);
324*4882a593Smuzhiyun if (!read_data_left) {
325*4882a593Smuzhiyun pr_err("ITT: 0x%08x read_data_left is zero!\n",
326*4882a593Smuzhiyun cmd->init_task_tag);
327*4882a593Smuzhiyun return dr;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL);
331*4882a593Smuzhiyun if (!pdu)
332*4882a593Smuzhiyun return dr;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {
335*4882a593Smuzhiyun pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
336*4882a593Smuzhiyun if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
337*4882a593Smuzhiyun pdu->flags |= ISCSI_FLAG_DATA_ACK;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun next_burst_len = 0;
340*4882a593Smuzhiyun } else {
341*4882a593Smuzhiyun if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) <
342*4882a593Smuzhiyun conn->sess->sess_ops->MaxBurstLength)
343*4882a593Smuzhiyun next_burst_len += pdu->length;
344*4882a593Smuzhiyun else {
345*4882a593Smuzhiyun pdu->flags |= ISCSI_FLAG_CMD_FINAL;
346*4882a593Smuzhiyun if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
347*4882a593Smuzhiyun pdu->flags |= ISCSI_FLAG_DATA_ACK;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun next_burst_len = 0;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
354*4882a593Smuzhiyun if (!dr->recovery) {
355*4882a593Smuzhiyun cmd->next_burst_len = next_burst_len;
356*4882a593Smuzhiyun cmd->read_data_done += pdu->length;
357*4882a593Smuzhiyun } else {
358*4882a593Smuzhiyun dr->next_burst_len = next_burst_len;
359*4882a593Smuzhiyun dr->read_data_done += pdu->length;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun datain->flags = pdu->flags;
363*4882a593Smuzhiyun datain->length = pdu->length;
364*4882a593Smuzhiyun datain->offset = pdu->offset;
365*4882a593Smuzhiyun datain->data_sn = pdu->data_sn;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun if (!dr->recovery) {
368*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_DATA_STATUS)
369*4882a593Smuzhiyun dr->dr_complete = DATAIN_COMPLETE_NORMAL;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun return dr;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (!dr->runlength) {
375*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
376*4882a593Smuzhiyun dr->dr_complete =
377*4882a593Smuzhiyun (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
378*4882a593Smuzhiyun DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
379*4882a593Smuzhiyun DATAIN_COMPLETE_CONNECTION_RECOVERY;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun } else {
382*4882a593Smuzhiyun if ((dr->begrun + dr->runlength) == dr->data_sn) {
383*4882a593Smuzhiyun dr->dr_complete =
384*4882a593Smuzhiyun (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
385*4882a593Smuzhiyun DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
386*4882a593Smuzhiyun DATAIN_COMPLETE_CONNECTION_RECOVERY;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun return dr;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /*
394*4882a593Smuzhiyun * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No.
395*4882a593Smuzhiyun */
iscsit_set_datain_values_no_and_no(struct iscsi_cmd * cmd,struct iscsi_datain * datain)396*4882a593Smuzhiyun static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
397*4882a593Smuzhiyun struct iscsi_cmd *cmd,
398*4882a593Smuzhiyun struct iscsi_datain *datain)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun u32 read_data_done, read_data_left, seq_send_order;
401*4882a593Smuzhiyun struct iscsi_conn *conn = cmd->conn;
402*4882a593Smuzhiyun struct iscsi_datain_req *dr;
403*4882a593Smuzhiyun struct iscsi_pdu *pdu;
404*4882a593Smuzhiyun struct iscsi_seq *seq = NULL;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun dr = iscsit_get_datain_req(cmd);
407*4882a593Smuzhiyun if (!dr)
408*4882a593Smuzhiyun return NULL;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun if (dr->recovery && dr->generate_recovery_values) {
411*4882a593Smuzhiyun if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
412*4882a593Smuzhiyun cmd, dr) < 0)
413*4882a593Smuzhiyun return NULL;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun dr->generate_recovery_values = 0;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun read_data_done = (!dr->recovery) ?
419*4882a593Smuzhiyun cmd->read_data_done : dr->read_data_done;
420*4882a593Smuzhiyun seq_send_order = (!dr->recovery) ?
421*4882a593Smuzhiyun cmd->seq_send_order : dr->seq_send_order;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun read_data_left = (cmd->se_cmd.data_length - read_data_done);
424*4882a593Smuzhiyun if (!read_data_left) {
425*4882a593Smuzhiyun pr_err("ITT: 0x%08x read_data_left is zero!\n",
426*4882a593Smuzhiyun cmd->init_task_tag);
427*4882a593Smuzhiyun return NULL;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
431*4882a593Smuzhiyun if (!seq)
432*4882a593Smuzhiyun return NULL;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun seq->sent = 1;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if (!dr->recovery && !seq->next_burst_len)
437*4882a593Smuzhiyun seq->first_datasn = cmd->data_sn;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun pdu = iscsit_get_pdu_holder_for_seq(cmd, seq);
440*4882a593Smuzhiyun if (!pdu)
441*4882a593Smuzhiyun return NULL;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun if (seq->pdu_send_order == seq->pdu_count) {
444*4882a593Smuzhiyun pdu->flags |= ISCSI_FLAG_CMD_FINAL;
445*4882a593Smuzhiyun if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
446*4882a593Smuzhiyun pdu->flags |= ISCSI_FLAG_DATA_ACK;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun seq->next_burst_len = 0;
449*4882a593Smuzhiyun seq_send_order++;
450*4882a593Smuzhiyun } else
451*4882a593Smuzhiyun seq->next_burst_len += pdu->length;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun if ((read_data_done + pdu->length) == cmd->se_cmd.data_length)
454*4882a593Smuzhiyun pdu->flags |= ISCSI_FLAG_DATA_STATUS;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
457*4882a593Smuzhiyun if (!dr->recovery) {
458*4882a593Smuzhiyun cmd->seq_send_order = seq_send_order;
459*4882a593Smuzhiyun cmd->read_data_done += pdu->length;
460*4882a593Smuzhiyun } else {
461*4882a593Smuzhiyun dr->seq_send_order = seq_send_order;
462*4882a593Smuzhiyun dr->read_data_done += pdu->length;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun datain->flags = pdu->flags;
466*4882a593Smuzhiyun datain->length = pdu->length;
467*4882a593Smuzhiyun datain->offset = pdu->offset;
468*4882a593Smuzhiyun datain->data_sn = pdu->data_sn;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (!dr->recovery) {
471*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_CMD_FINAL)
472*4882a593Smuzhiyun seq->last_datasn = datain->data_sn;
473*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_DATA_STATUS)
474*4882a593Smuzhiyun dr->dr_complete = DATAIN_COMPLETE_NORMAL;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun return dr;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun if (!dr->runlength) {
480*4882a593Smuzhiyun if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
481*4882a593Smuzhiyun dr->dr_complete =
482*4882a593Smuzhiyun (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
483*4882a593Smuzhiyun DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
484*4882a593Smuzhiyun DATAIN_COMPLETE_CONNECTION_RECOVERY;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun } else {
487*4882a593Smuzhiyun if ((dr->begrun + dr->runlength) == dr->data_sn) {
488*4882a593Smuzhiyun dr->dr_complete =
489*4882a593Smuzhiyun (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
490*4882a593Smuzhiyun DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
491*4882a593Smuzhiyun DATAIN_COMPLETE_CONNECTION_RECOVERY;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun return dr;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
iscsit_get_datain_values(struct iscsi_cmd * cmd,struct iscsi_datain * datain)498*4882a593Smuzhiyun struct iscsi_datain_req *iscsit_get_datain_values(
499*4882a593Smuzhiyun struct iscsi_cmd *cmd,
500*4882a593Smuzhiyun struct iscsi_datain *datain)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun struct iscsi_conn *conn = cmd->conn;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun if (conn->sess->sess_ops->DataSequenceInOrder &&
505*4882a593Smuzhiyun conn->sess->sess_ops->DataPDUInOrder)
506*4882a593Smuzhiyun return iscsit_set_datain_values_yes_and_yes(cmd, datain);
507*4882a593Smuzhiyun else if (!conn->sess->sess_ops->DataSequenceInOrder &&
508*4882a593Smuzhiyun conn->sess->sess_ops->DataPDUInOrder)
509*4882a593Smuzhiyun return iscsit_set_datain_values_no_and_yes(cmd, datain);
510*4882a593Smuzhiyun else if (conn->sess->sess_ops->DataSequenceInOrder &&
511*4882a593Smuzhiyun !conn->sess->sess_ops->DataPDUInOrder)
512*4882a593Smuzhiyun return iscsit_set_datain_values_yes_and_no(cmd, datain);
513*4882a593Smuzhiyun else if (!conn->sess->sess_ops->DataSequenceInOrder &&
514*4882a593Smuzhiyun !conn->sess->sess_ops->DataPDUInOrder)
515*4882a593Smuzhiyun return iscsit_set_datain_values_no_and_no(cmd, datain);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun return NULL;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_get_datain_values);
520