OSDN Git Service

iscsi/iser-target: Support multi-sequence sendtargets text response
authorSagi Grimberg <sagig@mellanox.com>
Mon, 9 Feb 2015 16:07:25 +0000 (18:07 +0200)
committerNicholas Bellinger <nab@linux-iscsi.org>
Thu, 12 Feb 2015 19:24:29 +0000 (11:24 -0800)
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: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/infiniband/ulp/isert/ib_isert.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
include/target/iscsi/iscsi_target_core.h

index da8c860..075b19c 100644 (file)
@@ -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);
                break;
        case ISCSI_OP_TEXT:
-               cmd = isert_allocate_cmd(conn);
-               if (!cmd)
-                       break;
+               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);
+                       if (!cmd)
+                               break;
+               }
 
                isert_cmd = iscsit_priv_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)
        struct isert_conn *isert_conn = isert_cmd->conn;
        struct iscsi_conn *conn = isert_conn->conn;
        struct isert_device *device = isert_conn->conn_device;
+       struct iscsi_text_rsp *hdr;
 
        isert_dbg("Cmd %p\n", isert_cmd);
 
@@ -1700,6 +1707,11 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err)
        case ISCSI_OP_REJECT:
        case ISCSI_OP_NOOP_OUT:
        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);
                if (!list_empty(&cmd->i_conn_node))
                        list_del_init(&cmd->i_conn_node);
index 75c29b6..f533a0d 100644 (file)
@@ -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;
index c211d3f..390df8e 100644 (file)
@@ -390,6 +390,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt(
                        init_task_tag, conn->cid);
        return NULL;
 }
+EXPORT_SYMBOL(iscsit_find_cmd_from_itt);
 
 struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
        struct iscsi_conn *conn,
index a68508c..1ab754a 100644 (file)
@@ -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,
                               unsigned char * ,__be32 cmdsn);
 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 *,
                        itt_t, u32);
 extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32);
index 5f41a17..04d8f99 100644 (file)
@@ -893,4 +893,5 @@ static inline u32 session_get_next_ttt(struct iscsi_session *session)
        return ttt;
 }
 
+extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
 #endif /* ISCSI_TARGET_CORE_H */