]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
IB/iser: Post initial receive buffers before sending the final login request
authorOr Gerlitz <ogerlitz@mellanox.com>
Mon, 5 Mar 2012 16:21:44 +0000 (18:21 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 2 Apr 2012 16:27:10 +0000 (09:27 -0700)
commit 89e984e2c2cd14f77ccb26c47726ac7f13b70ae8 upstream.

An iser target may send iscsi NO-OP PDUs as soon as it marks the iSER
iSCSI session as fully operative.  This means that there is window
where there are no posted receive buffers on the initiator side, so
it's possible for the iSER RC connection to break because of RNR NAK /
retry errors.  To fix this, rely on the flags bits in the login
request to have FFP (0x3) in the lower nibble as a marker for the
final login request, and post an initial chunk of receive buffers
before sending that login request instead of after getting the login
response.

Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_initiator.c

index 8db008de5392209c6da296d9a2aa7f3729e4ae72..f8f57583f5d07f55ad0260770623d6ef59050f5c 100644 (file)
@@ -354,6 +354,9 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
        }
        ib_conn = ep->dd_data;
 
+       if (iser_alloc_rx_descriptors(ib_conn))
+               return -ENOMEM;
+
        /* binds the iSER connection retrieved from the previously
         * connected ep_handle to the iSCSI layer connection. exchanges
         * connection pointers */
@@ -388,19 +391,6 @@ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
        iser_conn->ib_conn = NULL;
 }
 
-static int
-iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
-{
-       struct iscsi_conn *conn = cls_conn->dd_data;
-       int err;
-
-       err = iser_conn_set_full_featured_mode(conn);
-       if (err)
-               return err;
-
-       return iscsi_conn_start(cls_conn);
-}
-
 static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
 {
        struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
@@ -686,7 +676,7 @@ static struct iscsi_transport iscsi_iser_transport = {
        .get_conn_param         = iscsi_conn_get_param,
        .get_ep_param           = iscsi_iser_get_ep_param,
        .get_session_param      = iscsi_session_get_param,
-       .start_conn             = iscsi_iser_conn_start,
+       .start_conn             = iscsi_conn_start,
        .stop_conn              = iscsi_iser_conn_stop,
        /* iscsi host params */
        .get_host_param         = iscsi_host_get_param,
index 2f02ab0ccc1eb7e93c9a77aae44501646bc27ad8..634aef039fe25871cfd59ba5507705f06ff4b9bd 100644 (file)
@@ -365,4 +365,5 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
 void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task);
 int  iser_initialize_task_headers(struct iscsi_task *task,
                        struct iser_tx_desc *tx_desc);
+int iser_alloc_rx_descriptors(struct iser_conn *ib_conn);
 #endif
index 95a08a8ca8aab9fe3532cb877a38ba0026767bb0..eb1ee6f8d894899d80303df55b272d5abf291925 100644 (file)
@@ -170,7 +170,7 @@ static void iser_create_send_desc(struct iser_conn  *ib_conn,
 }
 
 
-static int iser_alloc_rx_descriptors(struct iser_conn *ib_conn)
+int iser_alloc_rx_descriptors(struct iser_conn *ib_conn)
 {
        int i, j;
        u64 dma_addr;
@@ -236,23 +236,24 @@ void iser_free_rx_descriptors(struct iser_conn *ib_conn)
        kfree(ib_conn->rx_descs);
 }
 
-/**
- *  iser_conn_set_full_featured_mode - (iSER API)
- */
-int iser_conn_set_full_featured_mode(struct iscsi_conn *conn)
+static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
 {
        struct iscsi_iser_conn *iser_conn = conn->dd_data;
 
-       iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX);
-
-       /* Check that there is no posted recv or send buffers left - */
-       /* they must be consumed during the login phase */
-       BUG_ON(iser_conn->ib_conn->post_recv_buf_count != 0);
-       BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
+       iser_dbg("req op %x flags %x\n", req->opcode, req->flags);
+       /* check if this is the last login - going to full feature phase */
+       if ((req->flags & ISCSI_FULL_FEATURE_PHASE) != ISCSI_FULL_FEATURE_PHASE)
+               return 0;
 
-       if (iser_alloc_rx_descriptors(iser_conn->ib_conn))
-               return -ENOMEM;
+       /*
+        * Check that there is one posted recv buffer (for the last login
+        * response) and no posted send buffers left - they must have been
+        * consumed during previous login phases.
+        */
+       WARN_ON(iser_conn->ib_conn->post_recv_buf_count != 1);
+       WARN_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
 
+       iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX);
        /* Initial post receive buffers */
        if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX))
                return -ENOMEM;
@@ -421,6 +422,9 @@ int iser_send_control(struct iscsi_conn *conn,
                err = iser_post_recvl(iser_conn->ib_conn);
                if (err)
                        goto send_control_error;
+               err = iser_post_rx_bufs(conn, task->hdr);
+               if (err)
+                       goto send_control_error;
        }
 
        err = iser_post_send(iser_conn->ib_conn, mdesc);