static unsigned int iscsi_max_lun = ~0;
 module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
 
+static bool iscsi_recv_from_iscsi_q;
+module_param_named(recv_from_iscsi_q, iscsi_recv_from_iscsi_q, bool, 0644);
+MODULE_PARM_DESC(recv_from_iscsi_q, "Set to true to read iSCSI data/headers from the iscsi_q workqueue. The default is false which will perform reads from the network softirq context.");
+
 static int iscsi_sw_tcp_dbg;
 module_param_named(debug_iscsi_tcp, iscsi_sw_tcp_dbg, int,
                   S_IRUGO | S_IWUSR);
        return 0;
 }
 
-static void iscsi_sw_tcp_data_ready(struct sock *sk)
+static void iscsi_sw_tcp_recv_data(struct iscsi_conn *conn)
 {
-       struct iscsi_conn *conn;
-       struct iscsi_tcp_conn *tcp_conn;
+       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+       struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
+       struct sock *sk = tcp_sw_conn->sock->sk;
        read_descriptor_t rd_desc;
 
-       read_lock_bh(&sk->sk_callback_lock);
-       conn = sk->sk_user_data;
-       if (!conn) {
-               read_unlock_bh(&sk->sk_callback_lock);
-               return;
-       }
-       tcp_conn = conn->dd_data;
-
        /*
         * Use rd_desc to pass 'conn' to iscsi_tcp_recv.
         * We set count to 1 because we want the network layer to
         */
        rd_desc.arg.data = conn;
        rd_desc.count = 1;
-       tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv);
 
-       iscsi_sw_sk_state_check(sk);
+       tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv);
 
        /* If we had to (atomically) map a highmem page,
         * unmap it now. */
        iscsi_tcp_segment_unmap(&tcp_conn->in.segment);
+
+       iscsi_sw_sk_state_check(sk);
+}
+
+static void iscsi_sw_tcp_recv_data_work(struct work_struct *work)
+{
+       struct iscsi_conn *conn = container_of(work, struct iscsi_conn,
+                                              recvwork);
+       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+       struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
+       struct sock *sk = tcp_sw_conn->sock->sk;
+
+       lock_sock(sk);
+       iscsi_sw_tcp_recv_data(conn);
+       release_sock(sk);
+}
+
+static void iscsi_sw_tcp_data_ready(struct sock *sk)
+{
+       struct iscsi_sw_tcp_conn *tcp_sw_conn;
+       struct iscsi_tcp_conn *tcp_conn;
+       struct iscsi_conn *conn;
+
+       read_lock_bh(&sk->sk_callback_lock);
+       conn = sk->sk_user_data;
+       if (!conn) {
+               read_unlock_bh(&sk->sk_callback_lock);
+               return;
+       }
+       tcp_conn = conn->dd_data;
+       tcp_sw_conn = tcp_conn->dd_data;
+
+       if (tcp_sw_conn->queue_recv)
+               iscsi_conn_queue_recv(conn);
+       else
+               iscsi_sw_tcp_recv_data(conn);
        read_unlock_bh(&sk->sk_callback_lock);
 }
 
                if (segment->total_copied + segment->size < segment->total_size)
                        flags |= MSG_MORE;
 
+               if (tcp_sw_conn->queue_recv)
+                       flags |= MSG_DONTWAIT;
+
                /* Use sendpage if we can; else fall back to sendmsg */
                if (!segment->data) {
                        sg = segment->sg;
        conn = cls_conn->dd_data;
        tcp_conn = conn->dd_data;
        tcp_sw_conn = tcp_conn->dd_data;
+       INIT_WORK(&conn->recvwork, iscsi_sw_tcp_recv_data_work);
+       tcp_sw_conn->queue_recv = iscsi_recv_from_iscsi_q;
 
        tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(tfm))
        iscsi_sw_tcp_conn_restore_callbacks(conn);
        sock_put(sock->sk);
 
+       iscsi_suspend_rx(conn);
+
        spin_lock_bh(&session->frwd_lock);
        tcp_sw_conn->sock = NULL;
        spin_unlock_bh(&session->frwd_lock);