~ubuntu-branches/ubuntu/trusty/linux-armadaxp/trusty

« back to all changes in this revision

Viewing changes to drivers/target/iscsi/iscsi_target_erl0.c

  • Committer: Package Import Robot
  • Author(s): Michael Casadevall, Bryan Wu, Dann Frazier, Michael Casadeall
  • Date: 2012-03-10 15:00:54 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120310150054-flugb39zon8vvgwe
Tags: 3.2.0-1600.1
[ Bryan Wu ]
* UBUNTU: import debian/debian.env and debian.armadaxp

[ Dann Frazier ]
* ARM: Armada XP: remove trailing '/' in dirnames in mvRules.mk

[ Michael Casadeall ]
* tools: add some tools for Marvell Armada XP processor
* kernel: timer tick hacking from Marvell
* kernel: Sheeva Errata: add delay on Sheeva when powering down
* net: add Marvell NFP netfilter
* net: socket and skb modifications made by Marvell
* miscdevice: add minor IDs for some Marvell Armada drivers
* fs: introduce memory pool for splice()
* video: EDID detection updates from Marvell Armada XP patchset
* video: backlight: add Marvell Dove LCD backlight driver
* video: display: add THS8200 display driver
* video: framebuffer: add Marvell Dove and Armada XP processor onchip LCD controller driver
* usbtest: add Interrupt transfer testing by Marvell Armada XP code
* usb: ehci: add support for Marvell EHCI controler
* tty/serial: 8250: add support for Marvell Armada XP processor and DeviceTree work
* rtc: add support for Marvell Armada XP onchip RTC controller
* net: pppoe: add Marvell ethernet NFP hook in PPPoE networking driver
* mtd: nand: add support for Marvell Armada XP Nand Flash Controller
* mtd: maps: add Marvell Armada XP specific map driver
* mmc: add support for Marvell Armada XP MMC/SD host controller
* i2c: add support for Marvell Armada XP onchip i2c bus controller
* hwmon: add Kconfig option for Armada XP onchip thermal sensor driver
* dmaengine: add Net DMA support for splice and update Marvell XOR DMA engine driver
* ata: add support for Marvell Armada XP SATA controller and update some quirks
* ARM: add Marvell Armada XP machine to mach-types
* ARM: oprofile: add support for Marvell PJ4B core
* ARM: mm: more ARMv6 switches for Marvell Armada XP
* ARM: remove static declaration to allow compilation
* ARM: alignment access fault trick
* ARM: mm: skip some fault fixing when run on NONE SMP ARMv6 mode during early abort event
* ARM: mm: add Marvell Sheeva CPU Architecture for PJ4B
* ARM: introduce optimized copy operation for Marvell Armada XP
* ARM: SAUCE: hardware breakpoint trick for Marvell Armada XP
* ARM: big endian and little endian tricks for Marvell Armada XP
* ARM: SAUCE: Add Marvell Armada XP build rules to arch/arm/kernel/Makefile
* ARM: vfp: add special handling for Marvell Armada XP
* ARM: add support for Marvell U-Boot
* ARM: add mv_controller_num for ARM PCI drivers
* ARM: add support for local PMUs, general SMP tweaks and cache flushing
* ARM: add Marvell device identifies in glue-proc.h
* ARM: add IPC driver support for Marvell platforms
* ARM: add DMA mapping for Marvell platforms
* ARM: add Sheeva errata and PJ4B code for booting
* ARM: update Kconfig and Makefile to include Marvell Armada XP platforms
* ARM: Armada XP: import LSP from Marvell for Armada XP 3.2 kernel enablement

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 * This file contains error recovery level zero functions used by
 
3
 * the iSCSI Target driver.
 
4
 *
 
5
 * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
 
6
 *
 
7
 * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
 
8
 *
 
9
 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
 
10
 *
 
11
 * This program is free software; you can redistribute it and/or modify
 
12
 * it under the terms of the GNU General Public License as published by
 
13
 * the Free Software Foundation; either version 2 of the License, or
 
14
 * (at your option) any later version.
 
15
 *
 
16
 * This program is distributed in the hope that it will be useful,
 
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
 * GNU General Public License for more details.
 
20
 ******************************************************************************/
 
21
 
 
22
#include <scsi/iscsi_proto.h>
 
23
#include <target/target_core_base.h>
 
24
#include <target/target_core_transport.h>
 
25
 
 
26
#include "iscsi_target_core.h"
 
27
#include "iscsi_target_seq_pdu_list.h"
 
28
#include "iscsi_target_tq.h"
 
29
#include "iscsi_target_erl0.h"
 
30
#include "iscsi_target_erl1.h"
 
31
#include "iscsi_target_erl2.h"
 
32
#include "iscsi_target_util.h"
 
33
#include "iscsi_target.h"
 
34
 
 
35
/*
 
36
 *      Used to set values in struct iscsi_cmd that iscsit_dataout_check_sequence()
 
37
 *      checks against to determine a PDU's Offset+Length is within the current
 
38
 *      DataOUT Sequence.  Used for DataSequenceInOrder=Yes only.
 
39
 */
 
40
void iscsit_set_dataout_sequence_values(
 
41
        struct iscsi_cmd *cmd)
 
42
{
 
43
        struct iscsi_conn *conn = cmd->conn;
 
44
        /*
 
45
         * Still set seq_start_offset and seq_end_offset for Unsolicited
 
46
         * DataOUT, even if DataSequenceInOrder=No.
 
47
         */
 
48
        if (cmd->unsolicited_data) {
 
49
                cmd->seq_start_offset = cmd->write_data_done;
 
50
                cmd->seq_end_offset = (cmd->write_data_done +
 
51
                        (cmd->data_length >
 
52
                         conn->sess->sess_ops->FirstBurstLength) ?
 
53
                        conn->sess->sess_ops->FirstBurstLength : cmd->data_length);
 
54
                return;
 
55
        }
 
56
 
 
57
        if (!conn->sess->sess_ops->DataSequenceInOrder)
 
58
                return;
 
59
 
 
60
        if (!cmd->seq_start_offset && !cmd->seq_end_offset) {
 
61
                cmd->seq_start_offset = cmd->write_data_done;
 
62
                cmd->seq_end_offset = (cmd->data_length >
 
63
                        conn->sess->sess_ops->MaxBurstLength) ?
 
64
                        (cmd->write_data_done +
 
65
                        conn->sess->sess_ops->MaxBurstLength) : cmd->data_length;
 
66
        } else {
 
67
                cmd->seq_start_offset = cmd->seq_end_offset;
 
68
                cmd->seq_end_offset = ((cmd->seq_end_offset +
 
69
                        conn->sess->sess_ops->MaxBurstLength) >=
 
70
                        cmd->data_length) ? cmd->data_length :
 
71
                        (cmd->seq_end_offset +
 
72
                         conn->sess->sess_ops->MaxBurstLength);
 
73
        }
 
74
}
 
