Roland,
    Vu> Since all the tuned parameter are target-centralized (passing
    Vu> in when add new target) I think about moving FMR resources
    Vu> (size, max_page...) ie. fmr_pool into srp_target_port
    Vu> struct. Each newly added target will have their own customized
    Vu> FMR pool.

That makes some sense.  An issue is that FMRs are a fairly limited
resource, and a system with many SRP targets where each target doesn't
get much traffic could tie up a lot of FMRs.

  
You're right. For the same reason of unused port (ie. srp_host), I create fmr resource per device and keep it in srp_device_data struct

I put back fmr + your patch and it works well with my setup.

Signed-off-by: Vu Pham <[EMAIL PROTECTED]>

 
Index: ulp/srp/ib_srp.c
===================================================================
--- ulp/srp/ib_srp.c    (revision 3615)
+++ ulp/srp/ib_srp.c    (working copy)
@@ -522,10 +522,105 @@ err:
        return ret;
 }
 
+static int srp_map_fmr(struct srp_target_port *target, struct scatterlist 
*scat,
+                      int sg_cnt, struct srp_request *req)
+                      
+{
+       dma_addr_t              dma_addr;
+       u32                     dma_len;
+       u32                     cur_len;
+       u32                     tmp_len;
+       int                     i;
+       u64                    *dma_pages;
+       u32                     page_cnt;
+       struct srp_fmr         *srp_fmr;
+       u32                     unaligned;
+
+       dma_pages = kmalloc(sizeof(u64) * sg_cnt * (SRP_MAX_INDIRECT + 2), 
GFP_ATOMIC);
+       if (!dma_pages)
+               goto err_dpages;        
+
+       req->fmr_arr = kmalloc(sizeof(struct srp_fmr) * sg_cnt, GFP_ATOMIC);
+       if (!req->fmr_arr)
+               goto err_farr;
+
+       srp_fmr = req->fmr_arr;
+       req->fmr_cnt = 0;
+       page_cnt = 0;
+       cur_len = 0;
+       unaligned = 0;
+
+       for (i = 0; i < sg_cnt; ++i) {
+               dma_len = sg_dma_len(scat);
+               dma_addr = sg_dma_address(scat);
+
+               if (scat->offset ||
+                   ((i == (sg_cnt - 1)) && !unaligned)) {
+                       srp_fmr->io_addr = dma_addr & PAGE_MASK;
+                       ++unaligned;
+               }
+
+               if (unaligned <= 1) {
+                       cur_len += dma_len;
+                       for (tmp_len = 0; tmp_len < dma_len;
+                            tmp_len += PAGE_SIZE, dma_addr += PAGE_SIZE)
+                               dma_pages[page_cnt++] = dma_addr & PAGE_MASK;
+               }
+
+               if ((unaligned > 1) || (i == (sg_cnt - 1))) {
+                       srp_fmr->mem =
+                               ib_fmr_pool_map_phys(target->srp_host->fmr_pool,
+                                                    dma_pages, page_cnt,
+                                                    &srp_fmr->io_addr);
+                       if (IS_ERR(srp_fmr->mem)) {
+                               srp_fmr->mem = NULL;
+                               goto err_map_phys;
+                       }
+
+                       srp_fmr->len = cur_len;
+                       ++req->fmr_cnt;
+
+                       /* restart the new fmr segment */
+                       if (unaligned > 1) {
+                               srp_fmr++;
+                               page_cnt = 0;
+                               --unaligned;
+                               cur_len = dma_len;
+                               srp_fmr->io_addr = dma_addr & PAGE_MASK;
+                               for (tmp_len = 0; tmp_len < dma_len;
+                                    tmp_len += PAGE_SIZE, dma_addr += 
PAGE_SIZE)
+                                       dma_pages[page_cnt++] = dma_addr & 
PAGE_MASK;
+                       }
+               }
+               scat++;
+       }
+
+       kfree(dma_pages);
+
+       return req->fmr_cnt;
+
+err_map_phys:
+       srp_fmr = req->fmr_arr;
+       for (i = 0; i < req->fmr_cnt; ++i) {
+               ib_fmr_pool_unmap(srp_fmr->mem);
+               ++srp_fmr;
+       }
+       kfree(req->fmr_arr);
+       req->fmr_arr = NULL;
+       req->fmr_cnt = 0;
+
+err_farr:
+       kfree(dma_pages);
+
+err_dpages:
+       return -ENOMEM;
+}
+
+
 static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port 
