|
@@ -1994,6 +1994,7 @@ iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
|
|
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
|
|
|
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
|
|
|
cmd->data_direction = DMA_NONE;
|
|
|
+ cmd->text_in_ptr = NULL;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -2007,9 +2008,13 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
|
|
int cmdsn_ret;
|
|
|
|
|
|
if (!text_in) {
|
|
|
- pr_err("Unable to locate text_in buffer for sendtargets"
|
|
|
- " discovery\n");
|
|
|
- goto reject;
|
|
|
+ cmd->targ_xfer_tag = be32_to_cpu(hdr->ttt);
|
|
|
+ if (cmd->targ_xfer_tag == 0xFFFFFFFF) {
|
|
|
+ pr_err("Unable to locate text_in buffer for sendtargets"
|
|
|
+ " discovery\n");
|
|
|
+ goto reject;
|
|
|
+ }
|
|
|
+ goto empty_sendtargets;
|
|
|
}
|
|
|
if (strncmp("SendTargets", text_in, 11) != 0) {
|
|
|
pr_err("Received Text Data that is not"
|
|
@@ -2036,6 +2041,7 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
|
|
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
|
|
|
spin_unlock_bh(&conn->cmd_lock);
|
|
|
|
|
|
+empty_sendtargets:
|
|
|
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
|
|
|
|
|
|
if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
|
|
@@ -3385,7 +3391,8 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np)
|
|
|
|
|
|
static int
|
|
|
iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
|
|
|
- enum iscsit_transport_type network_transport)
|
|
|
+ enum iscsit_transport_type network_transport,
|
|
|
+ int skip_bytes, bool *completed)
|
|
|
{
|
|
|
char *payload = NULL;
|
|
|
struct iscsi_conn *conn = cmd->conn;
|
|
@@ -3476,9 +3483,16 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
|
|
|
end_of_buf = 1;
|
|
|
goto eob;
|
|
|
}
|
|
|
- memcpy(payload + payload_len, buf, len);
|
|
|
- payload_len += len;
|
|
|
- target_name_printed = 1;
|
|
|
+
|
|
|
+ if (skip_bytes && len <= skip_bytes) {
|
|
|
+ skip_bytes -= len;
|
|
|
+ } else {
|
|
|
+ memcpy(payload + payload_len, buf, len);
|
|
|
+ payload_len += len;
|
|
|
+ target_name_printed = 1;
|
|
|
+ if (len > skip_bytes)
|
|
|
+ skip_bytes = 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
len = sprintf(buf, "TargetAddress="
|
|
@@ -3494,15 +3508,24 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
|
|
|
end_of_buf = 1;
|
|
|
goto eob;
|
|
|
}
|
|
|
- memcpy(payload + payload_len, buf, len);
|
|
|
- payload_len += len;
|
|
|
+
|
|
|
+ if (skip_bytes && len <= skip_bytes) {
|
|
|
+ skip_bytes -= len;
|
|
|
+ } else {
|
|
|
+ memcpy(payload + payload_len, buf, len);
|
|
|
+ payload_len += len;
|
|
|
+ if (len > skip_bytes)
|
|
|
+ skip_bytes = 0;
|
|
|
+ }
|
|
|
}
|
|
|
spin_unlock(&tpg->tpg_np_lock);
|
|
|
}
|
|
|
spin_unlock(&tiqn->tiqn_tpg_lock);
|
|
|
eob:
|
|
|
- if (end_of_buf)
|
|
|
+ if (end_of_buf) {
|
|
|
+ *completed = false;
|
|
|
break;
|
|
|
+ }
|
|
|
|
|
|
if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE)
|
|
|
break;
|
|
@@ -3520,13 +3543,23 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
|
|
|
enum iscsit_transport_type network_transport)
|
|
|
{
|
|
|
int text_length, padding;
|
|
|
+ bool completed = true;
|
|
|
|
|
|
- text_length = iscsit_build_sendtargets_response(cmd, network_transport);
|
|
|
+ text_length = iscsit_build_sendtargets_response(cmd, network_transport,
|
|
|
+ cmd->read_data_done,
|
|
|
+ &completed);
|
|
|
if (text_length < 0)
|
|
|
return text_length;
|
|
|
|
|
|
+ if (completed) {
|
|
|
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
|
|
|
+ } else {
|
|
|
+ hdr->flags |= ISCSI_FLAG_TEXT_CONTINUE;
|
|
|
+ cmd->read_data_done += text_length;
|
|
|
+ if (cmd->targ_xfer_tag == 0xFFFFFFFF)
|
|
|
+ cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
|
|
|
+ }
|
|
|
hdr->opcode = ISCSI_OP_TEXT_RSP;
|
|
|
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
|
|
|
padding = ((-text_length) & 3);
|
|
|
hton24(hdr->dlength, text_length);
|
|
|
hdr->itt = cmd->init_task_tag;
|
|
@@ -3535,21 +3568,25 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
|
|
|
hdr->statsn = cpu_to_be32(cmd->stat_sn);
|
|
|
|
|
|
iscsit_increment_maxcmdsn(cmd, conn->sess);
|
|
|
+ /*
|
|
|
+ * Reset maxcmdsn_inc in multi-part text payload exchanges to
|
|
|
+ * correctly increment MaxCmdSN for each response answering a
|
|
|
+ * non immediate text request with a valid CmdSN.
|
|
|
+ */
|
|
|
+ cmd->maxcmdsn_inc = 0;
|
|
|
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
|
|
|
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
|
|
|
|
|
|
- pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x,"
|
|
|
- " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn,
|
|
|
- text_length, conn->cid);
|
|
|
+ pr_debug("Built Text Response: ITT: 0x%08x, TTT: 0x%08x, StatSN: 0x%08x,"
|
|
|
+ " Length: %u, CID: %hu F: %d C: %d\n", cmd->init_task_tag,
|
|
|
+ cmd->targ_xfer_tag, cmd->stat_sn, text_length, conn->cid,
|
|
|
+ !!(hdr->flags & ISCSI_FLAG_CMD_FINAL),
|
|
|
+ !!(hdr->flags & ISCSI_FLAG_TEXT_CONTINUE));
|
|
|
|
|
|
return text_length + padding;
|
|
|
}
|
|
|
EXPORT_SYMBOL(iscsit_build_text_rsp);
|
|
|
|
|
|
-/*
|
|
|
- * FIXME: Add support for F_BIT and C_BIT when the length is longer than
|
|
|
- * MaxRecvDataSegmentLength.
|
|
|
- */
|
|
|
static int iscsit_send_text_rsp(
|
|
|
struct iscsi_cmd *cmd,
|
|
|
struct iscsi_conn *conn)
|
|
@@ -4013,9 +4050,15 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
|
|
|
ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
|
|
|
break;
|
|
|
case ISCSI_OP_TEXT:
|
|
|
- cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
|
|
|
- if (!cmd)
|
|
|
- goto reject;
|
|
|
+ if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
|
|
|
+ cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
|
|
|
+ if (!cmd)
|
|
|
+ goto reject;
|
|
|
+ } else {
|
|
|
+ cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
|
|
|
+ if (!cmd)
|
|
|
+ goto reject;
|
|
|
+ }
|
|
|
|
|
|
ret = iscsit_handle_text_cmd(conn, cmd, buf);
|
|
|
break;
|