75
 
 
76
static int iscsit_dataout_within_command_recovery_check(
 
77
        struct iscsi_cmd *cmd,
 
78
        unsigned char *buf)
 
79
{
 
80
        struct iscsi_conn *conn = cmd->conn;
 
81
        struct iscsi_data *hdr = (struct iscsi_data *) buf;
 
82
        u32 payload_length = ntoh24(hdr->dlength);
 
83
 
 
84
        /*
 
85
         * We do the within-command recovery checks here as it is
 
86
         * the first function called in iscsi_check_pre_dataout().
 
87
         * Basically, if we are in within-command recovery and
 
88
         * the PDU does not contain the offset the sequence needs,
 
89
         * dump the payload.
 
90
         *
 
91
         * This only applies to DataPDUInOrder=Yes, for
 
92
         * DataPDUInOrder=No we only re-request the failed PDU
 
93
         * and check that all PDUs in a sequence are received
 
94
         * upon end of sequence.
 
95
         */
 
96
        if (conn->sess->sess_ops->DataSequenceInOrder) {
 
97
                if ((cmd->cmd_flags & ICF_WITHIN_COMMAND_RECOVERY) &&
 
98
                    (cmd->write_data_done != hdr->offset))
 
99
                        goto dump;
 
100
 
 
101
                cmd->cmd_flags &= ~ICF_WITHIN_COMMAND_RECOVERY;
 
102
        } else {
 
103
                struct iscsi_seq *seq;
 
104
 
 
105
                seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length);
 
106
                if (!seq)
 
107
                        return DATAOUT_CANNOT_RECOVER;
 
108
                /*
 
109
                 * Set the struct iscsi_seq pointer to reuse later.
 
110
                 */
 
111
                cmd->seq_ptr = seq;
 
112
 
 
113
                if (conn->sess->sess_ops->DataPDUInOrder) {
 
114
                        if ((seq->status ==
 
115
                             DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) &&
 
116
                           ((seq->offset != hdr->offset) ||
 
117
                            (seq->data_sn != hdr->datasn)))
 
118
                                goto dump;
 
119
                } else {
 
120
                        if ((seq->status ==
 
121
                             DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) &&
 
122
                            (seq->data_sn != hdr->datasn))
 
123
                                goto dump;
 
124
                }
 
125
 
 
126
                if (seq->status == DATAOUT_SEQUENCE_COMPLETE)
 
127
                        goto dump;
 
128
 
 
129
                if (seq->status != DATAOUT_SEQUENCE_COMPLETE)
 
130
                        seq->status = 0;
 
131
        }
 
132
 
 
133
        return DATAOUT_NORMAL;
 
134
 
 
135
dump:
 
136
        pr_err("Dumping DataOUT PDU Offset: %u Length: %d DataSN:"
 
137
                " 0x%08x\n", hdr->offset, payload_length, hdr->datasn);
 
138
        return iscsit_dump_data_payload(conn, payload_length, 1);
 
139
}
 
140
 
 
141
static int iscsit_dataout_check_unsolicited_sequence(
 
142
        struct iscsi_cmd *cmd,
 
143
        unsigned char *buf)
 
144
{
 
145
        u32 first_burst_len;
 
146
        struct iscsi_conn *conn = cmd->conn;
 
147
        struct iscsi_data *hdr = (struct iscsi_data *) buf;
 
148
        u32 payload_length = ntoh24(hdr->dlength);
 
149
 
 
150
 
 
151
        if ((hdr->offset < cmd->seq_start_offset) ||
 
152
           ((hdr->offset + payload_length) > cmd->seq_end_offset)) {
 
153
                pr_err("Command ITT: 0x%08x with Offset: %u,"
 
154
                " Length: %u outside of Unsolicited Sequence %u:%u while"
 
155
                " DataSequenceInOrder=Yes.\n", cmd->init_task_tag,
 
156
                hdr->offset, payload_length, cmd->seq_start_offset,
 
157
                        cmd->seq_end_offset);
 
158
                return DATAOUT_CANNOT_RECOVER;
 
159
        }
 
160
 
 
161
        first_burst_len = (cmd->first_burst_len + payload_length);
 
162
 
 
163
        if (first_burst_len > conn->sess->sess_ops->FirstBurstLength) {
 
164
                pr_err("Total %u bytes exceeds FirstBurstLength: %u"
 
165
                        " for this Unsolicited DataOut Burst.\n",
 
166
                        first_burst_len, conn->sess->sess_ops->FirstBurstLength);
 
167
                transport_send_check_condition_and_sense(&cmd->se_cmd,
 
168
                                TCM_INCORRECT_AMOUNT_OF_DATA, 0);
 
169
                return DATAOUT_CANNOT_RECOVER;
 
170
        }
 
171
 
 
172
        /*
 
173
         * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity
 
174
         * checks for the current Unsolicited DataOUT Sequence.
 
175
         */
 
176
        if (hdr->flags & ISCSI_FLAG_CMD_FINAL) {
 
177
                /*
 
178
                 * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of
 
179
                 * sequence checks are handled in
 
180
                 * iscsit_dataout_datapduinorder_no_fbit().
 
181
                 */
 
182
                if (!conn->sess->sess_ops->DataPDUInOrder)
 
183
                        goto out;
 
184
 
 
185
                if ((first_burst_len != cmd->data_length) &&
 
186
                    (first_burst_len != conn->sess->sess_ops->FirstBurstLength)) {
 
187
                        pr_err("Unsolicited non-immediate data"
 
188
                        " received %u does not equal FirstBurstLength: %u, and"
 
189
                        " does not equal ExpXferLen %u.\n", first_burst_len,
 
190
                                conn->sess->sess_ops->FirstBurstLength,
 
191
                                cmd->data_length);
 
192
                        transport_send_check_condition_and_sense(&cmd->se_cmd,
 
193
                                        TCM_INCORRECT_AMOUNT_OF_DATA, 0);
 
194
                        return DATAOUT_CANNOT_RECOVER;
 
195
                }
 
196
        } else {
 
197
                if (first_burst_len == conn->sess->sess_ops->FirstBurstLength) {
 
198
                        pr_err("Command ITT: 0x%08x reached"
 
199
                        " FirstBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol"
 
200
                                " error.\n", cmd->init_task_tag,
 
201
                                conn->sess->sess_ops->FirstBurstLength);
 
202
                        return DATAOUT_CANNOT_RECOVER;
 
203
                }
 
204
                if (first_burst_len == cmd->data_length) {
 
205
                        pr_err("Command ITT: 0x%08x reached"
 
206
                        " ExpXferLen: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol"
 
207
                        " error.\n", cmd->init_task_tag, cmd->data_length);
 
208
                        return DATAOUT_CANNOT_RECOVER;
 
209
                }
 
210
        }
 
211
 
 
212
out:
 
213
        return DATAOUT_NORMAL;
 
214
}
 
