[PATCH] LOG2: Implement a general integer log2 facility in the kernel
[deliverable/linux.git] / drivers / infiniband / ulp / iser / iser_memory.c
index 8fea0bce5042c42379b022819163539ac31c67d0..3aedd59b8a847edf20ecf2f75dece524f1e837da 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
+#include <linux/highmem.h>
 #include <asm/io.h>
 #include <asm/scatterlist.h>
 #include <linux/scatterlist.h>
@@ -56,7 +57,7 @@ int iser_regd_buff_release(struct iser_regd_buf *regd_buf)
        if ((atomic_read(&regd_buf->ref_count) == 0) ||
            atomic_dec_and_test(&regd_buf->ref_count)) {
                /* if we used the dma mr, unreg is just NOP */
-               if (regd_buf->reg.rkey != 0)
+               if (regd_buf->reg.is_fmr)
                        iser_unreg_mem(&regd_buf->reg);
 
                if (regd_buf->dma_addr) {
@@ -91,9 +92,9 @@ void iser_reg_single(struct iser_device *device,
        BUG_ON(dma_mapping_error(dma_addr));
 
        regd_buf->reg.lkey = device->mr->lkey;
-       regd_buf->reg.rkey = 0; /* indicate there's no need to unreg */
        regd_buf->reg.len  = regd_buf->data_size;
        regd_buf->reg.va   = dma_addr;
+       regd_buf->reg.is_fmr = 0;
 
        regd_buf->dma_addr  = dma_addr;
        regd_buf->direction = direction;
@@ -113,7 +114,7 @@ int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task  *iser_ctask,
 
        if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
                mem = (void *)__get_free_pages(GFP_NOIO,
-                     long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+                     ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
        else
                mem = kmalloc(cmd_data_len, GFP_NOIO);
 
@@ -210,7 +211,7 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
 
        if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
                free_pages((unsigned long)mem_copy->copy_buf,
-                          long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+                          ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
        else
                kfree(mem_copy->copy_buf);
 
@@ -369,6 +370,44 @@ static void iser_page_vec_build(struct iser_data_buf *data,
        }
 }
 
+int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
+                           struct iser_data_buf       *data,
+                           enum   iser_data_dir       iser_dir,
+                           enum   dma_data_direction  dma_dir)
+{
+       struct device *dma_device;
+
+       iser_ctask->dir[iser_dir] = 1;
+       dma_device =
+               iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+       data->dma_nents = dma_map_sg(dma_device, data->buf, data->size, dma_dir);
+       if (data->dma_nents == 0) {
+               iser_err("dma_map_sg failed!!!\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
+{
+       struct device  *dma_device;
+       struct iser_data_buf *data;
+
+       dma_device =
+               iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+       if (iser_ctask->dir[ISER_DIR_IN]) {
+               data = &iser_ctask->data[ISER_DIR_IN];
+               dma_unmap_sg(dma_device, data->buf, data->size, DMA_FROM_DEVICE);
+       }
+
+       if (iser_ctask->dir[ISER_DIR_OUT]) {
+               data = &iser_ctask->data[ISER_DIR_OUT];
+               dma_unmap_sg(dma_device, data->buf, data->size, DMA_TO_DEVICE);
+       }
+}
+
 /**
  * iser_reg_rdma_mem - Registers memory intended for RDMA,
  * obtaining rkey and va
@@ -379,11 +418,13 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
                      enum   iser_data_dir        cmd_dir)
 {
        struct iser_conn     *ib_conn = iser_ctask->iser_conn->ib_conn;
+       struct iser_device   *device = ib_conn->device;
        struct iser_data_buf *mem = &iser_ctask->data[cmd_dir];
        struct iser_regd_buf *regd_buf;
        int aligned_len;
        int err;
        int i;
+       struct scatterlist *sg;
 
        regd_buf = &iser_ctask->rdma_regd[cmd_dir];
 
@@ -392,6 +433,10 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
                iser_err("rdma alignment violation %d/%d aligned\n",
                         aligned_len, mem->size);
                iser_data_buf_dump(mem);
+
+               /* unmap the command data before accessing it */
+               iser_dma_unmap_task_data(iser_ctask);
+
                /* allocate copy buf, if we are writing, copy the */
                /* unaligned scatterlist, dma map the copy        */
                if (iser_start_rdma_unaligned_sg(iser_ctask, cmd_dir) != 0)
@@ -399,19 +444,37 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
                mem = &iser_ctask->data_copy[cmd_dir];
        }
 
-       iser_page_vec_build(mem, ib_conn->page_vec);
-       err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, &regd_buf->reg);
-       if (err) {
-               iser_data_buf_dump(mem);
-               iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents,
-                        ntoh24(iser_ctask->desc.iscsi_header.dlength));
-               iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n",
-                        ib_conn->page_vec->data_size, ib_conn->page_vec->length,
-                        ib_conn->page_vec->offset);
-               for (i=0 ; i<ib_conn->page_vec->length ; i++) {
-                       iser_err("page_vec[%d] = 0x%lx\n", i, ib_conn->page_vec->pages[i]);
+       /* if there a single dma entry, FMR is not needed */
+       if (mem->dma_nents == 1) {
+               sg = (struct scatterlist *)mem->buf;
+
+               regd_buf->reg.lkey = device->mr->lkey;
+               regd_buf->reg.rkey = device->mr->rkey;
+               regd_buf->reg.len  = sg_dma_len(&sg[0]);
+               regd_buf->reg.va   = sg_dma_address(&sg[0]);
+               regd_buf->reg.is_fmr = 0;
+
+               iser_dbg("PHYSICAL Mem.register: lkey: 0x%08X rkey: 0x%08X  "
+                        "va: 0x%08lX sz: %ld]\n",
+                        (unsigned int)regd_buf->reg.lkey,
+                        (unsigned int)regd_buf->reg.rkey,
+                        (unsigned long)regd_buf->reg.va,
+                        (unsigned long)regd_buf->reg.len);
+       } else { /* use FMR for multiple dma entries */
+               iser_page_vec_build(mem, ib_conn->page_vec);
+               err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, &regd_buf->reg);
+               if (err) {
+                       iser_data_buf_dump(mem);
+                       iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents,
+                                ntoh24(iser_ctask->desc.iscsi_header.dlength));
+                       iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n",
+                                ib_conn->page_vec->data_size, ib_conn->page_vec->length,
+                                ib_conn->page_vec->offset);
+                       for (i=0 ; i<ib_conn->page_vec->length ; i++)
+                               iser_err("page_vec[%d] = 0x%llx\n", i,
+                                        (unsigned long long) ib_conn->page_vec->pages[i]);
+                       return err;
                }
-               return err;
        }
 
        /* take a reference on this regd buf such that it will not be released *
This page took 0.026709 seconds and 5 git commands to generate.