IB/iser: Use separate buffers for the login request/response
authorOr Gerlitz <ogerlitz@mellanox.com>
Thu, 3 Nov 2011 22:19:46 +0000 (00:19 +0200)
committerRoland Dreier <roland@purestorage.com>
Fri, 4 Nov 2011 16:30:52 +0000 (09:30 -0700)
The driver counted on the transactional nature of iSCSI login/text
flows and used the same buffer for both the request and the response.
We also went further and did DMA mapping only once, with
DMA_FROM_DEVICE, which violates the DMA mapping API.  Fix that by
using different buffers, one for requests and one for responses, and
use the correct DMA mapping direction for each.

Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/infiniband/ulp/iser/iser_verbs.c

index db6f3ce9f3bf52d2bbfde9475b7b239f0a341bcf..2982a14a0557cef458fc696d1442625678b1decd 100644 (file)
@@ -257,7 +257,8 @@ struct iser_conn {
        struct list_head             conn_list;       /* entry in ig conn list */
 
        char                         *login_buf;
-       u64                          login_dma;
+       char                         *login_req_buf, *login_resp_buf;
+       u64                          login_req_dma, login_resp_dma;
        unsigned int                 rx_desc_head;
        struct iser_rx_desc          *rx_descs;
        struct ib_recv_wr            rx_wr[ISER_MIN_POSTED_RX];
index f299de6b419bb03cf9486e7f813e1100c4cad4a5..a607542fc79611681b76fb8ce1b4831ca3b1a2bd 100644 (file)
@@ -221,8 +221,14 @@ void iser_free_rx_descriptors(struct iser_conn *ib_conn)
        struct iser_device *device = ib_conn->device;
 
        if (ib_conn->login_buf) {
-               ib_dma_unmap_single(device->ib_device, ib_conn->login_dma,
-                       ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE);
+               if (ib_conn->login_req_dma)
+                       ib_dma_unmap_single(device->ib_device,
+                               ib_conn->login_req_dma,
+                               ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE);
+               if (ib_conn->login_resp_dma)
+                       ib_dma_unmap_single(device->ib_device,
+                               ib_conn->login_resp_dma,
+                               ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE);
                kfree(ib_conn->login_buf);
        }
 
@@ -394,6 +400,7 @@ int iser_send_control(struct iscsi_conn *conn,
        unsigned long data_seg_len;
        int err = 0;
        struct iser_device *device;
+       struct iser_conn *ib_conn = iser_conn->ib_conn;
 
        /* build the tx desc regd header and add it to the tx desc dto */
        mdesc->type = ISCSI_TX_CONTROL;
@@ -409,9 +416,19 @@ int iser_send_control(struct iscsi_conn *conn,
                        iser_err("data present on non login task!!!\n");
                        goto send_control_error;
                }
-               memcpy(iser_conn->ib_conn->login_buf, task->data,
+
+               ib_dma_sync_single_for_cpu(device->ib_device,
+                       ib_conn->login_req_dma, task->data_count,
+                       DMA_TO_DEVICE);
+
+               memcpy(iser_conn->ib_conn->login_req_buf, task->data,
                                                        task->data_count);
-               tx_dsg->addr    = iser_conn->ib_conn->login_dma;
+
+               ib_dma_sync_single_for_device(device->ib_device,
+                       ib_conn->login_req_dma, task->data_count,
+                       DMA_TO_DEVICE);
+
+               tx_dsg->addr    = iser_conn->ib_conn->login_req_dma;
                tx_dsg->length  = task->data_count;
                tx_dsg->lkey    = device->mr->lkey;
                mdesc->num_sge = 2;
@@ -445,8 +462,8 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc,
        int rx_buflen, outstanding, count, err;
 
        /* differentiate between login to all other PDUs */
-       if ((char *)rx_desc == ib_conn->login_buf) {
-               rx_dma = ib_conn->login_dma;
+       if ((char *)rx_desc == ib_conn->login_resp_buf) {
+               rx_dma = ib_conn->login_resp_dma;
                rx_buflen = ISER_RX_LOGIN_SIZE;
        } else {
                rx_dma = rx_desc->dma_addr;
@@ -473,7 +490,7 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc,
         * for the posted rx bufs refcount to become zero handles everything   */
        conn->ib_conn->post_recv_buf_count--;
 
-       if (rx_dma == ib_conn->login_dma)
+       if (rx_dma == ib_conn->login_resp_dma)
                return;
 
        outstanding = ib_conn->post_recv_buf_count;
index ede1475bee09cc74ef7b6269f65d001c7dc97198..e28877c4ce159590a304ba98174d5637102ea9d0 100644 (file)
@@ -155,20 +155,39 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn)
 {
        struct iser_device      *device;
        struct ib_qp_init_attr  init_attr;
-       int                     ret = -ENOMEM;
+       int                     req_err, resp_err, ret = -ENOMEM;
        struct ib_fmr_pool_param params;
 
        BUG_ON(ib_conn->device == NULL);
 
        device = ib_conn->device;
 
-       ib_conn->login_buf = kmalloc(ISER_RX_LOGIN_SIZE, GFP_KERNEL);
+       ib_conn->login_buf = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN +
+                                       ISER_RX_LOGIN_SIZE, GFP_KERNEL);
        if (!ib_conn->login_buf)
                goto out_err;
 
-       ib_conn->login_dma = ib_dma_map_single(ib_conn->device->ib_device,
-                               (void *)ib_conn->login_buf, ISER_RX_LOGIN_SIZE,
-                               DMA_FROM_DEVICE);
+       ib_conn->login_req_buf  = ib_conn->login_buf;
+       ib_conn->login_resp_buf = ib_conn->login_buf + ISCSI_DEF_MAX_RECV_SEG_LEN;
+
+       ib_conn->login_req_dma = ib_dma_map_single(ib_conn->device->ib_device,
+                               (void *)ib_conn->login_req_buf,
+                               ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE);
+
+       ib_conn->login_resp_dma = ib_dma_map_single(ib_conn->device->ib_device,
+                               (void *)ib_conn->login_resp_buf,
+                               ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE);
+
+       req_err  = ib_dma_mapping_error(device->ib_device, ib_conn->login_req_dma);
+       resp_err = ib_dma_mapping_error(device->ib_device, ib_conn->login_resp_dma);
+
+       if (req_err || resp_err) {
+               if (req_err)
+                       ib_conn->login_req_dma = 0;
+               if (resp_err)
+                       ib_conn->login_resp_dma = 0;
+               goto out_err;
+       }
 
        ib_conn->page_vec = kmalloc(sizeof(struct iser_page_vec) +
                                    (sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE +1)),
@@ -658,11 +677,11 @@ int iser_post_recvl(struct iser_conn *ib_conn)
        struct ib_sge     sge;
        int ib_ret;
 
-       sge.addr   = ib_conn->login_dma;
+       sge.addr   = ib_conn->login_resp_dma;
        sge.length = ISER_RX_LOGIN_SIZE;
        sge.lkey   = ib_conn->device->mr->lkey;
 
-       rx_wr.wr_id   = (unsigned long)ib_conn->login_buf;
+       rx_wr.wr_id   = (unsigned long)ib_conn->login_resp_buf;
        rx_wr.sg_list = &sge;
        rx_wr.num_sge = 1;
        rx_wr.next    = NULL;