215
 
 
216
static int iscsit_dataout_check_sequence(
 
217
        struct iscsi_cmd *cmd,
 
218
        unsigned char *buf)
 
219
{
 
220
        u32 next_burst_len;
 
221
        struct iscsi_conn *conn = cmd->conn;
 
222
        struct iscsi_seq *seq = NULL;
 
223
        struct iscsi_data *hdr = (struct iscsi_data *) buf;
 
224
        u32 payload_length = ntoh24(hdr->dlength);
 
225
 
 
226
        /*
 
227
         * For DataSequenceInOrder=Yes: Check that the offset and offset+length
 
228
         * is within range as defined by iscsi_set_dataout_sequence_values().
 
229
         *
 
230
         * For DataSequenceInOrder=No: Check that an struct iscsi_seq exists for
 
231
         * offset+length tuple.
 
232
         */
 
233
        if (conn->sess->sess_ops->DataSequenceInOrder) {
 
234
                /*
 
235
                 * Due to possibility of recovery DataOUT sent by the initiator
 
236
                 * fullfilling an Recovery R2T, it's best to just dump the
 
237
                 * payload here, instead of erroring out.
 
238
                 */
 
239
                if ((hdr->offset < cmd->seq_start_offset) ||
 
240
                   ((hdr->offset + payload_length) > cmd->seq_end_offset)) {
 
241
                        pr_err("Command ITT: 0x%08x with Offset: %u,"
 
242
                        " Length: %u outside of Sequence %u:%u while"
 
243
                        " DataSequenceInOrder=Yes.\n", cmd->init_task_tag,
 
244
                        hdr->offset, payload_length, cmd->seq_start_offset,
 
245
                                cmd->seq_end_offset);
 
246
 
 
247
                        if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
 
248
                                return DATAOUT_CANNOT_RECOVER;
 
249
                        return DATAOUT_WITHIN_COMMAND_RECOVERY;
 
250
                }
 
251
 
 
252
                next_burst_len = (cmd->next_burst_len + payload_length);
 
253
        } else {
 
254
                seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length);
 
255
                if (!seq)
 
256
                        return DATAOUT_CANNOT_RECOVER;
 
257
                /*
 
258
                 * Set the struct iscsi_seq pointer to reuse later.
 
259
                 */
 
260
                cmd->seq_ptr = seq;
 
261
 
 
262
                if (seq->status == DATAOUT_SEQUENCE_COMPLETE) {
 
263
                        if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
 
264
                                return DATAOUT_CANNOT_RECOVER;
 
265
                        return DATAOUT_WITHIN_COMMAND_RECOVERY;
 
266
                }
 
267
 
 
268
                next_burst_len = (seq->next_burst_len + payload_length);
 
269
        }
 
270
 
 
271
        if (next_burst_len > conn->sess->sess_ops->MaxBurstLength) {
 
272
                pr_err("Command ITT: 0x%08x, NextBurstLength: %u and"
 
273
                        " Length: %u exceeds MaxBurstLength: %u. protocol"
 
274
                        " error.\n", cmd->init_task_tag,
 
275
                        (next_burst_len - payload_length),
 
276
                        payload_length, conn->sess->sess_ops->MaxBurstLength);
 
277
                return DATAOUT_CANNOT_RECOVER;
 
278
        }
 
279
 
 
280
        /*
 
281
         * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity
 
282
         * checks for the current DataOUT Sequence.
 
283
         */
 
284
        if (hdr->flags & ISCSI_FLAG_CMD_FINAL) {
 
285
                /*
 
286
                 * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of
 
287
                 * sequence checks are handled in
 
288
                 * iscsit_dataout_datapduinorder_no_fbit().
 
289
                 */
 
290
                if (!conn->sess->sess_ops->DataPDUInOrder)
 
291
                        goto out;
 
292
 
 
293
                if (conn->sess->sess_ops->DataSequenceInOrder) {
 
294
                        if ((next_burst_len <
 
295
                             conn->sess->sess_ops->MaxBurstLength) &&
 
296
                           ((cmd->write_data_done + payload_length) <
 
297
                             cmd->data_length)) {
 
298
                                pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL"
 
299
                                " before end of DataOUT sequence, protocol"
 
300
                                " error.\n", cmd->init_task_tag);
 
301
                                return DATAOUT_CANNOT_RECOVER;
 
302
                        }
 
303
                } else {
 
304
                        if (next_burst_len < seq->xfer_len) {
 
305
                                pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL"
 
306
                                " before end of DataOUT sequence, protocol"
 
307
                                " error.\n", cmd->init_task_tag);
 
308
                                return DATAOUT_CANNOT_RECOVER;
 
309
                        }
 
310
                }
 
311
        } else {
 
312
                if (conn->sess->sess_ops->DataSequenceInOrder) {
 
313
                        if (next_burst_len ==
 
314
                                        conn->sess->sess_ops->MaxBurstLength) {
 
315
                                pr_err("Command ITT: 0x%08x reached"
 
316
                                " MaxBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is"
 
317
                                " not set, protocol error.", cmd->init_task_tag,
 
318
                                        conn->sess->sess_ops->MaxBurstLength);
 
319
                                return DATAOUT_CANNOT_RECOVER;
 
320
                        }
 
321
                        if ((cmd->write_data_done + payload_length) ==
 
322
                                        cmd->data_length) {
 
323
                                pr_err("Command ITT: 0x%08x reached"
 
324
                                " last DataOUT PDU in sequence but ISCSI_FLAG_"
 
325
                                "CMD_FINAL is not set, protocol error.\n",
 
326
                                        cmd->init_task_tag);
 
327
                                return DATAOUT_CANNOT_RECOVER;
 
328
                        }
 
329
                } else {
 
330
                        if (next_burst_len == seq->xfer_len) {
 
331
                                pr_err("Command ITT: 0x%08x reached"
 
332
                                " last DataOUT PDU in sequence but ISCSI_FLAG_"
 
333
                                "CMD_FINAL is not set, protocol error.\n",
 
334
                                        cmd->init_task_tag);
 
335
                                return DATAOUT_CANNOT_RECOVER;
 
336
                        }
 
337
                }
 
338
        }
 
339
 
 
340
out:
 
341
        return DATAOUT_NORMAL;
 
342
}
 
343
 
 
344
static int iscsit_dataout_check_datasn(
 
345
        struct iscsi_cmd *cmd,
 
346
        unsigned char *buf)
 
347
{
 
348
        int dump = 0, recovery = 0;
 
349
        u32 data_sn = 0;
 
350
        struct iscsi_conn *conn = cmd->conn;
 
351
        struct iscsi_data *hdr = (struct iscsi_data *) buf;
 
352
        u32 payload_length = ntoh24(hdr->dlength);
 
353
 
 
354
        /*
 
355
         * Considering the target has no method of re-requesting DataOUT
 
356
         * by DataSN, if we receieve a greater DataSN than expected we
 
357
         * assume the functions for DataPDUInOrder=[Yes,No] below will
 
358
         * handle it.
 
359
         *
 
360
         * If the DataSN is less than expected, dump the payload.
 
361
         */
 
362
        if (conn->sess->sess_ops->DataSequenceInOrder)
 
363
                data_sn = cmd->data_sn;
 
364
        else {
 
365
                struct iscsi_seq *seq = cmd->seq_ptr;
 
366
                data_sn = seq->data_sn;
 
367
        }
 
368
 
 
369
        if (hdr->datasn > data_sn) {
 
370
                pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
 
371
                        " higher than expected 0x%08x.\n", cmd->init_task_tag,
 
372
                                hdr->datasn, data_sn);
 
373
                recovery = 1;
 
374
                goto recover;
 
375
        } else if (hdr->datasn < data_sn) {
 
376
                pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
 
377
                        " lower than expected 0x%08x, discarding payload.\n",
 
378
                        cmd->init_task_tag, hdr->datasn, data_sn);
 
379
                dump = 1;
 
380
                goto dump;
 
381
        }
 
382
 
 
383
        return DATAOUT_NORMAL;
 
384
 
 
385
recover:
 
386
        if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
 
387
                pr_err("Unable to perform within-command recovery"
 
388
                                " while ERL=0.\n");
 
389
                return DATAOUT_CANNOT_RECOVER;
 
390
        }
 
391
dump:
 
392
        if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
 
393
                return DATAOUT_CANNOT_RECOVER;
 
394
 
 
395
        return (recovery || dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY :
 
396
                                DATAOUT_NORMAL;
 
397
}
 
398
 
 
399
static int iscsit_dataout_pre_datapduinorder_yes(
 
400
        struct iscsi_cmd *cmd,
 
401
        unsigned char *buf)
 
402
{
 
403
        int dump = 0, recovery = 0;
 
404
        struct iscsi_conn *conn = cmd->conn;
 
405
        struct iscsi_data *hdr = (struct iscsi_data *) buf;
 
406
        u32 payload_length = ntoh24(hdr->dlength);
 
407
 
 
408
        /*
 
409
         * For DataSequenceInOrder=Yes: If the offset is greater than the global
 
410
         * DataPDUInOrder=Yes offset counter in struct iscsi_cmd a protcol error has
 
411
         * occured and fail the connection.
 
412
         *
 
413
         * For DataSequenceInOrder=No: If the offset is greater than the per
 
414
         * sequence DataPDUInOrder=Yes offset counter in struct iscsi_seq a protocol
 
415
         * error has occured and fail the connection.
 
416
         */
 
417
        if (conn->sess->sess_ops->DataSequenceInOrder) {
 
418
                if (hdr->offset != cmd->write_data_done) {
 
419
                        pr_err("Command ITT: 0x%08x, received offset"
 
420
                        " %u different than expected %u.\n", cmd->init_task_tag,
 
421
                                hdr->offset, cmd->write_data_done);
 
422
                        recovery = 1;
 
423
                        goto recover;
 
424
                }
 
425
        } else {
 
426
                struct iscsi_seq *seq = cmd->seq_ptr;
 
427
 
 
428
                if (hdr->offset > seq->offset) {
 
429
                        pr_err("Command ITT: 0x%08x, received offset"
 
430
                        " %u greater than expected %u.\n", cmd->init_task_tag,
 
431
                                hdr->offset, seq->offset);
 
432
                        recovery = 1;
 
433
                        goto recover;
 
434
                } else if (hdr->offset < seq->offset) {
 
435
                        pr_err("Command ITT: 0x%08x, received offset"
 
436
                        " %u less than expected %u, discarding payload.\n",
 
437
                                cmd->init_task_tag, hdr->offset, seq->offset);
 
438
                        dump = 1;
 
439
                        goto dump;
 
440
                }
 
441
        }
 
442
 
 
443
        return DATAOUT_NORMAL;
 
444
 
 
445
recover:
 
446
        if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
 
447
                pr_err("Unable to perform within-command recovery"
 
448
                                " while ERL=0.\n");
 
449
                return DATAOUT_CANNOT_RECOVER;
 
450
        }
 
451
dump:
 
452
        if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
 
453
                return DATAOUT_CANNOT_RECOVER;
 
454
 
 
455
        return (recovery) ? iscsit_recover_dataout_sequence(cmd,
 
456
                hdr->offset, payload_length) :
 
457
               (dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY : DATAOUT_NORMAL;
 
458
}
 
459
 
 
460
static int iscsit_dataout_pre_datapduinorder_no(
 
461
        struct iscsi_cmd *cmd,
 
462
        unsigned char *buf)
 
463
{
 
464
        struct iscsi_pdu *pdu;
 
465
        struct iscsi_data *hdr = (struct iscsi_data *) buf;
 
466
        u32 payload_length = ntoh24(hdr->dlength);
 
467
 
 
468
        pdu = iscsit_get_pdu_holder(cmd, hdr->offset, payload_length);
 
469
        if (!pdu)
 
470
                return DATAOUT_CANNOT_RECOVER;
 
471
 
 
472
        cmd->pdu_ptr = pdu;
 
473
 
 
474
        switch (pdu->status) {
 
475
        case ISCSI_PDU_NOT_RECEIVED:
 
476
        case ISCSI_PDU_CRC_FAILED:
 
477
        case ISCSI_PDU_TIMED_OUT:
 
478
                break;
 
479
        case ISCSI_PDU_RECEIVED_OK:
 
480
                pr_err("Command ITT: 0x%08x received already gotten"
 
481
                        " Offset: %u, Length: %u\n", cmd->init_task_tag,
 
482
                                hdr->offset, payload_length);
 
483
                return iscsit_dump_data_payload(cmd->conn, payload_length, 1);
 
484
        default:
 
485
                return DATAOUT_CANNOT_RECOVER;
 
486
        }
 
487
 
 
488
        return DATAOUT_NORMAL;
 
489
}
 
490
 
 
491
static int iscsit_dataout_update_r2t(struct iscsi_cmd *cmd, u32 offset, u32 length)
 
492
{
 
493
        struct iscsi_r2t *r2t;
 
494
 
 
495
        if (cmd->unsolicited_data)
 
496
                return 0;
 
497
 
 
498
        r2t = iscsit_get_r2t_for_eos(cmd, offset, length);
 
499
        if (!r2t)
 
500
                return -1;
 
501
 
 
502
        spin_lock_bh(&cmd->r2t_lock);
 
503
        r2t->seq_complete = 1;
 
504
        cmd->outstanding_r2ts--;
 
505
        spin_unlock_bh(&cmd->r2t_lock);
 
506
 
 
507
        return 0;
 
508
}
 
509
 
 
510
static int iscsit_dataout_update_datapduinorder_no(
 
511
        struct iscsi_cmd *cmd,
 
512
        u32 data_sn,
 
513
        int f_bit)
 
514
{
 
515
        int ret = 0;
 
516
        struct iscsi_pdu *pdu = cmd->pdu_ptr;
 
517
 
 
518
        pdu->data_sn = data_sn;
 
519
 
 
520
        switch (pdu->status) {
 
521
        case ISCSI_PDU_NOT_RECEIVED:
 
522
                pdu->status = ISCSI_PDU_RECEIVED_OK;
 
523
                break;
 
524
        case ISCSI_PDU_CRC_FAILED:
 
525
                pdu->status = ISCSI_PDU_RECEIVED_OK;
 
526
                break;
 
527
        case ISCSI_PDU_TIMED_OUT:
 
528
                pdu->status = ISCSI_PDU_RECEIVED_OK;
 
529
                break;
 
530
        default:
 
531
                return DATAOUT_CANNOT_RECOVER;
 
532
        }
 
533
 
 
534
        if (f_bit) {
 
535
                ret = iscsit_dataout_datapduinorder_no_fbit(cmd, pdu);
 
536
                if (ret == DATAOUT_CANNOT_RECOVER)
 
537
                        return ret;
 
538
        }
 
539
 
 
540
        return DATAOUT_NORMAL;
 
541
}
 
542
 
 
543
static int iscsit_dataout_post_crc_passed(
 
544
        struct iscsi_cmd *cmd,
 
545
        unsigned char *buf)
 
