Commit e4f4e801 authored by Sagi Grimberg's avatar Sagi Grimberg Committed by Nicholas Bellinger

iscsi/iser-target: Support multi-sequence sendtargets text response

In case sendtargets response is larger than initiator MRDSL, we
send a partial sendtargets response (setting F=0, C=1, TTT!=0xffffffff),
accept a consecutive empty text message and send the rest of the payload.
In case we are done, we set F=1, C=0, TTT=0xffffffff.
We do that by storing the sendtargets response bytes done under
the session.

This patch also makes iscsit_find_cmd_from_itt public for isert.

(Re-add cmd->maxcmdsn_inc and clear in iscsit_build_text_rsp - nab)
Signed-off-by: default avatarSagi Grimberg <sagig@mellanox.com>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 11378cdb
...@@ -1436,9 +1436,15 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, ...@@ -1436,9 +1436,15 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr); ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr);
break; break;
case ISCSI_OP_TEXT: case ISCSI_OP_TEXT:
if (be32_to_cpu(hdr->ttt) != 0xFFFFFFFF) {
cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
if (!cmd)
break;
} else {
cmd = isert_allocate_cmd(conn); cmd = isert_allocate_cmd(conn);
if (!cmd) if (!cmd)
break; break;
}
isert_cmd = iscsit_priv_cmd(cmd); isert_cmd = iscsit_priv_cmd(cmd);
ret = isert_handle_text_cmd(isert_conn, isert_cmd, cmd, ret = isert_handle_text_cmd(isert_conn, isert_cmd, cmd,
...@@ -1660,6 +1666,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err) ...@@ -1660,6 +1666,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err)
struct isert_conn *isert_conn = isert_cmd->conn; struct isert_conn *isert_conn = isert_cmd->conn;
struct iscsi_conn *conn = isert_conn->conn; struct iscsi_conn *conn = isert_conn->conn;
struct isert_device *device = isert_conn->conn_device; struct isert_device *device = isert_conn->conn_device;
struct iscsi_text_rsp *hdr;
isert_dbg("Cmd %p\n", isert_cmd); isert_dbg("Cmd %p\n", isert_cmd);
...@@ -1700,6 +1707,11 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err) ...@@ -1700,6 +1707,11 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err)
case ISCSI_OP_REJECT: case ISCSI_OP_REJECT:
case ISCSI_OP_NOOP_OUT: case ISCSI_OP_NOOP_OUT:
case ISCSI_OP_TEXT: case ISCSI_OP_TEXT:
hdr = (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header;
/* If the continue bit is on, keep the command alive */
if (hdr->flags & ISCSI_FLAG_TEXT_CONTINUE)
break;
spin_lock_bh(&conn->cmd_lock); spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node)) if (!list_empty(&cmd->i_conn_node))
list_del_init(&cmd->i_conn_node); list_del_init(&cmd->i_conn_node);
......
...@@ -1994,6 +1994,7 @@ iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -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->cmd_sn = be32_to_cpu(hdr->cmdsn);
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn); cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->data_direction = DMA_NONE; cmd->data_direction = DMA_NONE;
cmd->text_in_ptr = NULL;
return 0; return 0;
} }
...@@ -2007,10 +2008,14 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -2007,10 +2008,14 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
int cmdsn_ret; int cmdsn_ret;
if (!text_in) { if (!text_in) {
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" pr_err("Unable to locate text_in buffer for sendtargets"
" discovery\n"); " discovery\n");
goto reject; goto reject;
} }
goto empty_sendtargets;
}
if (strncmp("SendTargets", text_in, 11) != 0) { if (strncmp("SendTargets", text_in, 11) != 0) {
pr_err("Received Text Data that is not" pr_err("Received Text Data that is not"
" SendTargets, cannot continue.\n"); " SendTargets, cannot continue.\n");
...@@ -2036,6 +2041,7 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -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); list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock); spin_unlock_bh(&conn->cmd_lock);
empty_sendtargets:
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
...@@ -3385,7 +3391,8 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np) ...@@ -3385,7 +3391,8 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np)
static int static int
iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, 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; char *payload = NULL;
struct iscsi_conn *conn = cmd->conn; struct iscsi_conn *conn = cmd->conn;
...@@ -3476,9 +3483,16 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, ...@@ -3476,9 +3483,16 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
end_of_buf = 1; end_of_buf = 1;
goto eob; goto eob;
} }
if (skip_bytes && len <= skip_bytes) {
skip_bytes -= len;
} else {
memcpy(payload + payload_len, buf, len); memcpy(payload + payload_len, buf, len);
payload_len += len; payload_len += len;
target_name_printed = 1; target_name_printed = 1;
if (len > skip_bytes)
skip_bytes = 0;
}
} }
len = sprintf(buf, "TargetAddress=" len = sprintf(buf, "TargetAddress="
...@@ -3494,15 +3508,24 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, ...@@ -3494,15 +3508,24 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
end_of_buf = 1; end_of_buf = 1;
goto eob; goto eob;
} }
if (skip_bytes && len <= skip_bytes) {
skip_bytes -= len;
} else {
memcpy(payload + payload_len, buf, len); memcpy(payload + payload_len, buf, len);
payload_len += len; payload_len += len;
if (len > skip_bytes)
skip_bytes = 0;
}
} }
spin_unlock(&tpg->tpg_np_lock); spin_unlock(&tpg->tpg_np_lock);
} }
spin_unlock(&tiqn->tiqn_tpg_lock); spin_unlock(&tiqn->tiqn_tpg_lock);
eob: eob:
if (end_of_buf) if (end_of_buf) {
*completed = false;
break; break;
}
if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE)
break; break;
...@@ -3520,13 +3543,23 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, ...@@ -3520,13 +3543,23 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
enum iscsit_transport_type network_transport) enum iscsit_transport_type network_transport)
{ {
int text_length, padding; 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) if (text_length < 0)
return text_length; return text_length;
hdr->opcode = ISCSI_OP_TEXT_RSP; if (completed) {
hdr->flags |= ISCSI_FLAG_CMD_FINAL; 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;
padding = ((-text_length) & 3); padding = ((-text_length) & 3);
hton24(hdr->dlength, text_length); hton24(hdr->dlength, text_length);
hdr->itt = cmd->init_task_tag; hdr->itt = cmd->init_task_tag;
...@@ -3535,21 +3568,25 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, ...@@ -3535,21 +3568,25 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
hdr->statsn = cpu_to_be32(cmd->stat_sn); hdr->statsn = cpu_to_be32(cmd->stat_sn);
iscsit_increment_maxcmdsn(cmd, conn->sess); 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->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x," pr_debug("Built Text Response: ITT: 0x%08x, TTT: 0x%08x, StatSN: 0x%08x,"
" Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn, " Length: %u, CID: %hu F: %d C: %d\n", cmd->init_task_tag,
text_length, conn->cid); 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; return text_length + padding;
} }
EXPORT_SYMBOL(iscsit_build_text_rsp); 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( static int iscsit_send_text_rsp(
struct iscsi_cmd *cmd, struct iscsi_cmd *cmd,
struct iscsi_conn *conn) struct iscsi_conn *conn)
...@@ -4013,9 +4050,15 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf) ...@@ -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); ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
break; break;
case ISCSI_OP_TEXT: case ISCSI_OP_TEXT:
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); cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
if (!cmd) if (!cmd)
goto reject; goto reject;
}
ret = iscsit_handle_text_cmd(conn, cmd, buf); ret = iscsit_handle_text_cmd(conn, cmd, buf);
break; break;
......
...@@ -390,6 +390,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt( ...@@ -390,6 +390,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt(
init_task_tag, conn->cid); init_task_tag, conn->cid);
return NULL; return NULL;
} }
EXPORT_SYMBOL(iscsit_find_cmd_from_itt);
struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump( struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
struct iscsi_conn *conn, struct iscsi_conn *conn,
......
...@@ -16,7 +16,6 @@ extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32); ...@@ -16,7 +16,6 @@ extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
unsigned char * ,__be32 cmdsn); unsigned char * ,__be32 cmdsn);
extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *); extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);
extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *, extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
itt_t, u32); itt_t, u32);
extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32); extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32);
......
...@@ -893,4 +893,5 @@ static inline u32 session_get_next_ttt(struct iscsi_session *session) ...@@ -893,4 +893,5 @@ static inline u32 session_get_next_ttt(struct iscsi_session *session)
return ttt; return ttt;
} }
extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
#endif /* ISCSI_TARGET_CORE_H */ #endif /* ISCSI_TARGET_CORE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment