Roland,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