546
{
 
547
        int ret, send_r2t = 0;
 
548
        struct iscsi_conn *conn = cmd->conn;
 
549
        struct iscsi_seq *seq = NULL;
 
550
        struct iscsi_data *hdr = (struct iscsi_data *) buf;
 
551
        u32 payload_length = ntoh24(hdr->dlength);
 
552
 
 
553
        if (cmd->unsolicited_data) {
 
554
                if ((cmd->first_burst_len + payload_length) ==
 
555
                     conn->sess->sess_ops->FirstBurstLength) {
 
556
                        if (iscsit_dataout_update_r2t(cmd, hdr->offset,
 
557
                                        payload_length) < 0)
 
558
                                return DATAOUT_CANNOT_RECOVER;
 
559
                        send_r2t = 1;
 
560
                }
 
561
 
 
562
                if (!conn->sess->sess_ops->DataPDUInOrder) {
 
563
                        ret = iscsit_dataout_update_datapduinorder_no(cmd,
 
564
                                hdr->datasn, (hdr->flags & ISCSI_FLAG_CMD_FINAL));
 
565
                        if (ret == DATAOUT_CANNOT_RECOVER)
 
566
                                return ret;
 
567
                }
 
568
 
 
569
                cmd->first_burst_len += payload_length;
 
570
 
 
571
                if (conn->sess->sess_ops->DataSequenceInOrder)
 
572
                        cmd->data_sn++;
 
573
                else {
 
574
                        seq = cmd->seq_ptr;
 
575
                        seq->data_sn++;
 
576
                        seq->offset += payload_length;
 
577
                }
 
578
 
 
579
                if (send_r2t) {
 
580
                        if (seq)
 
581
                                seq->status = DATAOUT_SEQUENCE_COMPLETE;
 
582
                        cmd->first_burst_len = 0;
 
583
                        cmd->unsolicited_data = 0;
 
584
                }
 
585
        } else {
 
586
                if (conn->sess->sess_ops->DataSequenceInOrder) {
 
587
                        if ((cmd->next_burst_len + payload_length) ==
 
588
                             conn->sess->sess_ops->MaxBurstLength) {
 
589
                                if (iscsit_dataout_update_r2t(cmd, hdr->offset,
 
590
                                                payload_length) < 0)
 
591
                                        return DATAOUT_CANNOT_RECOVER;
 
592
                                send_r2t = 1;
 
593
                        }
 
594
 
 
595
                        if (!conn->sess->sess_ops->DataPDUInOrder) {
 
596
                                ret = iscsit_dataout_update_datapduinorder_no(
 
597
                                                cmd, hdr->datasn,
 
598
                                                (hdr->flags & ISCSI_FLAG_CMD_FINAL));
 
599
                                if (ret == DATAOUT_CANNOT_RECOVER)
 
600
                                        return ret;
 
601
                        }
 
602
 
 
603
                        cmd->next_burst_len += payload_length;
 
604
                        cmd->data_sn++;
 
605
 
 
606
                        if (send_r2t)
 
607
                                cmd->next_burst_len = 0;
 
608
                } else {
 
609
                        seq = cmd->seq_ptr;
 
610
 
 
611
                        if ((seq->next_burst_len + payload_length) ==
 
612
                             seq->xfer_len) {
 
613
                                if (iscsit_dataout_update_r2t(cmd, hdr->offset,
 
614
                                                payload_length) < 0)
 
615
                                        return DATAOUT_CANNOT_RECOVER;
 
616
                                send_r2t = 1;
 
617
                        }
 
618
 
 
619
                        if (!conn->sess->sess_ops->DataPDUInOrder) {
 
620
                                ret = iscsit_dataout_update_datapduinorder_no(
 
621
                                                cmd, hdr->datasn,
 
622
                                                (hdr->flags & ISCSI_FLAG_CMD_FINAL));
 
623
                                if (ret == DATAOUT_CANNOT_RECOVER)
 
624
                                        return ret;
 
625
                        }
 
626
 
 
627
                        seq->data_sn++;
 
628
                        seq->offset += payload_length;
 
629
                        seq->next_burst_len += payload_length;
 
630
 
 
631
                        if (send_r2t) {
 
632
                                seq->next_burst_len = 0;
 
633
                                seq->status = DATAOUT_SEQUENCE_COMPLETE;
 
634
                        }
 
635
                }
 
636
        }
 
637
 
 
638
        if (send_r2t && conn->sess->sess_ops->DataSequenceInOrder)
 
639
                cmd->data_sn = 0;
 
640
 
 
641
        cmd->write_data_done += payload_length;
 
642
 
 
643
        return (cmd->write_data_done == cmd->data_length) ?
 
644
                DATAOUT_SEND_TO_TRANSPORT : (send_r2t) ?
 
645
                DATAOUT_SEND_R2T : DATAOUT_NORMAL;
 
646
}
 
647
 
 
648
static int iscsit_dataout_post_crc_failed(
 
649
        struct iscsi_cmd *cmd,
 
650
        unsigned char *buf)
 
651
{
 
652
        struct iscsi_conn *conn = cmd->conn;
 
653
        struct iscsi_pdu *pdu;
 
654
        struct iscsi_data *hdr = (struct iscsi_data *) buf;
 
655
        u32 payload_length = ntoh24(hdr->dlength);
 
656
 
 
657
        if (conn->sess->sess_ops->DataPDUInOrder)
 
658
                goto recover;
 
659
        /*
 
660
         * The rest of this function is only called when DataPDUInOrder=No.
 
661
         */
 
662
        pdu = cmd->pdu_ptr;
 
663
 
 
664
        switch (pdu->status) {
 
665
        case ISCSI_PDU_NOT_RECEIVED:
 
666
                pdu->status = ISCSI_PDU_CRC_FAILED;
 
667
                break;
 
668
        case ISCSI_PDU_CRC_FAILED:
 
669
                break;
 
670
        case ISCSI_PDU_TIMED_OUT:
 
671
                pdu->status = ISCSI_PDU_CRC_FAILED;
 
672
                break;
 
673
        default:
 
674
                return DATAOUT_CANNOT_RECOVER;
 
675
        }
 
676
 
 
677
recover:
 
678
        return iscsit_recover_dataout_sequence(cmd, hdr->offset, payload_length);
 
679
}
 
680
 
 
681
/*
 
682
 *      Called from iscsit_handle_data_out() before DataOUT Payload is received
 
683
 *      and CRC computed.
 
684
 */
 
685
extern int iscsit_check_pre_dataout(
 
686
        struct iscsi_cmd *cmd,
 
687
        unsigned char *buf)
 
688
{
 
689
        int ret;
 
690
        struct iscsi_conn *conn = cmd->conn;
 
691
 
 
692
        ret = iscsit_dataout_within_command_recovery_check(cmd, buf);
 
693
        if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||
 
694
            (ret == DATAOUT_CANNOT_RECOVER))
 
695
                return ret;
 
696
 
 
697
        ret = iscsit_dataout_check_datasn(cmd, buf);
 
698
        if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||
 
699
            (ret == DATAOUT_CANNOT_RECOVER))
 
700
                return ret;
 
701
 
 
702
        if (cmd->unsolicited_data) {
 
703
                ret = iscsit_dataout_check_unsolicited_sequence(cmd, buf);
 
704
                if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||
 
705
                    (ret == DATAOUT_CANNOT_RECOVER))
 
706
                        return ret;
 
707
        } else {
 
708
                ret = iscsit_dataout_check_sequence(cmd, buf);
 
709
                if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||
 
710
                    (ret == DATAOUT_CANNOT_RECOVER))
 
711
                        return ret;
 
712
        }
 
713
 
 
714
        return (conn->sess->sess_ops->DataPDUInOrder) ?
 
715
                iscsit_dataout_pre_datapduinorder_yes(cmd, buf) :
 
716
                iscsit_dataout_pre_datapduinorder_no(cmd, buf);
 
717
}
 
718
 
 
719
/*
 
720
 *      Called from iscsit_handle_data_out() after DataOUT Payload is received
 
721
 *      and CRC computed.
 
722
 */
 
723
int iscsit_check_post_dataout(
 
724
        struct iscsi_cmd *cmd,
 
725
        unsigned char *buf,
 
726
        u8 data_crc_failed)
 