*target,
-                       struct srp_iu *iu)
+                       struct srp_request *req)
 {
-       struct srp_cmd *cmd = iu->buf;
+       struct srp_cmd *cmd = req->cmd->buf;
        int len;
        u8 fmt;
 
@@ -561,36 +656,71 @@ static int srp_map_data(struct scsi_cmnd
                } else {
                        struct srp_indirect_buf *buf = (void *) cmd->add_data;
                        u32 datalen = 0;
+                       int fmr_cnt;
+                       struct srp_fmr *srp_fmr;
 
-                       fmt = SRP_DATA_DESC_INDIRECT;
+                       fmr_cnt = srp_map_fmr(target, scat, n, req);
+                       srp_fmr = req->fmr_arr;
 
-                       if (scmnd->sc_data_direction == DMA_TO_DEVICE)
-                               cmd->data_out_desc_cnt = n;
-                       else
-                               cmd->data_in_desc_cnt = n;
-
-                       buf->table_desc.va  = cpu_to_be64(iu->dma +
-                                                         sizeof *cmd +
-                                                         sizeof *buf);
-                       buf->table_desc.key =
-                               cpu_to_be32(target->srp_host->mr->rkey);
-                       buf->table_desc.len =
-                               cpu_to_be32(n * sizeof (struct srp_direct_buf));
-
-                       for (i = 0; i < n; ++i) {
-                               buf->desc_list[i].va  = 
cpu_to_be64(sg_dma_address(&scat[i]));
-                               buf->desc_list[i].key =
-                                       cpu_to_be32(target->srp_host->mr->rkey);
-                               buf->desc_list[i].len = 
cpu_to_be32(sg_dma_len(&scat[i]));
+                       if (fmr_cnt == 1) {
+                               struct srp_direct_buf *d_buf = (void *) 
cmd->add_data;
 
-                               datalen += sg_dma_len(&scat[i]);
+                               d_buf->va  = cpu_to_be64(srp_fmr->io_addr);
+                               d_buf->key = 
cpu_to_be32(srp_fmr->mem->fmr->rkey);
+                               d_buf->len = cpu_to_be32(srp_fmr->len);
+                               n = 1;
+                       } else if (fmr_cnt <= 0) {
+                               for (i = 0; i < n; ++i) {
+                                       buf->desc_list[i].va  = 
+                                               
cpu_to_be64(sg_dma_address(&scat[i]));
+                                       buf->desc_list[i].key =
+                                               
cpu_to_be32(target->srp_host->mr->rkey);
+                                       buf->desc_list[i].len =
+                                               
cpu_to_be32(sg_dma_len(&scat[i]));
+
+                                       datalen += sg_dma_len(&scat[i]);
+                               }
+                       } else {
+                               for (i = 0; i < req->fmr_cnt; ++i) {
+                                       buf->desc_list[i].va  = 
+                                               cpu_to_be64(srp_fmr->io_addr);
+                                       buf->desc_list[i].key =
+                                               
cpu_to_be32(srp_fmr->mem->fmr->rkey);
+                                       buf->desc_list[i].len = 
+                                               cpu_to_be32(srp_fmr->len);
+                       
+                                       datalen += srp_fmr->len;
+                                       ++srp_fmr;
+                               }
+                               n = fmr_cnt;
                        }
 
-                       buf->len = cpu_to_be32(datalen);
+                       if (n == 1) {
+                               fmt = SRP_DATA_DESC_DIRECT;
+                               len = sizeof (struct srp_cmd) +
+                                       sizeof (struct srp_direct_buf);
+                       } else {
+                               fmt = SRP_DATA_DESC_INDIRECT;
+
+                               if (scmnd->sc_data_direction == DMA_TO_DEVICE)
+                                       cmd->data_out_desc_cnt = n;
+                               else
+                                       cmd->data_in_desc_cnt = n;
+
+                               buf->table_desc.va  = cpu_to_be64(req->cmd->dma 
+
+                                                                 sizeof *cmd +
+                                                                 sizeof *buf);
+                               buf->table_desc.key =
+                                       cpu_to_be32(target->srp_host->mr->rkey);
+                               buf->table_desc.len =
+                                       cpu_to_be32(n * sizeof (struct 
srp_direct_buf));
 
-                       len = sizeof (struct srp_cmd) +
-                               sizeof (struct srp_indirect_buf) +
-                               n * sizeof (struct srp_direct_buf);
+                               buf->len = cpu_to_be32(datalen);
+       
+                               len = sizeof (struct srp_cmd) +
+                                       sizeof (struct srp_indirect_buf) +
+                                       n * sizeof (struct srp_direct_buf);
+                       }
                }
        } else {
                struct srp_direct_buf *buf = (void *) cmd->add_data;
@@ -606,6 +736,8 @@ static int srp_map_data(struct scsi_cmnd
                        return -EINVAL;
                }
 
+               pci_unmap_addr_set(req, direct_mapping, dma);
+
                buf->va  = cpu_to_be64(dma);
                buf->key = cpu_to_be32(target->srp_host->mr->rkey);
                buf->len = cpu_to_be32(scmnd->request_bufflen);
@@ -626,7 +758,7 @@ static int srp_map_data(struct scsi_cmnd
 
 static void srp_unmap_data(struct scsi_cmnd *scmnd,
                           struct srp_target_port *target,
-                          struct srp_cmd *cmd)
+                          struct srp_request *req)
 {
        if (!scmnd->request_buffer ||
            (scmnd->sc_data_direction != DMA_TO_DEVICE &&
@@ -639,7 +771,7 @@ static void srp_unmap_data(struct scsi_c
                             scmnd->use_sg, scmnd->sc_data_direction);
        else
                dma_unmap_single(target->srp_host->dev->dma_device,
-                                be64_to_cpu(((struct srp_direct_buf *) 
cmd->add_data)->va),
+                                pci_unmap_addr(req, direct_mapping),
                                 scmnd->request_bufflen,
                                 scmnd->sc_data_direction);
 }
@@ -648,7 +780,6 @@ static void srp_process_rsp(struct srp_t
 {
        struct srp_request *req;
        struct scsi_cmnd *scmnd;
-       struct srp_iu *iu;
        unsigned long flags;
        s32 delta;
 
@@ -667,7 +798,6 @@ static void srp_process_rsp(struct srp_t
                        req->tsk_status = rsp->data[3];
                complete(&req->done);
        } else {
-               iu            = req->cmd;
                scmnd         = req->scmnd;
                scmnd->result = rsp->status;
 
@@ -683,7 +813,19 @@ static void srp_process_rsp(struct srp_t
                else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | 
SRP_RSP_FLAG_DIUNDER))
                        scmnd->resid = be32_to_cpu(rsp->data_in_res_cnt);
 
-               srp_unmap_data(scmnd, target, iu->buf);
+               if (req->fmr_arr) {
+                       struct srp_fmr *srp_fmr = req->fmr_arr;
+
+                       while (req->fmr_cnt) {
+                               ib_fmr_pool_unmap(srp_fmr->mem);
+                               ++srp_fmr;
+                               --req->fmr_cnt;
+                       }
+                       kfree(req->fmr_arr);
+                       req->fmr_arr = NULL;
+               }
+
+               srp_unmap_data(scmnd, target, req);
 
                if (!req->tsk_mgmt) {
                        req->scmnd = NULL;
@@ -919,7 +1061,7 @@ static int srp_queuecommand(struct scsi_
        req->cmd_done = 0;
        req->tsk_mgmt = NULL;
 
-       len = srp_map_data(scmnd, target, iu);
+       len = srp_map_data(scmnd, target, req);
        if (len < 0) {
                printk(KERN_ERR PFX "Failed to map data\n");
                goto err;
@@ -944,7 +1086,19 @@ static int srp_queuecommand(struct scsi_
        return 0;
 
 err_unmap:
-       srp_unmap_data(scmnd, target, cmd);
+       if (req->fmr_arr) {
+               struct srp_fmr *srp_fmr = req->fmr_arr;
+
+               while (req->fmr_cnt) {
+                       ib_fmr_pool_unmap(srp_fmr->mem);
+                       ++srp_fmr;
+                       --req->fmr_cnt;
+               }
+               kfree(req->fmr_arr);
+               req->fmr_arr = NULL;
+       }
+
+       srp_unmap_data(scmnd, target, req);
 
 err:
        return SCSI_MLQUEUE_HOST_BUSY;
@@ -1230,6 +1384,8 @@ static int srp_add_target(struct srp_hos
        sprintf(target->target_name, "SRP.T10:%016llX",
                 (unsigned long long) be64_to_cpu(target->id_ext));
 
+       target->scsi_host->max_lun = SRP_MAX_LUN;
+
        if (scsi_add_host(target->scsi_host, host->dev->dma_device))
                return -ENODEV;
 
@@ -1464,6 +1620,7 @@ err:
 static CLASS_DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target);
 
 static struct srp_host *srp_add_port(struct ib_device *device,
+                                    struct srp_device_data *srp_data,
                                     __be64 node_guid, u8 port)
 {
        struct srp_host *host;
@@ -1477,28 +1634,20 @@ static struct srp_host *srp_add_port(str
        init_completion(&host->released);
        host->dev  = device;
        host->port = port;
+       host->pd = srp_data->pd;
+       host->mr = srp_data->mr;
+       host->fmr_pool = srp_data->fmr_pool;
 
        host->initiator_port_id[7] = port;
        memcpy(host->initiator_port_id + 8, &node_guid, 8);
 
-       host->pd   = ib_alloc_pd(device);
-       if (IS_ERR(host->pd))
-               goto err_free;
-
-       host->mr   = ib_get_dma_mr(host->pd,
-                                  IB_ACCESS_LOCAL_WRITE |
-                                  IB_ACCESS_REMOTE_READ |
-                                  IB_ACCESS_REMOTE_WRITE);
-       if (IS_ERR(host->mr))
-               goto err_pd;
-
        host->class_dev.class = &srp_class;
        host->class_dev.dev   = device->dma_device;
        snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d",
                 device->name, port);
 
        if (class_device_register(&host->class_dev))
-               goto err_mr;
+               goto err_free;
        if (class_device_create_file(&host->class_dev, 
&class_device_attr_add_target))
                goto err_class;
        /* XXX ibdev / port files as well */
@@ -1508,12 +1657,6 @@ static struct srp_host *srp_add_port(str
 err_class:
        class_device_unregister(&host->class_dev);
 
-err_mr:
-       ib_dereg_mr(host->mr);
-
-err_pd:
-       ib_dealloc_pd(host->pd);
-
 err_free:
        kfree(host);
 
@@ -1522,10 +1665,11 @@ err_free:
 
 static void srp_add_one(struct ib_device *device)
 {
-       struct list_head *dev_list;
+       struct srp_device_data *srp_data;
        struct srp_host *host;
        struct ib_device_attr *dev_attr;
        int s, e, p;
+       struct ib_fmr_pool_param fmr_params;
 
        dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
        if (!dev_attr)
@@ -1534,14 +1678,41 @@ static void srp_add_one(struct ib_device
        if (ib_query_device(device, dev_attr)) {
                printk(KERN_WARNING PFX "Couldn't query node GUID for %s.\n",
                       device->name);
-               goto out;
+               goto free_attr;
        }
 
-       dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
-       if (!dev_list)
-               goto out;
+       srp_data = kmalloc(sizeof *srp_data, GFP_KERNEL); 
+       if (!srp_data)
+               goto free_attr;
+
+       srp_data->dev_list = kmalloc(sizeof *srp_data->dev_list, GFP_KERNEL);
+       if (!srp_data->dev_list)
+               goto free_params_attr;
+
+       INIT_LIST_HEAD(srp_data->dev_list);
+
+       srp_data->pd   = ib_alloc_pd(device);
+       if (IS_ERR(srp_data->pd))
+               goto free_all;
+
+       srp_data->mr   = ib_get_dma_mr(srp_data->pd,
+                                        IB_ACCESS_LOCAL_WRITE |
+                                        IB_ACCESS_REMOTE_READ |
+                                        IB_ACCESS_REMOTE_WRITE);
+       if (IS_ERR(srp_data->mr))
+               goto err_pd;
 
-       INIT_LIST_HEAD(dev_list);
+       memset(&fmr_params, 0, sizeof fmr_params);
+       fmr_params.pool_size = SRP_FMR_POOL_SIZE;
+       fmr_params.dirty_watermark = SRP_FMR_DIRTY_SIZE;
+       fmr_params.cache = 0;
+       fmr_params.max_pages_per_fmr = SRP_MAX_SECTORS * 512 / PAGE_SIZE;
+       fmr_params.access = (IB_ACCESS_LOCAL_WRITE |
+                            IB_ACCESS_REMOTE_WRITE |
+                            IB_ACCESS_REMOTE_READ);
+       srp_data->fmr_pool = ib_create_fmr_pool(srp_data->pd, &fmr_params);
+       if (IS_ERR(srp_data->fmr_pool))
+               goto err_mr;
 
        if (device->node_type == IB_NODE_SWITCH) {
                s = 0;
@@ -1552,28 +1723,38 @@ static void srp_add_one(struct ib_device
        }
 
        for (p = s; p <= e; ++p) {
-               host = srp_add_port(device, dev_attr->node_guid, p);
+               host = srp_add_port(device, srp_data, dev_attr->node_guid, p);
                if (host)
-                       list_add_tail(&host->list, dev_list);
+                       list_add_tail(&host->list, srp_data->dev_list);
        }
 
-       ib_set_client_data(device, &srp_client, dev_list);
+       ib_set_client_data(device, &srp_client, srp_data);
 
-out:
+       goto free_attr;
+
+err_mr:
+       ib_dereg_mr(srp_data->mr);
+err_pd:
+       ib_dealloc_pd(srp_data->pd);
+free_all:
+       kfree(srp_data->dev_list);
+free_params_attr:
+       kfree(srp_data);
+free_attr:
        kfree(dev_attr);
 }
 
 static void srp_remove_one(struct ib_device *device)
 {
-       struct list_head *dev_list;
+       struct srp_device_data *srp_data;
        struct srp_host *host, *tmp_host;
        LIST_HEAD(target_list);
        struct srp_target_port *target, *tmp_target;
        unsigned long flags;
 
-       dev_list = ib_get_client_data(device, &srp_client);
+       srp_data = ib_get_client_data(device, &srp_client);
 
-       list_for_each_entry_safe(host, tmp_host, dev_list, list) {
+       list_for_each_entry_safe(host, tmp_host, srp_data->dev_list, list) {
                class_device_unregister(&host->class_dev);
                /*
                 * Wait for the sysfs entry to go away, so that no new
@@ -1610,12 +1791,15 @@ static void srp_remove_one(struct ib_dev
                        scsi_host_put(target->scsi_host);
                }
 
-               ib_dereg_mr(host->mr);
-               ib_dealloc_pd(host->pd);
                kfree(host);
        }
 
-       kfree(dev_list);
+       ib_destroy_fmr_pool(srp_data->fmr_pool);
+       ib_dereg_mr(srp_data->mr);
+       ib_dealloc_pd(srp_data->pd);
+
+       kfree(srp_data->dev_list);
+       kfree(srp_data);
 }
 
 static int __init srp_init_module(void)
Index: ulp/srp/ib_srp.h
===================================================================
--- ulp/srp/ib_srp.h    (revision 3615)
+++ ulp/srp/ib_srp.h    (working copy)
@@ -46,6 +46,7 @@
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_sa.h>
 #include <rdma/ib_cm.h>
+#include <rdma/ib_fmr_pool.h>
 
 enum {
        SRP_PATH_REC_TIMEOUT_MS = 1000,
@@ -56,11 +57,17 @@ enum {
 
        SRP_MAX_IU_LEN          = 256,
 
+       SRP_MAX_LUN             = 512,
+       SRP_MAX_SECTORS         = 256,
+
        SRP_RQ_SHIFT            = 6,
        SRP_RQ_SIZE             = 1 << SRP_RQ_SHIFT,
        SRP_SQ_SIZE             = SRP_RQ_SIZE - 1,
        SRP_CQ_SIZE             = SRP_SQ_SIZE + SRP_RQ_SIZE,
 
+       SRP_FMR_POOL_SIZE       = 8192,
+       SRP_FMR_DIRTY_SIZE      = SRP_FMR_POOL_SIZE >> 4,
+
        SRP_TAG_TSK_MGMT        = 1 << (SRP_RQ_SHIFT + 1)
 };
 
@@ -76,6 +83,13 @@ enum srp_target_state {
        SRP_TARGET_REMOVED
 };
 
+struct srp_device_data {
+       struct list_head       *dev_list;
+       struct ib_pd           *pd;
+       struct ib_mr           *mr;
+       struct ib_fmr_pool     *fmr_pool;
+};
+       
 struct srp_host {
        u8                      initiator_port_id[16];
        struct ib_device       *dev;
@@ -87,6 +101,13 @@ struct srp_host {
        struct semaphore        target_mutex;
        struct completion       released;
        struct list_head        list;
+       struct ib_fmr_pool     *fmr_pool;
+};
+
+struct srp_fmr {
+       u64                     io_addr;
+       struct ib_pool_fmr     *mem;
+       u32                     len;
 };
 
 struct srp_request {
@@ -94,10 +115,14 @@ struct srp_request {
        struct scsi_cmnd       *scmnd;
        struct srp_iu          *cmd;
        struct srp_iu          *tsk_mgmt;
+       DECLARE_PCI_UNMAP_ADDR(direct_mapping)
        struct completion       done;
        short                   next;
        u8                      cmd_done;
        u8                      tsk_status;
+       struct srp_fmr         *fmr_arr;
+       u16                     fmr_cnt;
+       u16                     in_use;
 };
 
 struct srp_target_port {
_______________________________________________
openib-general mailing list
[email protected]
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to