Commit 778de368 authored by Nicholas Bellinger's avatar Nicholas Bellinger

iscsi/isert-target: Refactor ISCSI_OP_NOOP RX handling

This patch refactors ISCSI_OP_NOOP handling within iscsi-target in
order to handle iscsi_nopout payloads in a transport specific manner.

This includes splitting existing iscsit_handle_nop_out() into
iscsit_setup_nop_out() and iscsit_process_nop_out() calls, and
makes iscsit_handle_nop_out() be only used internally by traditional
iscsi socket calls.

Next update iser-target code to use new callers and add FIXME for
the handling iscsi_nopout payloads.  Also fix reject response handling
in iscsit_setup_nop_out() to use proper iscsit_add_reject_from_cmd().

v2: Fix uninitialized iscsit_handle_nop_out() payload_length usage (Fengguang)
v3: Remove left-over dead code in iscsit_setup_nop_out() (DanC)
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 08234e3a
...@@ -1000,6 +1000,25 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn, ...@@ -1000,6 +1000,25 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
return 0; return 0;
} }
static int
isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
struct iser_rx_desc *rx_desc, unsigned char *buf)
{
struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
struct iscsi_conn *conn = isert_conn->conn;
struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
int rc;
rc = iscsit_setup_nop_out(conn, cmd, hdr);
if (rc < 0)
return rc;
/*
* FIXME: Add support for NOPOUT payload using unsolicited RDMA payload
*/
return iscsit_process_nop_out(conn, cmd, hdr);
}
static int static int
isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
uint32_t read_stag, uint64_t read_va, uint32_t read_stag, uint64_t read_va,
...@@ -1032,7 +1051,9 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, ...@@ -1032,7 +1051,9 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
if (!cmd) if (!cmd)
break; break;
ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr); isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
ret = isert_handle_nop_out(isert_conn, isert_cmd,
rx_desc, (unsigned char *)hdr);
break; break;
case ISCSI_OP_SCSI_DATA_OUT: case ISCSI_OP_SCSI_DATA_OUT:
ret = isert_handle_iscsi_dataout(isert_conn, rx_desc, ret = isert_handle_iscsi_dataout(isert_conn, rx_desc,
......
...@@ -1535,24 +1535,16 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) ...@@ -1535,24 +1535,16 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed); return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed);
} }
int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
unsigned char *buf) struct iscsi_nopout *hdr)
{ {
unsigned char *ping_data = NULL; u32 payload_length = ntoh24(hdr->dlength);
int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size;
u32 checksum, data_crc, padding = 0, payload_length;
struct iscsi_cmd *cmd_p = NULL;
struct kvec *iov = NULL;
struct iscsi_nopout *hdr;
hdr = (struct iscsi_nopout *) buf;
payload_length = ntoh24(hdr->dlength);
if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
pr_err("NOPOUT ITT is reserved, but Immediate Bit is" pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
" not set, protocol error.\n"); " not set, protocol error.\n");
return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
buf, conn); 1, 0, (unsigned char *)hdr, cmd);
} }
if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) { if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
...@@ -1560,8 +1552,8 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -1560,8 +1552,8 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
" greater than MaxXmitDataSegmentLength: %u, protocol" " greater than MaxXmitDataSegmentLength: %u, protocol"
" error.\n", payload_length, " error.\n", payload_length,
conn->conn_ops->MaxXmitDataSegmentLength); conn->conn_ops->MaxXmitDataSegmentLength);
return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
buf, conn); 1, 0, (unsigned char *)hdr, cmd);
} }
pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x," pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x,"
...@@ -1577,11 +1569,6 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -1577,11 +1569,6 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
* can contain ping data. * can contain ping data.
*/ */
if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
if (!cmd)
return iscsit_add_reject(
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
1, buf, conn);
cmd->iscsi_opcode = ISCSI_OP_NOOP_OUT; cmd->iscsi_opcode = ISCSI_OP_NOOP_OUT;
cmd->i_state = ISTATE_SEND_NOPIN; cmd->i_state = ISTATE_SEND_NOPIN;
cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ?
...@@ -1593,8 +1580,87 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -1593,8 +1580,87 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
cmd->data_direction = DMA_NONE; cmd->data_direction = DMA_NONE;
} }
return 0;
}
EXPORT_SYMBOL(iscsit_setup_nop_out);
int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
struct iscsi_nopout *hdr)
{
struct iscsi_cmd *cmd_p = NULL;
int cmdsn_ret = 0;
/*
* Initiator is expecting a NopIN ping reply..
*/
if (hdr->itt != RESERVED_ITT) {
BUG_ON(!cmd);
spin_lock_bh(&conn->cmd_lock);
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
iscsit_add_cmd_to_response_queue(cmd, conn,
cmd->i_state);
return 0;
}
cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
return 0;
if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
1, 0, (unsigned char *)hdr, cmd);
return 0;
}
/*
* This was a response to a unsolicited NOPIN ping.
*/
if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
if (!cmd_p)
return -EINVAL;
iscsit_stop_nopin_response_timer(conn);
cmd_p->i_state = ISTATE_REMOVE;
iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
iscsit_start_nopin_timer(conn);
return 0;
}
/*
* Otherwise, initiator is not expecting a NOPIN is response.
* Just ignore for now.
*/
return 0;
}
EXPORT_SYMBOL(iscsit_process_nop_out);
static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
unsigned char *buf)
{
unsigned char *ping_data = NULL;
struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
struct kvec *iov = NULL;
u32 payload_length = ntoh24(hdr->dlength);
int ret;
ret = iscsit_setup_nop_out(conn, cmd, hdr);
if (ret < 0)
return ret;
/*
* Handle NOP-OUT payload for traditional iSCSI sockets
*/
if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
rx_size = payload_length; u32 checksum, data_crc, padding = 0;
int niov = 0, rx_got, rx_size = payload_length;
ping_data = kzalloc(payload_length + 1, GFP_KERNEL); ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
if (!ping_data) { if (!ping_data) {
pr_err("Unable to allocate memory for" pr_err("Unable to allocate memory for"
...@@ -1673,76 +1739,14 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -1673,76 +1739,14 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
pr_debug("Ping Data: \"%s\"\n", ping_data); pr_debug("Ping Data: \"%s\"\n", ping_data);
} }
if (hdr->itt != RESERVED_ITT) { return iscsit_process_nop_out(conn, cmd, hdr);
if (!cmd) {
pr_err("Checking CmdSN for NOPOUT,"
" but cmd is NULL!\n");
return -1;
}
/*
* Initiator is expecting a NopIN ping reply,
*/
spin_lock_bh(&conn->cmd_lock);
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
iscsit_add_cmd_to_response_queue(cmd, conn,
cmd->i_state);
return 0;
}
cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
ret = 0;
goto ping_out;
}
if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
1, 0, buf, cmd);
return 0;
}
if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
/*
* This was a response to a unsolicited NOPIN ping.
*/
cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
if (!cmd_p)
return -1;
iscsit_stop_nopin_response_timer(conn);
cmd_p->i_state = ISTATE_REMOVE;
iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
iscsit_start_nopin_timer(conn);
} else {
/*
* Initiator is not expecting a NOPIN is response.
* Just ignore for now.
*
* iSCSI v19-91 10.18
* "A NOP-OUT may also be used to confirm a changed
* ExpStatSN if another PDU will not be available
* for a long time."
*/
ret = 0;
goto out;
}
return 0;
out: out:
if (cmd) if (cmd)
iscsit_free_cmd(cmd, false); iscsit_free_cmd(cmd, false);
ping_out:
kfree(ping_data); kfree(ping_data);
return ret; return ret;
} }
EXPORT_SYMBOL(iscsit_handle_nop_out);
int int
iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
......
...@@ -45,8 +45,10 @@ extern int iscsit_check_dataout_hdr(struct iscsi_conn *, unsigned char *, ...@@ -45,8 +45,10 @@ extern int iscsit_check_dataout_hdr(struct iscsi_conn *, unsigned char *,
struct iscsi_cmd **); struct iscsi_cmd **);
extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *, extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *,
bool); bool);
extern int iscsit_handle_nop_out(struct iscsi_conn *, struct iscsi_cmd *, extern int iscsit_setup_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
unsigned char *); struct iscsi_nopout *);
extern int iscsit_process_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
struct iscsi_nopout *);
extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *, extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *,
unsigned char *); unsigned char *);
extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *, extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *,
......
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