727
{
 
728
        struct iscsi_conn *conn = cmd->conn;
 
729
 
 
730
        cmd->dataout_timeout_retries = 0;
 
731
 
 
732
        if (!data_crc_failed)
 
733
                return iscsit_dataout_post_crc_passed(cmd, buf);
 
734
        else {
 
735
                if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
 
736
                        pr_err("Unable to recover from DataOUT CRC"
 
737
                                " failure while ERL=0, closing session.\n");
 
738
                        iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
 
739
                                        1, 0, buf, cmd);
 
740
                        return DATAOUT_CANNOT_RECOVER;
 
741
                }
 
742
 
 
743
                iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
 
744
                                0, 0, buf, cmd);
 
745
                return iscsit_dataout_post_crc_failed(cmd, buf);
 
746
        }
 
747
}
 
748
 
 
749
static void iscsit_handle_time2retain_timeout(unsigned long data)
 
750
{
 
751
        struct iscsi_session *sess = (struct iscsi_session *) data;
 
752
        struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess);
 
753
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
 
754
 
 
755
        spin_lock_bh(&se_tpg->session_lock);
 
756
        if (sess->time2retain_timer_flags & ISCSI_TF_STOP) {
 
757
                spin_unlock_bh(&se_tpg->session_lock);
 
758
                return;
 
759
        }
 
760
        if (atomic_read(&sess->session_reinstatement)) {
 
761
                pr_err("Exiting Time2Retain handler because"
 
762
                                " session_reinstatement=1\n");
 
763
                spin_unlock_bh(&se_tpg->session_lock);
 
764
                return;
 
765
        }
 
766
        sess->time2retain_timer_flags |= ISCSI_TF_EXPIRED;
 
767
 
 
768
        pr_err("Time2Retain timer expired for SID: %u, cleaning up"
 
769
                        " iSCSI session.\n", sess->sid);
 
770
        {
 
771
        struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
 
772
 
 
773
        if (tiqn) {
 
774
                spin_lock(&tiqn->sess_err_stats.lock);
 
775
                strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
 
776
                        (void *)sess->sess_ops->InitiatorName);
 
777
                tiqn->sess_err_stats.last_sess_failure_type =
 
778
                                ISCSI_SESS_ERR_CXN_TIMEOUT;
 
779
                tiqn->sess_err_stats.cxn_timeout_errors++;
 
780
                sess->conn_timeout_errors++;
 
781
                spin_unlock(&tiqn->sess_err_stats.lock);
 
782
        }
 
783
        }
 
784
 
 
785
        spin_unlock_bh(&se_tpg->session_lock);
 
786
        iscsit_close_session(sess);
 
787
}
 
788
 
 
789
extern void iscsit_start_time2retain_handler(struct iscsi_session *sess)
 
790
{
 
791
        int tpg_active;
 
792
        /*
 
793
         * Only start Time2Retain timer when the assoicated TPG is still in
 
794
         * an ACTIVE (eg: not disabled or shutdown) state.
 
795
         */
 
796
        spin_lock(&ISCSI_TPG_S(sess)->tpg_state_lock);
 
797
        tpg_active = (ISCSI_TPG_S(sess)->tpg_state == TPG_STATE_ACTIVE);
 
798
        spin_unlock(&ISCSI_TPG_S(sess)->tpg_state_lock);
 
799
 
 
800
        if (!tpg_active)
 
801
                return;
 
802
 
 
803
        if (sess->time2retain_timer_flags & ISCSI_TF_RUNNING)
 
804
                return;
 
805
 
 
806
        pr_debug("Starting Time2Retain timer for %u seconds on"
 
807
                " SID: %u\n", sess->sess_ops->DefaultTime2Retain, sess->sid);
 
808
 
 
809
        init_timer(&sess->time2retain_timer);
 
810
        sess->time2retain_timer.expires =
 
811
                (get_jiffies_64() + sess->sess_ops->DefaultTime2Retain * HZ);
 
812
        sess->time2retain_timer.data = (unsigned long)sess;
 
813
        sess->time2retain_timer.function = iscsit_handle_time2retain_timeout;
 
814
        sess->time2retain_timer_flags &= ~ISCSI_TF_STOP;
 
815
        sess->time2retain_timer_flags |= ISCSI_TF_RUNNING;
 
816
        add_timer(&sess->time2retain_timer);
 
817
}
 
818
 
 
819
/*
 
820
 *      Called with spin_lock_bh(&struct se_portal_group->session_lock) held
 
821
 */
 
822
extern int iscsit_stop_time2retain_timer(struct iscsi_session *sess)
 
823
{
 
824
        struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess);
 
825
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
 
826
 
 
827
        if (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)
 
828
                return -1;
 
829
 
 
830
        if (!(sess->time2retain_timer_flags & ISCSI_TF_RUNNING))
 
831
                return 0;
 
832
 
 
833
        sess->time2retain_timer_flags |= ISCSI_TF_STOP;
 
834
        spin_unlock_bh(&se_tpg->session_lock);
 
835
 
 
836
        del_timer_sync(&sess->time2retain_timer);
 
837
 
 
838
        spin_lock_bh(&se_tpg->session_lock);
 
839
        sess->time2retain_timer_flags &= ~ISCSI_TF_RUNNING;
 
840
        pr_debug("Stopped Time2Retain Timer for SID: %u\n",
 
841
                        sess->sid);
 
842
        return 0;
 
843
}
 
844
 
 
845
void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *conn)
 
846
{
 
847
        spin_lock_bh(&conn->state_lock);
 
848
        if (atomic_read(&conn->connection_exit)) {
 
849
                spin_unlock_bh(&conn->state_lock);
 
850
                goto sleep;
 
851
        }
 
852
 
 
853
        if (atomic_read(&conn->transport_failed)) {
 
854
                spin_unlock_bh(&conn->state_lock);
 
855
                goto sleep;
 
856
        }
 
857
        spin_unlock_bh(&conn->state_lock);
 
858
 
 
859
        iscsi_thread_set_force_reinstatement(conn);
 
860
 
 
861
sleep:
 
862
        wait_for_completion(&conn->conn_wait_rcfr_comp);
 
863
        complete(&conn->conn_post_wait_comp);
 
864
}
 
865
 
 
866
void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep)
 
