]> Pileus Git - ~andy/linux/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)
committerRoland Dreier <roland@purestorage.com>
Mon, 5 Mar 2012 16:53:05 +0000 (08:53 -0800)
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>
Cc: <stable@vger.kernel.org>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_initiator.c

index 9a43cb07f294a80ec4d5cc0143053e566ac53866..db43b3117168f0df7c13532dca71cd5289ef6096 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 622e9857c86913899b3e1ad1e8be01a84686ca92..a00ccd1ca33337681afa9624b652c1912574ef07 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;
@@ -230,23 +230,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;
@@ -426,6 +427,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);