Is there any reason to make the IO virtual address of the FMR equal to
the local bus address?
No

If we made the IO address 0 all the time, then the code would be
simpler and there wouldn't even be a need for the io_addr member of
the structure.

It's a good idea. Here is the patch (this also does not have reformatting issue from previous patch)

Thanks,
Vu

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


Index: ib_srp.c
===================================================================
--- ib_srp.c	(revision 5918)
+++ ib_srp.c	(working copy)
@@ -500,13 +500,87 @@ 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;
+	int unaligned;
+
+	dma_pages = kmalloc(sizeof(u64) * sg_cnt * SRP_MAX_INDIRECT, GFP_ATOMIC);
+	if (!dma_pages)
+		goto err_dpages;	
+
+	srp_fmr = &req->s_fmr;
+	srp_fmr->len = 0;
+	page_cnt = 0;
+	cur_len = 0;
+	unaligned = 0;
+
+	/*
+	 * Walking the sg_list, group all aligned sg_entry to one fmr
+	 * If there is an unaligned sg_entry, fall back to dma_mr
+	 */
+	for (i = 0; i < sg_cnt; ++i, ++scat) {
+		dma_len = sg_dma_len(scat);
+		dma_addr = sg_dma_address(scat);
+
+		if (dma_addr & (PAGE_SIZE - 1))
+			++unaligned;
+
+		if ((dma_addr + dma_len) & (PAGE_SIZE - 1))
+			++unaligned;
+
+		/* 
+		 * Every FMR segment has atmost 1 unaligned element
+		 */
+		if (!unaligned) {
+			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;
+
+		} else
+			goto err_farr;
+
+		if (i == (sg_cnt - 1)) {
+			u64 io_addr = 0;
+
+			srp_fmr->mem =
+				ib_fmr_pool_map_phys(target->srp_host->fmr_pool,
+						     dma_pages, page_cnt,
+						     &io_addr);
+			if (IS_ERR(srp_fmr->mem))
+				goto err_farr;
+
+			srp_fmr->len = cur_len;
+		}
+	}
+
+	kfree(dma_pages);
+
+	return 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_request *req)
 {
 	struct scatterlist *scat;
 	struct srp_cmd *cmd = req->cmd->buf;
 	int len, nents, count;
-	int i;
 	u8 fmt;
 
 	if (!scmnd->request_buffer || scmnd->sc_data_direction == DMA_NONE)
@@ -532,8 +606,8 @@ static int srp_map_data(struct scsi_cmnd
 		sg_init_one(scat, scmnd->request_buffer, scmnd->request_bufflen);
 	}
 
-	count = dma_map_sg(target->srp_host->dev->dma_device, scat, nents,
-			   scmnd->sc_data_direction);
+	count = dma_map_sg(target->srp_host->dev->dma_device,
+			   scat, nents, scmnd->sc_data_direction);
 
 	if (count == 1) {
 		struct srp_direct_buf *buf = (void *) cmd->add_data;
@@ -550,6 +624,29 @@ static int srp_map_data(struct scsi_cmnd
 		struct srp_indirect_buf *buf = (void *) cmd->add_data;
 		u32 datalen = 0;
 
+		if (srp_map_fmr(target, scat, count, req)) {
+			int i;
+
+			/* fail map_fmr - use dma rkey */
+			for (i = 0; i < count; ++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 {
+			count = 1;
+			buf->desc_list[0].va = 0;
+			buf->desc_list[0].key =
+				cpu_to_be32(req->s_fmr.mem->fmr->rkey);
+			buf->desc_list[0].len =
+				cpu_to_be32(req->s_fmr.len);
+			datalen += req->s_fmr.len;
+		}
+	
 		fmt = SRP_DATA_DESC_INDIRECT;
 
 		if (scmnd->sc_data_direction == DMA_TO_DEVICE)
@@ -565,20 +662,11 @@ static int srp_map_data(struct scsi_cmnd
 		buf->table_desc.len =
 			cpu_to_be32(count * sizeof (struct srp_direct_buf));
 
-		for (i = 0; i < count; ++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]);
-		}
-
 		buf->len = cpu_to_be32(datalen);
 
 		len = sizeof (struct srp_cmd) +
-			sizeof (struct srp_indirect_buf) +
-			count * sizeof (struct srp_direct_buf);
+			      sizeof (struct srp_indirect_buf) +
+			      count * sizeof (struct srp_direct_buf);
 	}
 
 	if (scmnd->sc_data_direction == DMA_TO_DEVICE)
@@ -586,6 +674,7 @@ static int srp_map_data(struct scsi_cmnd
 	else
 		cmd->buf_fmt = fmt;
 
+
 	return len;
 }
 
@@ -599,7 +688,7 @@ static void srp_unmap_data(struct scsi_c
 	if (!scmnd->request_buffer ||
 	    (scmnd->sc_data_direction != DMA_TO_DEVICE &&
 	     scmnd->sc_data_direction != DMA_FROM_DEVICE))
-	    return;
+		return;
 
 	/*
 	 * This handling of non-SG commands can be killed when the
@@ -615,6 +704,11 @@ static void srp_unmap_data(struct scsi_c
 
 	dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents,
 		     scmnd->sc_data_direction);
+
+	if (req->s_fmr.len) {
+		ib_fmr_pool_unmap(req->s_fmr.mem);
+		req->s_fmr.len = 0;
+	}
 }
 
 static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
@@ -1322,6 +1416,7 @@ static struct scsi_host_template srp_tem
 	.can_queue			= SRP_SQ_SIZE,
 	.this_id			= -1,
 	.sg_tablesize			= SRP_MAX_INDIRECT,
+	.max_sectors			= SRP_MAX_SECTORS,
 	.cmd_per_lun			= SRP_SQ_SIZE,
 	.use_clustering			= ENABLE_CLUSTERING,
 	.shost_attrs			= srp_host_attrs
@@ -1463,7 +1558,7 @@ static int srp_parse_options(const char 
 				printk(KERN_WARNING PFX "bad max sect parameter '%s'\n", p);
 				goto out;
 			}
-			target->scsi_host->max_sectors = token;
+			target->scsi_host->max_sectors = min(token, SRP_MAX_SECTORS);
 			break;
 
 		default:
@@ -1513,8 +1608,10 @@ static ssize_t srp_create_target(struct 
 
 	INIT_WORK(&target->work, srp_reconnect_work, target);
 
-	for (i = 0; i < SRP_SQ_SIZE - 1; ++i)
+	for (i = 0; i < SRP_SQ_SIZE - 1; ++i) {
+		memset(&target->req_ring[i].s_fmr, 0, sizeof(struct srp_fmr));
 		target->req_ring[i].next = i + 1;
+	}
 	target->req_ring[SRP_SQ_SIZE - 1].next = -1;
 	INIT_LIST_HEAD(&target->req_queue);
 
@@ -1598,7 +1695,8 @@ static ssize_t show_port(struct class_de
 
 static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
 
-static struct srp_host *srp_add_port(struct ib_device *device, u8 port)
+static struct srp_host *srp_add_port(struct ib_device *device,
+				     struct srp_dev_data *dev_data, u8 port)
 {
 	struct srp_host *host;
 
@@ -1615,16 +1713,9 @@ static struct srp_host *srp_add_port(str
 	host->initiator_port_id[7] = port;
 	memcpy(host->initiator_port_id + 8, &device->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->pd = dev_data->pd;
+	host->mr = dev_data->mr;
+	host->fmr_pool = dev_data->fmr_pool;
 
 	host->class_dev.class = &srp_class;
 	host->class_dev.dev   = device->dma_device;
@@ -1632,7 +1723,7 @@ static struct srp_host *srp_add_port(str
 		 device->name, port);
 
 	if (class_device_register(&host->class_dev))
-		goto err_mr;
+		goto free_host;
 	if (class_device_create_file(&host->class_dev, &class_device_attr_add_target))
 		goto err_class;
 	if (class_device_create_file(&host->class_dev, &class_device_attr_ibdev))
@@ -1645,13 +1736,7 @@ 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:
+free_host:
 	kfree(host);
 
 	return NULL;
@@ -1659,18 +1744,55 @@ err_free:
 
 static void srp_add_one(struct ib_device *device)
 {
-	struct list_head *dev_list;
+	struct srp_dev_data *dev_data;
+	struct ib_device_attr *dev_attr;
+	struct ib_fmr_pool_param fmr_param;
 	struct srp_host *host;
 	int s, e, p;
 
 	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
 		return;
 
-	dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
-	if (!dev_list)
+	dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
+	if (!dev_attr)
 		return;
 
-	INIT_LIST_HEAD(dev_list);
+	if (ib_query_device(device, dev_attr)) {
+		printk(KERN_WARNING PFX "Query device failed for %s\n",
+		       device->name);
+		goto free_attr;
+	}
+
+	dev_data = kmalloc(sizeof *dev_data, GFP_KERNEL);
+	if (!dev_data)
+		goto free_attr;
+
+	INIT_LIST_HEAD(&dev_data->dev_list);
+
+	dev_data->pd = ib_alloc_pd(device);
+	if (IS_ERR(dev_data->pd))
+		goto free_dev;
+
+	dev_data->mr = ib_get_dma_mr(dev_data->pd,
+				     IB_ACCESS_LOCAL_WRITE |
+				     IB_ACCESS_REMOTE_READ |
+				     IB_ACCESS_REMOTE_WRITE);
+	if (IS_ERR(dev_data->mr))
+		goto err_pd;
+
+	memset(&fmr_param, 0, sizeof fmr_param);
+	fmr_param.pool_size = SRP_FMR_POOL_SIZE;
+	fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE;
+	fmr_param.cache = 0;
+	fmr_param.max_pages_per_fmr = SRP_MAX_SECTORS * 512 / PAGE_SIZE;
+	fmr_param.page_shift = PAGE_SHIFT;
+	fmr_param.access = (IB_ACCESS_LOCAL_WRITE |
+			     IB_ACCESS_REMOTE_WRITE |
+			     IB_ACCESS_REMOTE_READ);
+
+	dev_data->fmr_pool = ib_create_fmr_pool(dev_data->pd, &fmr_param);
+	if (IS_ERR(dev_data->fmr_pool))
+		goto err_mr;
 
 	if (device->node_type == RDMA_NODE_IB_SWITCH) {
 		s = 0;
@@ -1681,25 +1803,36 @@ static void srp_add_one(struct ib_device
 	}
 
 	for (p = s; p <= e; ++p) {
-		host = srp_add_port(device, p);
+		host = srp_add_port(device, dev_data, p);
 		if (host)
-			list_add_tail(&host->list, dev_list);
+			list_add_tail(&host->list, &dev_data->dev_list);
 	}
 
-	ib_set_client_data(device, &srp_client, dev_list);
+	ib_set_client_data(device, &srp_client, dev_data);
+
+	goto free_attr;
+
+err_mr:
+	ib_dereg_mr(dev_data->mr);
+err_pd:
+	ib_dealloc_pd(dev_data->pd);
+free_dev:
+	kfree(dev_data);
+free_attr:
+	kfree(dev_attr);
 }
 
 static void srp_remove_one(struct ib_device *device)
 {
-	struct list_head *dev_list;
+	struct srp_dev_data *dev_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);
+	dev_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, &dev_data->dev_list, list) {
 		class_device_unregister(&host->class_dev);
 		/*
 		 * Wait for the sysfs entry to go away, so that no new
@@ -1737,12 +1870,13 @@ 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(dev_data->fmr_pool);
+	ib_dereg_mr(dev_data->mr);
+	ib_dealloc_pd(dev_data->pd);
+	kfree(dev_data);
 }
 
 static int __init srp_init_module(void)
Index: ib_srp.h
===================================================================
--- ib_srp.h	(revision 5918)
+++ ib_srp.h	(working copy)
@@ -53,6 +53,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,
@@ -63,13 +64,17 @@ enum {
 
 	SRP_MAX_LUN		= 512,
 	SRP_MAX_IU_LEN		= 256,
+	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_TAG_TSK_MGMT	= 1 << (SRP_RQ_SHIFT + 1)
+	SRP_TAG_TSK_MGMT	= 1 << (SRP_RQ_SHIFT + 1),
+
+	SRP_FMR_POOL_SIZE	= 2048,
+	SRP_FMR_DIRTY_SIZE	= SRP_FMR_POOL_SIZE >> 4
 };
 
 #define SRP_OP_RECV		(1 << 31)
@@ -84,17 +89,30 @@ enum srp_target_state {
 	SRP_TARGET_REMOVED
 };
 
+struct srp_dev_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;
-	u8                      port;
+	u8			port;
 	struct ib_pd	       *pd;
 	struct ib_mr	       *mr;
 	struct class_device	class_dev;
 	struct list_head	target_list;
-	struct mutex            target_mutex;
+	struct mutex		target_mutex;
 	struct completion	released;
 	struct list_head	list;
+	struct ib_fmr_pool	*fmr_pool;
+};
+
+struct srp_fmr {
+	struct ib_pool_fmr	*mem;
+	u32			len;
 };
 
 struct srp_request {
@@ -111,6 +129,7 @@ struct srp_request {
 	short			next;
 	u8			cmd_done;
 	u8			tsk_status;
+	struct srp_fmr		s_fmr;
 };
 
 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