867
{
 
868
        spin_lock_bh(&conn->state_lock);
 
869
        if (atomic_read(&conn->connection_exit)) {
 
870
                spin_unlock_bh(&conn->state_lock);
 
871
                return;
 
872
        }
 
873
 
 
874
        if (atomic_read(&conn->transport_failed)) {
 
875
                spin_unlock_bh(&conn->state_lock);
 
876
                return;
 
877
        }
 
878
 
 
879
        if (atomic_read(&conn->connection_reinstatement)) {
 
880
                spin_unlock_bh(&conn->state_lock);
 
881
                return;
 
882
        }
 
883
 
 
884
        if (iscsi_thread_set_force_reinstatement(conn) < 0) {
 
885
                spin_unlock_bh(&conn->state_lock);
 
886
                return;
 
887
        }
 
888
 
 
889
        atomic_set(&conn->connection_reinstatement, 1);
 
890
        if (!sleep) {
 
891
                spin_unlock_bh(&conn->state_lock);
 
892
                return;
 
893
        }
 
894
 
 
895
        atomic_set(&conn->sleep_on_conn_wait_comp, 1);
 
896
        spin_unlock_bh(&conn->state_lock);
 
897
 
 
898
        wait_for_completion(&conn->conn_wait_comp);
 
899
        complete(&conn->conn_post_wait_comp);
 
900
}
 
901
 
 
902
void iscsit_fall_back_to_erl0(struct iscsi_session *sess)
 
903
{
 
904
        pr_debug("Falling back to ErrorRecoveryLevel=0 for SID:"
 
905
                        " %u\n", sess->sid);
 
906
 
 
907
        atomic_set(&sess->session_fall_back_to_erl0, 1);
 
908
}
 
909
 
 
910
static void iscsit_handle_connection_cleanup(struct iscsi_conn *conn)
 
911
{
 
912
        struct iscsi_session *sess = conn->sess;
 
913
 
 
914
        if ((sess->sess_ops->ErrorRecoveryLevel == 2) &&
 
915
            !atomic_read(&sess->session_reinstatement) &&
 
916
            !atomic_read(&sess->session_fall_back_to_erl0))
 
917
                iscsit_connection_recovery_transport_reset(conn);
 
918
        else {
 
919
                pr_debug("Performing cleanup for failed iSCSI"
 
920
                        " Connection ID: %hu from %s\n", conn->cid,
 
921
                        sess->sess_ops->InitiatorName);
 
922
                iscsit_close_connection(conn);
 
923
        }
 
924
}
 
925
 
 
926
extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
 
927
{
 
928
        spin_lock_bh(&conn->state_lock);
 
929
        if (atomic_read(&conn->connection_exit)) {
 
930
                spin_unlock_bh(&conn->state_lock);
 
931
                return;
 
932
        }
 
933
        atomic_set(&conn->connection_exit, 1);
 
934
 
 
935
        if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
 
936
                spin_unlock_bh(&conn->state_lock);
 
937
                iscsit_close_connection(conn);
 
938
                return;
 
939
        }
 
940
 
 
941
        if (conn->conn_state == TARG_CONN_STATE_CLEANUP_WAIT) {
 
942
                spin_unlock_bh(&conn->state_lock);
 
943
                return;
 
944
        }
 
945
 
 
946
        pr_debug("Moving to TARG_CONN_STATE_CLEANUP_WAIT.\n");
 
947
        conn->conn_state = TARG_CONN_STATE_CLEANUP_WAIT;
 
948
        spin_unlock_bh(&conn->state_lock);
 
949
 
 
950
        iscsit_handle_connection_cleanup(conn);
 
951
}
 
952
 
 
953
/*
 
954
 *      This is the simple function that makes the magic of
 
955
 *      sync and steering happen in the follow paradoxical order:
 
956
 *
 
957
 *      0) Receive conn->of_marker (bytes left until next OFMarker)
 
958
 *         bytes into an offload buffer.  When we pass the exact number
 
959
 *         of bytes in conn->of_marker, iscsit_dump_data_payload() and hence
 
960
 *         rx_data() will automatically receive the identical u32 marker
 
961
 *         values and store it in conn->of_marker_offset;
 
962
 *      1) Now conn->of_marker_offset will contain the offset to the start
 
963
 *         of the next iSCSI PDU.  Dump these remaining bytes into another
 
964
 *         offload buffer.
 
965
 *      2) We are done!
 
966
 *         Next byte in the TCP stream will contain the next iSCSI PDU!
 
967
 *         Cool Huh?!
 
968
 */
 
969
int iscsit_recover_from_unknown_opcode(struct iscsi_conn *conn)
 
970
{
 
971
        /*
 
972
         * Make sure the remaining bytes to next maker is a sane value.
 
973
         */
 
974
        if (conn->of_marker > (conn->conn_ops->OFMarkInt * 4)) {
 
975
                pr_err("Remaining bytes to OFMarker: %u exceeds"
 
976
                        " OFMarkInt bytes: %u.\n", conn->of_marker,
 
977
                                conn->conn_ops->OFMarkInt * 4);
 
978
                return -1;
 
979
        }
 
980
 
 
981
        pr_debug("Advancing %u bytes in TCP stream to get to the"
 
982
                        " next OFMarker.\n", conn->of_marker);
 
983
 
 
984
        if (iscsit_dump_data_payload(conn, conn->of_marker, 0) < 0)
 
985
                return -1;
 
986
 
 
987
        /*
 
988
         * Make sure the offset marker we retrived is a valid value.
 
989
         */
 
990
        if (conn->of_marker_offset > (ISCSI_HDR_LEN + (ISCSI_CRC_LEN * 2) +
 
991
            conn->conn_ops->MaxRecvDataSegmentLength)) {
 
992
                pr_err("OfMarker offset value: %u exceeds limit.\n",
 
993
                        conn->of_marker_offset);
 
994
                return -1;
 
995
        }
 
996
 
 
997
        pr_debug("Discarding %u bytes of TCP stream to get to the"
 
998
                        " next iSCSI Opcode.\n", conn->of_marker_offset);
 
999
 
 
1000
        if (iscsit_dump_data_payload(conn, conn->of_marker_offset, 0) < 0)
 
1001
                return -1;
 
1002
 
 
1003
        return 0;
 
1004
}