iscsi/isert-target: Refactor ISCSI_OP_NOOP RX handling
authorNicholas Bellinger <nab@linux-iscsi.org>
Fri, 14 Jun 2013 23:07:47 +0000 (16:07 -0700)
committerNicholas Bellinger <nab@linux-iscsi.org>
Tue, 25 Jun 2013 05:35:51 +0000 (22:35 -0700)
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: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/infiniband/ulp/isert/ib_isert.c
drivers/target/iscsi/iscsi_target.c
include/target/iscsi/iscsi_transport.h

index 41712f096515675ee70273c99856e8d888a06ea9..c48c9481025c98c8b7a9a6bc36c44289215d40c4 100644 (file)
@@ -1000,6 +1000,25 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
        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
 isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                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,
                if (!cmd)
                        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;
        case ISCSI_OP_SCSI_DATA_OUT:
                ret = isert_handle_iscsi_dataout(isert_conn, rx_desc,
index cc43d4163adce80e5c9d32b150cbe8f01c48bf96..f684627244bfc27f62e1c9439847cc07a3fbdc1d 100644 (file)
@@ -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);
 }
 
-int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
-                       unsigned char *buf)
+int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                        struct iscsi_nopout *hdr)
 {
-       unsigned char *ping_data = NULL;
-       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);
+       u32 payload_length = ntoh24(hdr->dlength);
 
        if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
                pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
                        " not set, protocol error.\n");
-               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buf, conn);
+               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+                                       1, 0, (unsigned char *)hdr, cmd);
        }
 
        if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
@@ -1560,8 +1552,8 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                        " greater than MaxXmitDataSegmentLength: %u, protocol"
                        " error.\n", payload_length,
                        conn->conn_ops->MaxXmitDataSegmentLength);
-               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buf, conn);
+               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+                                       1, 0, (unsigned char *)hdr, cmd);
        }
 
        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,
         * can contain ping data.
         */
        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->i_state            = ISTATE_SEND_NOPIN;
                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,
                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)) {
-               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);
                if (!ping_data) {
                        pr_err("Unable to allocate memory for"
@@ -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);
        }
 
-       if (hdr->itt != RESERVED_ITT) {
-               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;
+       return iscsit_process_nop_out(conn, cmd, hdr);
 out:
        if (cmd)
                iscsit_free_cmd(cmd, false);
-ping_out:
+
        kfree(ping_data);
        return ret;
 }
-EXPORT_SYMBOL(iscsit_handle_nop_out);
 
 int
 iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
index 23a87d0cd72c22ed876463bc997d5190ccb635d0..ecb53ea6d1c7b8da15dba2cfb3fdf8df8a1cad6e 100644 (file)
@@ -45,8 +45,10 @@ extern int iscsit_check_dataout_hdr(struct iscsi_conn *, unsigned char *,
                                struct iscsi_cmd **);
 extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *,
                                bool);
-extern int iscsit_handle_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
-                               unsigned char *);
+extern int iscsit_setup_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
+                               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 *,
                                unsigned char *);
 extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *,