]> git.karo-electronics.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:52:36 +0000 (09:52 -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 7e7373a700e603bc2fed30f974a6e0f2d3b990aa..d5f3b692cdd0cde6173687de3fde8c4c15065bc3 100644 (file)
@@ -364,6 +364,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 */
@@ -398,19 +401,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);
@@ -724,7 +714,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 db7ea3704da75a62b65ab0e78b7f53fbac068b39..296be431a0e93b773b5618efd0b07d018d187b3b 100644 (file)
@@ -366,4 +366,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 a607542fc79611681b76fb8ce1b4831ca3b1a2bd..738a1499812b3286f0fb959775de1c328fb2875d 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;
@@ -242,23 +242,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;
@@ -438,6 +439,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);