mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
![Thomas Gleixner](/assets/img/avatar_default.png)
Based on 3 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [graeme] [gregory] [gg]@[slimlogic] [co] [uk] [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] [based] [on] [twl6030]_[usb] [c] [author] [hema] [hk] [hemahk]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 1105 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Richard Fontana <rfontana@redhat.com> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070033.202006027@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
690 lines
17 KiB
C
690 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*******************************************************************************
|
|
* This file contains main functions related to iSCSI DataSequenceInOrder=No
|
|
* and DataPDUInOrder=No.
|
|
*
|
|
* (c) Copyright 2007-2013 Datera, Inc.
|
|
*
|
|
* Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include <linux/slab.h>
|
|
#include <linux/random.h>
|
|
|
|
#include <target/iscsi/iscsi_target_core.h>
|
|
#include "iscsi_target_util.h"
|
|
#include "iscsi_target_tpg.h"
|
|
#include "iscsi_target_seq_pdu_list.h"
|
|
|
|
#ifdef DEBUG
|
|
static void iscsit_dump_seq_list(struct iscsi_cmd *cmd)
|
|
{
|
|
int i;
|
|
struct iscsi_seq *seq;
|
|
|
|
pr_debug("Dumping Sequence List for ITT: 0x%08x:\n",
|
|
cmd->init_task_tag);
|
|
|
|
for (i = 0; i < cmd->seq_count; i++) {
|
|
seq = &cmd->seq_list[i];
|
|
pr_debug("i: %d, pdu_start: %d, pdu_count: %d,"
|
|
" offset: %d, xfer_len: %d, seq_send_order: %d,"
|
|
" seq_no: %d\n", i, seq->pdu_start, seq->pdu_count,
|
|
seq->offset, seq->xfer_len, seq->seq_send_order,
|
|
seq->seq_no);
|
|
}
|
|
}
|
|
|
|
static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd)
|
|
{
|
|
int i;
|
|
struct iscsi_pdu *pdu;
|
|
|
|
pr_debug("Dumping PDU List for ITT: 0x%08x:\n",
|
|
cmd->init_task_tag);
|
|
|
|
for (i = 0; i < cmd->pdu_count; i++) {
|
|
pdu = &cmd->pdu_list[i];
|
|
pr_debug("i: %d, offset: %d, length: %d,"
|
|
" pdu_send_order: %d, seq_no: %d\n", i, pdu->offset,
|
|
pdu->length, pdu->pdu_send_order, pdu->seq_no);
|
|
}
|
|
}
|
|
#else
|
|
static void iscsit_dump_seq_list(struct iscsi_cmd *cmd) {}
|
|
static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) {}
|
|
#endif
|
|
|
|
static void iscsit_ordered_seq_lists(
|
|
struct iscsi_cmd *cmd,
|
|
u8 type)
|
|
{
|
|
u32 i, seq_count = 0;
|
|
|
|
for (i = 0; i < cmd->seq_count; i++) {
|
|
if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
|
|
continue;
|
|
cmd->seq_list[i].seq_send_order = seq_count++;
|
|
}
|
|
}
|
|
|
|
static void iscsit_ordered_pdu_lists(
|
|
struct iscsi_cmd *cmd,
|
|
u8 type)
|
|
{
|
|
u32 i, pdu_send_order = 0, seq_no = 0;
|
|
|
|
for (i = 0; i < cmd->pdu_count; i++) {
|
|
redo:
|
|
if (cmd->pdu_list[i].seq_no == seq_no) {
|
|
cmd->pdu_list[i].pdu_send_order = pdu_send_order++;
|
|
continue;
|
|
}
|
|
seq_no++;
|
|
pdu_send_order = 0;
|
|
goto redo;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Generate count random values into array.
|
|
* Use 0x80000000 to mark generates valued in array[].
|
|
*/
|
|
static void iscsit_create_random_array(u32 *array, u32 count)
|
|
{
|
|
int i, j, k;
|
|
|
|
if (count == 1) {
|
|
array[0] = 0;
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
redo:
|
|
get_random_bytes(&j, sizeof(u32));
|
|
j = (1 + (int) (9999 + 1) - j) % count;
|
|
for (k = 0; k < i + 1; k++) {
|
|
j |= 0x80000000;
|
|
if ((array[k] & 0x80000000) && (array[k] == j))
|
|
goto redo;
|
|
}
|
|
array[i] = j;
|
|
}
|
|
|
|
for (i = 0; i < count; i++)
|
|
array[i] &= ~0x80000000;
|
|
}
|
|
|
|
static int iscsit_randomize_pdu_lists(
|
|
struct iscsi_cmd *cmd,
|
|
u8 type)
|
|
{
|
|
int i = 0;
|
|
u32 *array, pdu_count, seq_count = 0, seq_no = 0, seq_offset = 0;
|
|
|
|
for (pdu_count = 0; pdu_count < cmd->pdu_count; pdu_count++) {
|
|
redo:
|
|
if (cmd->pdu_list[pdu_count].seq_no == seq_no) {
|
|
seq_count++;
|
|
continue;
|
|
}
|
|
array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
|
|
if (!array) {
|
|
pr_err("Unable to allocate memory"
|
|
" for random array.\n");
|
|
return -ENOMEM;
|
|
}
|
|
iscsit_create_random_array(array, seq_count);
|
|
|
|
for (i = 0; i < seq_count; i++)
|
|
cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
|
|
|
|
kfree(array);
|
|
|
|
seq_offset += seq_count;
|
|
seq_count = 0;
|
|
seq_no++;
|
|
goto redo;
|
|
}
|
|
|
|
if (seq_count) {
|
|
array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
|
|
if (!array) {
|
|
pr_err("Unable to allocate memory for"
|
|
" random array.\n");
|
|
return -ENOMEM;
|
|
}
|
|
iscsit_create_random_array(array, seq_count);
|
|
|
|
for (i = 0; i < seq_count; i++)
|
|
cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
|
|
|
|
kfree(array);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int iscsit_randomize_seq_lists(
|
|
struct iscsi_cmd *cmd,
|
|
u8 type)
|
|
{
|
|
int i, j = 0;
|
|
u32 *array, seq_count = cmd->seq_count;
|
|
|
|
if ((type == PDULIST_IMMEDIATE) || (type == PDULIST_UNSOLICITED))
|
|
seq_count--;
|
|
else if (type == PDULIST_IMMEDIATE_AND_UNSOLICITED)
|
|
seq_count -= 2;
|
|
|
|
if (!seq_count)
|
|
return 0;
|
|
|
|
array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
|
|
if (!array) {
|
|
pr_err("Unable to allocate memory for random array.\n");
|
|
return -ENOMEM;
|
|
}
|
|
iscsit_create_random_array(array, seq_count);
|
|
|
|
for (i = 0; i < cmd->seq_count; i++) {
|
|
if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
|
|
continue;
|
|
cmd->seq_list[i].seq_send_order = array[j++];
|
|
}
|
|
|
|
kfree(array);
|
|
return 0;
|
|
}
|
|
|
|
static void iscsit_determine_counts_for_list(
|
|
struct iscsi_cmd *cmd,
|
|
struct iscsi_build_list *bl,
|
|
u32 *seq_count,
|
|
u32 *pdu_count)
|
|
{
|
|
int check_immediate = 0;
|
|
u32 burstlength = 0, offset = 0;
|
|
u32 unsolicited_data_length = 0;
|
|
u32 mdsl;
|
|
struct iscsi_conn *conn = cmd->conn;
|
|
|
|
if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
|
|
mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
|
|
else
|
|
mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
|
|
|
|
if ((bl->type == PDULIST_IMMEDIATE) ||
|
|
(bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
|
|
check_immediate = 1;
|
|
|
|
if ((bl->type == PDULIST_UNSOLICITED) ||
|
|
(bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
|
|
unsolicited_data_length = min(cmd->se_cmd.data_length,
|
|
conn->sess->sess_ops->FirstBurstLength);
|
|
|
|
while (offset < cmd->se_cmd.data_length) {
|
|
*pdu_count += 1;
|
|
|
|
if (check_immediate) {
|
|
check_immediate = 0;
|
|
offset += bl->immediate_data_length;
|
|
*seq_count += 1;
|
|
if (unsolicited_data_length)
|
|
unsolicited_data_length -=
|
|
bl->immediate_data_length;
|
|
continue;
|
|
}
|
|
if (unsolicited_data_length > 0) {
|
|
if ((offset + mdsl) >= cmd->se_cmd.data_length) {
|
|
unsolicited_data_length -=
|
|
(cmd->se_cmd.data_length - offset);
|
|
offset += (cmd->se_cmd.data_length - offset);
|
|
continue;
|
|
}
|
|
if ((offset + mdsl)
|
|
>= conn->sess->sess_ops->FirstBurstLength) {
|
|
unsolicited_data_length -=
|
|
(conn->sess->sess_ops->FirstBurstLength -
|
|
offset);
|
|
offset += (conn->sess->sess_ops->FirstBurstLength -
|
|
offset);
|
|
burstlength = 0;
|
|
*seq_count += 1;
|
|
continue;
|
|
}
|
|
|
|
offset += mdsl;
|
|
unsolicited_data_length -= mdsl;
|
|
continue;
|
|
}
|
|
if ((offset + mdsl) >= cmd->se_cmd.data_length) {
|
|
offset += (cmd->se_cmd.data_length - offset);
|
|
continue;
|
|
}
|
|
if ((burstlength + mdsl) >=
|
|
conn->sess->sess_ops->MaxBurstLength) {
|
|
offset += (conn->sess->sess_ops->MaxBurstLength -
|
|
burstlength);
|
|
burstlength = 0;
|
|
*seq_count += 1;
|
|
continue;
|
|
}
|
|
|
|
burstlength += mdsl;
|
|
offset += mdsl;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
|
|
* or DataPDUInOrder=No.
|
|
*/
|
|
static int iscsit_do_build_pdu_and_seq_lists(
|
|
struct iscsi_cmd *cmd,
|
|
struct iscsi_build_list *bl)
|
|
{
|
|
int check_immediate = 0, datapduinorder, datasequenceinorder;
|
|
u32 burstlength = 0, offset = 0, i = 0, mdsl;
|
|
u32 pdu_count = 0, seq_no = 0, unsolicited_data_length = 0;
|
|
struct iscsi_conn *conn = cmd->conn;
|
|
struct iscsi_pdu *pdu = cmd->pdu_list;
|
|
struct iscsi_seq *seq = cmd->seq_list;
|
|
|
|
if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
|
|
mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
|
|
else
|
|
mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
|
|
|
|
datapduinorder = conn->sess->sess_ops->DataPDUInOrder;
|
|
datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder;
|
|
|
|
if ((bl->type == PDULIST_IMMEDIATE) ||
|
|
(bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
|
|
check_immediate = 1;
|
|
|
|
if ((bl->type == PDULIST_UNSOLICITED) ||
|
|
(bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
|
|
unsolicited_data_length = min(cmd->se_cmd.data_length,
|
|
conn->sess->sess_ops->FirstBurstLength);
|
|
|
|
while (offset < cmd->se_cmd.data_length) {
|
|
pdu_count++;
|
|
if (!datapduinorder) {
|
|
pdu[i].offset = offset;
|
|
pdu[i].seq_no = seq_no;
|
|
}
|
|
if (!datasequenceinorder && (pdu_count == 1)) {
|
|
seq[seq_no].pdu_start = i;
|
|
seq[seq_no].seq_no = seq_no;
|
|
seq[seq_no].offset = offset;
|
|
seq[seq_no].orig_offset = offset;
|
|
}
|
|
|
|
if (check_immediate) {
|
|
check_immediate = 0;
|
|
if (!datapduinorder) {
|
|
pdu[i].type = PDUTYPE_IMMEDIATE;
|
|
pdu[i++].length = bl->immediate_data_length;
|
|
}
|
|
if (!datasequenceinorder) {
|
|
seq[seq_no].type = SEQTYPE_IMMEDIATE;
|
|
seq[seq_no].pdu_count = 1;
|
|
seq[seq_no].xfer_len =
|
|
bl->immediate_data_length;
|
|
}
|
|
offset += bl->immediate_data_length;
|
|
pdu_count = 0;
|
|
seq_no++;
|
|
if (unsolicited_data_length)
|
|
unsolicited_data_length -=
|
|
bl->immediate_data_length;
|
|
continue;
|
|
}
|
|
if (unsolicited_data_length > 0) {
|
|
if ((offset + mdsl) >= cmd->se_cmd.data_length) {
|
|
if (!datapduinorder) {
|
|
pdu[i].type = PDUTYPE_UNSOLICITED;
|
|
pdu[i].length =
|
|
(cmd->se_cmd.data_length - offset);
|
|
}
|
|
if (!datasequenceinorder) {
|
|
seq[seq_no].type = SEQTYPE_UNSOLICITED;
|
|
seq[seq_no].pdu_count = pdu_count;
|
|
seq[seq_no].xfer_len = (burstlength +
|
|
(cmd->se_cmd.data_length - offset));
|
|
}
|
|
unsolicited_data_length -=
|
|
(cmd->se_cmd.data_length - offset);
|
|
offset += (cmd->se_cmd.data_length - offset);
|
|
continue;
|
|
}
|
|
if ((offset + mdsl) >=
|
|
conn->sess->sess_ops->FirstBurstLength) {
|
|
if (!datapduinorder) {
|
|
pdu[i].type = PDUTYPE_UNSOLICITED;
|
|
pdu[i++].length =
|
|
(conn->sess->sess_ops->FirstBurstLength -
|
|
offset);
|
|
}
|
|
if (!datasequenceinorder) {
|
|
seq[seq_no].type = SEQTYPE_UNSOLICITED;
|
|
seq[seq_no].pdu_count = pdu_count;
|
|
seq[seq_no].xfer_len = (burstlength +
|
|
(conn->sess->sess_ops->FirstBurstLength -
|
|
offset));
|
|
}
|
|
unsolicited_data_length -=
|
|
(conn->sess->sess_ops->FirstBurstLength -
|
|
offset);
|
|
offset += (conn->sess->sess_ops->FirstBurstLength -
|
|
offset);
|
|
burstlength = 0;
|
|
pdu_count = 0;
|
|
seq_no++;
|
|
continue;
|
|
}
|
|
|
|
if (!datapduinorder) {
|
|
pdu[i].type = PDUTYPE_UNSOLICITED;
|
|
pdu[i++].length = mdsl;
|
|
}
|
|
burstlength += mdsl;
|
|
offset += mdsl;
|
|
unsolicited_data_length -= mdsl;
|
|
continue;
|
|
}
|
|
if ((offset + mdsl) >= cmd->se_cmd.data_length) {
|
|
if (!datapduinorder) {
|
|
pdu[i].type = PDUTYPE_NORMAL;
|
|
pdu[i].length = (cmd->se_cmd.data_length - offset);
|
|
}
|
|
if (!datasequenceinorder) {
|
|
seq[seq_no].type = SEQTYPE_NORMAL;
|
|
seq[seq_no].pdu_count = pdu_count;
|
|
seq[seq_no].xfer_len = (burstlength +
|
|
(cmd->se_cmd.data_length - offset));
|
|
}
|
|
offset += (cmd->se_cmd.data_length - offset);
|
|
continue;
|
|
}
|
|
if ((burstlength + mdsl) >=
|
|
conn->sess->sess_ops->MaxBurstLength) {
|
|
if (!datapduinorder) {
|
|
pdu[i].type = PDUTYPE_NORMAL;
|
|
pdu[i++].length =
|
|
(conn->sess->sess_ops->MaxBurstLength -
|
|
burstlength);
|
|
}
|
|
if (!datasequenceinorder) {
|
|
seq[seq_no].type = SEQTYPE_NORMAL;
|
|
seq[seq_no].pdu_count = pdu_count;
|
|
seq[seq_no].xfer_len = (burstlength +
|
|
(conn->sess->sess_ops->MaxBurstLength -
|
|
burstlength));
|
|
}
|
|
offset += (conn->sess->sess_ops->MaxBurstLength -
|
|
burstlength);
|
|
burstlength = 0;
|
|
pdu_count = 0;
|
|
seq_no++;
|
|
continue;
|
|
}
|
|
|
|
if (!datapduinorder) {
|
|
pdu[i].type = PDUTYPE_NORMAL;
|
|
pdu[i++].length = mdsl;
|
|
}
|
|
burstlength += mdsl;
|
|
offset += mdsl;
|
|
}
|
|
|
|
if (!datasequenceinorder) {
|
|
if (bl->data_direction & ISCSI_PDU_WRITE) {
|
|
if (bl->randomize & RANDOM_R2T_OFFSETS) {
|
|
if (iscsit_randomize_seq_lists(cmd, bl->type)
|
|
< 0)
|
|
return -1;
|
|
} else
|
|
iscsit_ordered_seq_lists(cmd, bl->type);
|
|
} else if (bl->data_direction & ISCSI_PDU_READ) {
|
|
if (bl->randomize & RANDOM_DATAIN_SEQ_OFFSETS) {
|
|
if (iscsit_randomize_seq_lists(cmd, bl->type)
|
|
< 0)
|
|
return -1;
|
|
} else
|
|
iscsit_ordered_seq_lists(cmd, bl->type);
|
|
}
|
|
|
|
iscsit_dump_seq_list(cmd);
|
|
}
|
|
if (!datapduinorder) {
|
|
if (bl->data_direction & ISCSI_PDU_WRITE) {
|
|
if (bl->randomize & RANDOM_DATAOUT_PDU_OFFSETS) {
|
|
if (iscsit_randomize_pdu_lists(cmd, bl->type)
|
|
< 0)
|
|
return -1;
|
|
} else
|
|
iscsit_ordered_pdu_lists(cmd, bl->type);
|
|
} else if (bl->data_direction & ISCSI_PDU_READ) {
|
|
if (bl->randomize & RANDOM_DATAIN_PDU_OFFSETS) {
|
|
if (iscsit_randomize_pdu_lists(cmd, bl->type)
|
|
< 0)
|
|
return -1;
|
|
} else
|
|
iscsit_ordered_pdu_lists(cmd, bl->type);
|
|
}
|
|
|
|
iscsit_dump_pdu_list(cmd);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int iscsit_build_pdu_and_seq_lists(
|
|
struct iscsi_cmd *cmd,
|
|
u32 immediate_data_length)
|
|
{
|
|
struct iscsi_build_list bl;
|
|
u32 pdu_count = 0, seq_count = 1;
|
|
struct iscsi_conn *conn = cmd->conn;
|
|
struct iscsi_pdu *pdu = NULL;
|
|
struct iscsi_seq *seq = NULL;
|
|
|
|
struct iscsi_session *sess = conn->sess;
|
|
struct iscsi_node_attrib *na;
|
|
|
|
/*
|
|
* Do nothing if no OOO shenanigans
|
|
*/
|
|
if (sess->sess_ops->DataSequenceInOrder &&
|
|
sess->sess_ops->DataPDUInOrder)
|
|
return 0;
|
|
|
|
if (cmd->data_direction == DMA_NONE)
|
|
return 0;
|
|
|
|
na = iscsit_tpg_get_node_attrib(sess);
|
|
memset(&bl, 0, sizeof(struct iscsi_build_list));
|
|
|
|
if (cmd->data_direction == DMA_FROM_DEVICE) {
|
|
bl.data_direction = ISCSI_PDU_READ;
|
|
bl.type = PDULIST_NORMAL;
|
|
if (na->random_datain_pdu_offsets)
|
|
bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS;
|
|
if (na->random_datain_seq_offsets)
|
|
bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS;
|
|
} else {
|
|
bl.data_direction = ISCSI_PDU_WRITE;
|
|
bl.immediate_data_length = immediate_data_length;
|
|
if (na->random_r2t_offsets)
|
|
bl.randomize |= RANDOM_R2T_OFFSETS;
|
|
|
|
if (!cmd->immediate_data && !cmd->unsolicited_data)
|
|
bl.type = PDULIST_NORMAL;
|
|
else if (cmd->immediate_data && !cmd->unsolicited_data)
|
|
bl.type = PDULIST_IMMEDIATE;
|
|
else if (!cmd->immediate_data && cmd->unsolicited_data)
|
|
bl.type = PDULIST_UNSOLICITED;
|
|
else if (cmd->immediate_data && cmd->unsolicited_data)
|
|
bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED;
|
|
}
|
|
|
|
iscsit_determine_counts_for_list(cmd, &bl, &seq_count, &pdu_count);
|
|
|
|
if (!conn->sess->sess_ops->DataSequenceInOrder) {
|
|
seq = kcalloc(seq_count, sizeof(struct iscsi_seq), GFP_ATOMIC);
|
|
if (!seq) {
|
|
pr_err("Unable to allocate struct iscsi_seq list\n");
|
|
return -ENOMEM;
|
|
}
|
|
cmd->seq_list = seq;
|
|
cmd->seq_count = seq_count;
|
|
}
|
|
|
|
if (!conn->sess->sess_ops->DataPDUInOrder) {
|
|
pdu = kcalloc(pdu_count, sizeof(struct iscsi_pdu), GFP_ATOMIC);
|
|
if (!pdu) {
|
|
pr_err("Unable to allocate struct iscsi_pdu list.\n");
|
|
kfree(seq);
|
|
return -ENOMEM;
|
|
}
|
|
cmd->pdu_list = pdu;
|
|
cmd->pdu_count = pdu_count;
|
|
}
|
|
|
|
return iscsit_do_build_pdu_and_seq_lists(cmd, &bl);
|
|
}
|
|
|
|
struct iscsi_pdu *iscsit_get_pdu_holder(
|
|
struct iscsi_cmd *cmd,
|
|
u32 offset,
|
|
u32 length)
|
|
{
|
|
u32 i;
|
|
struct iscsi_pdu *pdu = NULL;
|
|
|
|
if (!cmd->pdu_list) {
|
|
pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
|
|
return NULL;
|
|
}
|
|
|
|
pdu = &cmd->pdu_list[0];
|
|
|
|
for (i = 0; i < cmd->pdu_count; i++)
|
|
if ((pdu[i].offset == offset) && (pdu[i].length == length))
|
|
return &pdu[i];
|
|
|
|
pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
|
|
" %u, Length: %u\n", cmd->init_task_tag, offset, length);
|
|
return NULL;
|
|
}
|
|
|
|
struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(
|
|
struct iscsi_cmd *cmd,
|
|
struct iscsi_seq *seq)
|
|
{
|
|
u32 i;
|
|
struct iscsi_conn *conn = cmd->conn;
|
|
struct iscsi_pdu *pdu = NULL;
|
|
|
|
if (!cmd->pdu_list) {
|
|
pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (conn->sess->sess_ops->DataSequenceInOrder) {
|
|
redo:
|
|
pdu = &cmd->pdu_list[cmd->pdu_start];
|
|
|
|
for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) {
|
|
pr_debug("pdu[i].seq_no: %d, pdu[i].pdu"
|
|
"_send_order: %d, pdu[i].offset: %d,"
|
|
" pdu[i].length: %d\n", pdu[i].seq_no,
|
|
pdu[i].pdu_send_order, pdu[i].offset,
|
|
pdu[i].length);
|
|
|
|
if (pdu[i].pdu_send_order == cmd->pdu_send_order) {
|
|
cmd->pdu_send_order++;
|
|
return &pdu[i];
|
|
}
|
|
}
|
|
|
|
cmd->pdu_start += cmd->pdu_send_order;
|
|
cmd->pdu_send_order = 0;
|
|
cmd->seq_no++;
|
|
|
|
if (cmd->pdu_start < cmd->pdu_count)
|
|
goto redo;
|
|
|
|
pr_err("Command ITT: 0x%08x unable to locate"
|
|
" struct iscsi_pdu for cmd->pdu_send_order: %u.\n",
|
|
cmd->init_task_tag, cmd->pdu_send_order);
|
|
return NULL;
|
|
} else {
|
|
if (!seq) {
|
|
pr_err("struct iscsi_seq is NULL!\n");
|
|
return NULL;
|
|
}
|
|
|
|
pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
|
|
" seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count,
|
|
seq->seq_no);
|
|
|
|
pdu = &cmd->pdu_list[seq->pdu_start];
|
|
|
|
if (seq->pdu_send_order == seq->pdu_count) {
|
|
pr_err("Command ITT: 0x%08x seq->pdu_send"
|
|
"_order: %u equals seq->pdu_count: %u\n",
|
|
cmd->init_task_tag, seq->pdu_send_order,
|
|
seq->pdu_count);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < seq->pdu_count; i++) {
|
|
if (pdu[i].pdu_send_order == seq->pdu_send_order) {
|
|
seq->pdu_send_order++;
|
|
return &pdu[i];
|
|
}
|
|
}
|
|
|
|
pr_err("Command ITT: 0x%08x unable to locate iscsi"
|
|
"_pdu_t for seq->pdu_send_order: %u.\n",
|
|
cmd->init_task_tag, seq->pdu_send_order);
|
|
return NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct iscsi_seq *iscsit_get_seq_holder(
|
|
struct iscsi_cmd *cmd,
|
|
u32 offset,
|
|
u32 length)
|
|
{
|
|
u32 i;
|
|
|
|
if (!cmd->seq_list) {
|
|
pr_err("struct iscsi_cmd->seq_list is NULL!\n");
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < cmd->seq_count; i++) {
|
|
pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
|
|
"xfer_len: %d, seq_list[i].seq_no %u\n",
|
|
cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len,
|
|
cmd->seq_list[i].seq_no);
|
|
|
|
if ((cmd->seq_list[i].orig_offset +
|
|
cmd->seq_list[i].xfer_len) >=
|
|
(offset + length))
|
|
return &cmd->seq_list[i];
|
|
}
|
|
|
|
pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
|
|
" Offset: %u, Length: %u\n", cmd->init_task_tag, offset,
|
|
length);
|
|
return NULL;
|
|
}
|