[openib-general] [PATCH 5/10] Implementation of Data path of the communication protocol

Ramachandra K rkuchimanchi at silverstorm.com
Mon Oct 2 13:06:56 PDT 2006


Adds the files that implement the data transfer part of the
communication protocol with the VEx. The RDMA of ethernet
packets is implemented in here.

Signed-off-by: Ramachandra K <rkuchimanchi at silverstorm.com>
---

 drivers/infiniband/ulp/vnic/vnic_data.c    | 1065 ++++++++++++++++++++++++++++
 drivers/infiniband/ulp/vnic/vnic_data.h    |  179 +++++
 drivers/infiniband/ulp/vnic/vnic_trailer.h |   63 ++
 3 files changed, 1307 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/ulp/vnic/vnic_data.c b/drivers/infiniband/ulp/vnic/vnic_data.c
new file mode 100644
index 0000000..e3b9739
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_data.c
@@ -0,0 +1,1065 @@
+/*
+ * Copyright (c) 2006 SilverStorm Technologies Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <net/inet_sock.h>
+#include <linux/ip.h>
+
+#include "vnic_util.h"
+#include "vnic_viport.h"
+#include "vnic_config.h"
+#include "vnic_data.h"
+#include "vnic_trailer.h"
+
+static void data_received_kick(struct io *io);
+static void data_xmit_complete(struct io *io);
+
+#define LOCAL_IO(x) PTR64((x))
+
+#define INBOUND_COPY
+
+#ifdef INBOUND_COPY
+u32 min_rcv_skb = 60;
+module_param(min_rcv_skb, int, 0444);
+#endif
+
+u32 min_xmt_skb = 60;
+module_param(min_xmt_skb, int, 0444);
+
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+cycles_t recv_ref;
+#endif	/* CONFIG_INFINIBAND_VNIC_STATS */
+
+BOOLEAN data_init(struct data * data, struct viport * viport,
+		  struct data_config * config, struct ib_pd *pd, u64 guid)
+{
+	DATA_FUNCTION("data_init()\n");
+
+	data->parent = viport;
+	data->config = config;
+	data->ib_conn.viport = viport;
+	data->ib_conn.ib_config = &config->ib_config;
+	data->ib_conn.state = IB_CONN_UNINITTED;
+
+	if ((min_xmt_skb < 60) || (min_xmt_skb > 9000)) {
+		DATA_ERROR("min_xmt_skb (%d) must be between 60 and 9000\n",
+			   min_xmt_skb);
+		goto failure;
+	}
+	if (!vnic_ib_conn_init(&data->ib_conn, viport, pd, guid,
+			       &config->ib_config)) {
+		goto failure;
+	}
+	data->mr = ib_get_dma_mr(pd,
+				 IB_ACCESS_LOCAL_WRITE |
+				 IB_ACCESS_REMOTE_READ |
+				 IB_ACCESS_REMOTE_WRITE);
+	if (IS_ERR(data->mr)) {
+		DATA_ERROR("failed to register memory for data connection\n");
+		goto destroy_conn;
+	}
+
+	data->ib_conn.cm_id = ib_create_cm_id(viport->config->ibdev,
+				      	      vnic_ib_cm_handler,
+					      &data->ib_conn);
+
+	if (IS_ERR(data->ib_conn.cm_id)) {
+		DATA_ERROR("creating data CM ID failed\n");
+		return FALSE;
+	}
+
+	return TRUE;
+
+destroy_conn:
+	ib_destroy_qp(data->ib_conn.qp);
+	ib_destroy_cq(data->ib_conn.cq);
+failure:
+	return FALSE;
+}
+
+static void data_post_recvs(struct data *data)
+{
+	unsigned long flags;
+
+	DATA_FUNCTION("data_post_recvs()\n");
+	spin_lock_irqsave(&data->recv_ios_lock, flags);
+	while (!list_empty(&data->recv_ios)) {
+		struct io *io = list_entry(data->recv_ios.next,
+					   struct io, list_ptrs);
+		struct recv_io *recv_io = (struct recv_io *)io;
+
+		list_del(&recv_io->io.list_ptrs);
+		spin_unlock_irqrestore(&data->recv_ios_lock, flags);
+		if (!vnic_ib_post_recv(&data->ib_conn, &recv_io->io)) {
+			viport_failure(data->parent);
+			return;
+		}
+		spin_lock_irqsave(&data->recv_ios_lock, flags);
+	}
+	spin_unlock_irqrestore(&data->recv_ios_lock, flags);
+}
+
+BOOLEAN data_connect(struct data * data)
+{
+	struct xmit_pool	*xmit_pool = &data->xmit_pool;
+	struct recv_pool	*recv_pool = &data->recv_pool;
+	struct recv_io		*recv_io;
+	struct send_io		*send_io;
+	struct rdma_io		*rdma_io;
+	struct rdma_dest	*rdma_dest;
+	u8 			*region_data = NULL;
+	int			sz;
+	unsigned int		i;
+	dma_addr_t		region_data_dma;
+	dma_addr_t		xmit_dma;
+	u8			*xmit_data;
+	struct viport		*viport = data->parent;
+
+	DATA_FUNCTION("data_connect()\n");
+
+	recv_pool->pool_sz = data->config->host_recv_pool_entries;
+	recv_pool->eioc_pool_sz = data->host_pool_parms.num_recv_pool_entries;
+	if (recv_pool->pool_sz > recv_pool->eioc_pool_sz)
+		recv_pool->pool_sz =
+		    data->host_pool_parms.num_recv_pool_entries;
+
+	xmit_pool->pool_sz = data->eioc_pool_parms.num_recv_pool_entries;
+
+	recv_pool->buffer_sz = data->host_pool_parms.size_recv_pool_entry;
+	xmit_pool->buffer_sz = data->eioc_pool_parms.size_recv_pool_entry;
+
+	xmit_pool->notify_count = 0;
+	xmit_pool->notify_bundle = data->config->notify_bundle;
+	xmit_pool->next_xmit_pool = 0;
+#ifdef LIMIT_OUTSTANDING_SENDS
+	xmit_pool->num_xmit_bufs = xmit_pool->notify_bundle * 2;
+#else	/* !LIMIT_OUTSTANDING_SENDS */
+	xmit_pool->num_xmit_bufs = xmit_pool->pool_sz;
+#endif	/* LIMIT_OUTSTANDING_SENDS */
+	xmit_pool->next_xmit_buf = 0;
+	xmit_pool->last_comp_buf = xmit_pool->num_xmit_bufs - 1;
+
+	recv_pool->sz_free_bundle =
+	    data->host_pool_parms.free_recv_pool_entries_per_update;
+	recv_pool->num_free_bufs = 0;
+	recv_pool->num_posted_bufs = 0;
+	xmit_pool->kick_count = 0;
+	xmit_pool->kick_byte_count = 0;
+
+	xmit_pool->send_kicks =
+	    data->eioc_pool_parms.num_recv_pool_entries_before_kick
+	    || data->eioc_pool_parms.num_recv_pool_bytes_before_kick;
+	xmit_pool->kick_bundle =
+	    data->eioc_pool_parms.num_recv_pool_entries_before_kick;
+	xmit_pool->kick_byte_bundle =
+	    data->eioc_pool_parms.num_recv_pool_bytes_before_kick;
+	recv_pool->next_full_buf = 0;
+	recv_pool->next_free_buf = 0;
+	recv_pool->kick_on_free = FALSE;
+
+	xmit_pool->need_buffers = TRUE;
+
+	sz = sizeof(struct rdma_dest) * recv_pool->pool_sz;
+	sz += sizeof(struct recv_io) * data->config->num_recvs;
+	sz += sizeof(struct rdma_io) * xmit_pool->num_xmit_bufs;
+
+	xmit_pool->xmitdata_len =
+	    BUFFER_SIZE(min_xmt_skb) * xmit_pool->num_xmit_bufs;
+	if ((data->local_storage = vmalloc(sz)) == NULL) {
+		DATA_ERROR("failed allocating %d bytes local storage\n", sz);
+		goto failure;
+	}
+
+	memset(data->local_storage, '\0', sz);
+
+	recv_pool->recv_bufs = (struct rdma_dest *)data->local_storage;
+	sz = sizeof(struct rdma_dest) * recv_pool->pool_sz;
+	recv_io = (struct recv_io *)(data->local_storage + sz);
+	sz += sizeof(struct recv_io) * data->config->num_recvs;
+	xmit_pool->xmit_bufs = (struct rdma_io *)(data->local_storage + sz);
+	sz += sizeof(struct rdma_io) * xmit_pool->num_xmit_bufs;
+
+	if ((region_data = kzalloc(4, GFP_KERNEL)) == NULL) {
+		DATA_ERROR("failed to alloc memory for region data\n");
+		goto failure;
+	}
+
+	data->region_data = region_data;
+
+	recv_pool->buf_pool_len =
+	    sizeof(struct buff_pool_entry) * recv_pool->eioc_pool_sz;
+	if ((recv_pool->buf_pool =
+	     kzalloc(recv_pool->buf_pool_len, GFP_KERNEL)) == NULL) {
+		DATA_ERROR("failed allocating %d bytes"
+			   " for recv pool bufpool\n",
+			   recv_pool->buf_pool_len);
+		goto failure;
+	}
+
+	recv_pool->buf_pool_dma =
+	    dma_map_single(viport->config->ibdev->dma_device,
+			   recv_pool->buf_pool, recv_pool->buf_pool_len,
+			   DMA_TO_DEVICE);
+
+	if (dma_mapping_error(recv_pool->buf_pool_dma)) {
+		DATA_ERROR("xmit buf_pool dma map error\n");
+		goto failure;
+	}
+
+	xmit_pool->buf_pool_len =
+	    sizeof(struct buff_pool_entry) * xmit_pool->pool_sz;
+	if ((xmit_pool->buf_pool =
+	     kzalloc(xmit_pool->buf_pool_len, GFP_KERNEL)) == NULL) {
+		DATA_ERROR("failed allocating %d bytes"
+			   " for xmit pool bufpool\n",
+			   xmit_pool->buf_pool_len);
+		goto failure;
+	}
+	xmit_pool->buf_pool_dma =
+	    dma_map_single(viport->config->ibdev->dma_device,
+			   xmit_pool->buf_pool, xmit_pool->buf_pool_len,
+			   DMA_FROM_DEVICE);
+
+	if (dma_mapping_error(xmit_pool->buf_pool_dma)) {
+		DATA_ERROR("xmit buf_pool dma map error\n");
+		goto failure;
+	}
+
+	if ((xmit_pool->xmit_data =
+	     kzalloc(xmit_pool->xmitdata_len, GFP_KERNEL)) == NULL) {
+		DATA_ERROR("failed allocating %d bytes for xmit data\n",
+			   xmit_pool->xmitdata_len);
+		goto failure;
+	}
+
+	xmit_pool->xmitdata_dma =
+	    dma_map_single(viport->config->ibdev->dma_device,
+			   xmit_pool->xmit_data, xmit_pool->xmitdata_len,
+			   DMA_TO_DEVICE);
+
+	if (dma_mapping_error(xmit_pool->xmitdata_dma)) {
+		DATA_ERROR("xmit data dma map error\n");
+		goto failure;
+	}
+
+	rdma_io = &data->free_bufs_io;
+	rdma_io->io.viport = data->parent;
+	rdma_io->io.routine = NULL;
+
+	rdma_io->list[0].lkey = data->mr->lkey;
+
+	rdma_io->io.swr.wr_id = (unsigned long)rdma_io;
+	rdma_io->io.swr.sg_list = rdma_io->list;
+	rdma_io->io.swr.num_sge = 1;
+	rdma_io->io.swr.opcode = IB_WR_RDMA_WRITE;
+	rdma_io->io.swr.send_flags = IB_SEND_SIGNALED;
+	rdma_io->io.type = RDMA;
+
+	send_io = &data->kick_io;
+	send_io->io.viport = data->parent;
+	send_io->io.routine = NULL;
+
+	region_data_dma = dma_map_single(viport->config->ibdev->dma_device,
+					 region_data, 4, DMA_BIDIRECTIONAL);
+
+	if (dma_mapping_error(region_data_dma)) {
+		DATA_ERROR("region data dma map error\n");
+		goto failure;
+	}
+
+	data->regiondata_dma = region_data_dma;
+
+	send_io->list.addr = region_data_dma;
+	send_io->list.length = 0;
+	send_io->list.lkey = data->mr->lkey;
+
+	send_io->io.swr.wr_id = (unsigned long)send_io;
+	send_io->io.swr.sg_list = &send_io->list;
+	send_io->io.swr.num_sge = 1;
+	send_io->io.swr.opcode = IB_WR_SEND;
+	send_io->io.swr.send_flags = IB_SEND_SIGNALED;
+	send_io->io.type = SEND;
+
+	INIT_LIST_HEAD(&data->recv_ios);
+	spin_lock_init(&data->recv_ios_lock);
+	spin_lock_init(&data->xmit_buf_lock);
+	for (i = 0; i < data->config->num_recvs; i++) {
+		recv_io[i].io.viport = data->parent;
+		recv_io[i].io.routine = data_received_kick;
+		recv_io[i].list.addr = region_data_dma;
+		recv_io[i].list.length = 4;
+		recv_io[i].list.lkey = data->mr->lkey;
+
+		recv_io[i].io.rwr.wr_id = PTR64(&recv_io[i].io);
+		recv_io[i].io.rwr.sg_list = &recv_io[i].list;
+		recv_io[i].io.rwr.num_sge = 1;
+
+		list_add(&recv_io[i].io.list_ptrs, &data->recv_ios);
+	}
+	INIT_LIST_HEAD(&recv_pool->avail_recv_bufs);
+	for (i = 0; i < recv_pool->pool_sz; i++) {
+		rdma_dest = &recv_pool->recv_bufs[i];
+		list_add(&rdma_dest->list_ptrs, &recv_pool->avail_recv_bufs);
+	}
+
+	xmit_dma = xmit_pool->xmitdata_dma;
+	xmit_data = xmit_pool->xmit_data;
+
+	for (i = 0; i < xmit_pool->num_xmit_bufs; i++) {
+		rdma_io = &xmit_pool->xmit_bufs[i];
+		rdma_io->index = i;
+		rdma_io->io.viport = data->parent;
+		rdma_io->io.routine = data_xmit_complete;
+
+		rdma_io->list[0].lkey = data->mr->lkey;
+		rdma_io->list[1].lkey = data->mr->lkey;
+		rdma_io->io.swr.wr_id = PTR64(rdma_io);
+		rdma_io->io.swr.sg_list = rdma_io->list;
+		rdma_io->io.swr.num_sge = 2;
+		rdma_io->io.swr.opcode = IB_WR_RDMA_WRITE;
+		rdma_io->io.swr.send_flags = IB_SEND_SIGNALED;
+		rdma_io->io.type = RDMA;
+
+		rdma_io->data = xmit_data;
+		rdma_io->data_dma = xmit_dma;
+
+		xmit_data += ROUNDUPP2(min_xmt_skb, VIPORT_TRAILER_ALIGNMENT);
+		xmit_dma += ROUNDUPP2(min_xmt_skb, VIPORT_TRAILER_ALIGNMENT);
+		rdma_io->trailer = (struct viport_trailer *)xmit_data;
+		rdma_io->trailer_dma = xmit_dma;
+		xmit_data += sizeof(struct viport_trailer);
+		xmit_dma += sizeof(struct viport_trailer);
+	}
+
+	xmit_pool->rdma_rkey = data->mr->rkey;
+	xmit_pool->rdma_addr = xmit_pool->buf_pool_dma;
+
+	data_post_recvs(data);
+
+	if (vnic_ib_cm_connect(&data->ib_conn))
+		return TRUE;
+failure:
+	if (data->local_storage) {
+		vfree(data->local_storage);
+	}
+
+	if (region_data)
+		kfree(region_data);
+
+	if (recv_pool->buf_pool)
+		kfree(recv_pool->buf_pool);
+
+	if (xmit_pool->buf_pool)
+		kfree(xmit_pool->buf_pool);
+
+	if (xmit_pool->xmit_data)
+		kfree(xmit_pool->xmit_data);
+
+	return FALSE;
+}
+
+static void data_add_free_buffer(struct data *data, int index,
+				 struct rdma_dest *rdma_dest)
+{
+	struct recv_pool *pool = &data->recv_pool;
+	struct buff_pool_entry *bpe;
+
+	DATA_FUNCTION("data_add_free_buffer()\n");
+	rdma_dest->trailer->connection_hash_and_valid = 0;
+	dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+				pool->buf_pool_dma, pool->buf_pool_len,
+				DMA_TO_DEVICE);
+
+	bpe = &pool->buf_pool[index];
+	bpe->r_key = hton32(data->mr->rkey);
+
+	bpe->remote_addr = hton64(PTR64(virt_to_phys(rdma_dest->data)));
+	bpe->valid = (u32) (rdma_dest - &pool->recv_bufs[0]) + 1;
+	++pool->num_free_bufs;
+
+	dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+				   pool->buf_pool_dma, pool->buf_pool_len,
+				   DMA_TO_DEVICE);
+	return;
+}
+
+/* NOTE: this routine is not reentrant */
+static void data_alloc_buffers(struct data *data, BOOLEAN initial_allocation)
+{
+	struct recv_pool *pool = &data->recv_pool;
+	struct rdma_dest *rdma_dest;
+	struct sk_buff *skb;
+	int index;
+
+	DATA_FUNCTION("data_alloc_buffers()\n");
+	index =
+	    ADD(pool->next_free_buf, pool->num_free_bufs, pool->eioc_pool_sz);
+	DATA_INFO("next_free_buf %x\n", pool->next_free_buf);
+	while (!list_empty(&pool->avail_recv_bufs)) {
+		rdma_dest =
+		    list_entry(pool->avail_recv_bufs.next, struct rdma_dest,
+			       list_ptrs);
+		if (!rdma_dest->skb) {
+			if (initial_allocation)
+				skb =
+				    alloc_skb(pool->buffer_sz + 2, GFP_KERNEL);
+			else
+				skb = dev_alloc_skb(pool->buffer_sz + 2);
+			if (skb == NULL) {
+				DATA_ERROR("failed to alloc skb\n");
+				break;
+			}
+			skb_reserve(skb, 2);
+			skb_put(skb, pool->buffer_sz);
+			rdma_dest->skb = skb;
+			rdma_dest->data = skb->data;
+			rdma_dest->trailer =
+			    (struct viport_trailer *)(rdma_dest->data +
+						      pool->buffer_sz -
+						      sizeof(struct
+							     viport_trailer));
+		}
+		rdma_dest->trailer->connection_hash_and_valid = 0;
+
+		list_del_init(&rdma_dest->list_ptrs);
+
+		data_add_free_buffer(data, index, rdma_dest);
+		index = NEXT(index, pool->eioc_pool_sz);
+	}
+	return;
+}
+
+static void data_send_kick_message(struct data *data)
+{
+	struct xmit_pool *pool = &data->xmit_pool;
+	DATA_FUNCTION("data_send_kick_message()\n");
+	/* stop timer for bundle_timeout */
+	if (data->kick_timer_on == TRUE) {
+		del_timer(&data->kick_timer);
+		data->kick_timer_on = FALSE;
+	}
+	pool->kick_count = 0;
+	pool->kick_byte_count = 0;
+
+	/* TBD: keep track of when kick is outstanding, and
+	 * don't reuse until complete
+	 */
+	if (!vnic_ib_post_send(&data->ib_conn, &data->free_bufs_io.io)) {
+		DATA_ERROR("failed to post send\n");
+		viport_failure(data->parent);
+		return;
+	}
+	return;
+}
+
+static void data_send_free_recv_buffers(struct data *data)
+{
+	struct recv_pool *pool = &data->recv_pool;
+	struct ib_send_wr *swr = &data->free_bufs_io.io.swr;
+
+	BOOLEAN bufs_sent = FALSE;
+	u64 rdma_addr;
+	u32 offset;
+	u32 sz;
+	unsigned int num_to_send, next_increment;
+
+	DATA_FUNCTION("data_send_free_recv_buffers()\n");
+
+	DATA_INFO("num_free_bufs %x sz_free_bundle %x\n",
+		  pool->num_free_bufs, pool->sz_free_bundle);
+
+	for (num_to_send = pool->sz_free_bundle;
+	     num_to_send <= pool->num_free_bufs;
+	     num_to_send += pool->sz_free_bundle) {
+		/* handle multiple bundles as one when possible. */
+		next_increment = num_to_send + pool->sz_free_bundle;
+		if ((next_increment <= pool->num_free_bufs)
+		    && (pool->next_free_buf + next_increment <=
+			pool->eioc_pool_sz)) {
+			continue;
+		}
+		offset = pool->next_free_buf * sizeof(struct buff_pool_entry);
+		sz = num_to_send * sizeof(struct buff_pool_entry);
+		rdma_addr = pool->eioc_rdma_addr + offset;
+		swr->sg_list->length = sz;
+		swr->sg_list->addr = pool->buf_pool_dma + offset;
+		swr->wr.rdma.remote_addr = rdma_addr;
+
+		if (!vnic_ib_post_send(&data->ib_conn,
+		    &data->free_bufs_io.io)) {
+			DATA_ERROR("failed to post send\n");
+			viport_failure(data->parent);
+			break;
+		}
+		INC(pool->next_free_buf, num_to_send, pool->eioc_pool_sz);
+		pool->num_free_bufs -= num_to_send;
+		pool->num_posted_bufs += num_to_send;
+		bufs_sent = TRUE;
+	}
+
+	if (bufs_sent) {
+		if (pool->kick_on_free) {
+			data_send_kick_message(data);
+		}
+	}
+	if (pool->num_posted_bufs == 0) {
+		DATA_ERROR("%s: unable to allocate receive buffers\n",
+			   config_viport_name(data->parent->config));
+		viport_failure(data->parent);
+	}
+	return;
+}
+
+void data_connected(struct data *data)
+{
+	DATA_FUNCTION("data_connected()\n");
+	data->free_bufs_io.io.swr.wr.rdma.rkey = data->recv_pool.eioc_rdma_rkey;
+	data_alloc_buffers(data, TRUE);
+	data_send_free_recv_buffers(data);
+	data->connected = TRUE;
+	return;
+}
+
+void data_disconnect(struct data *data)
+{
+	struct xmit_pool *xmit_pool = &data->xmit_pool;
+	struct recv_pool *recv_pool = &data->recv_pool;
+	u8 *region_data = data->region_data;
+	unsigned int i;
+
+	DATA_FUNCTION("data_disconnect()\n");
+
+	data->connected = FALSE;
+	if (data->kick_timer_on) {
+		del_timer_sync(&data->kick_timer);
+		data->kick_timer_on = FALSE;
+	}
+
+	for (i = 0; i < xmit_pool->num_xmit_bufs; i++) {
+		if (xmit_pool->xmit_bufs[i].skb)
+			dev_kfree_skb(xmit_pool->xmit_bufs[i].skb);
+		xmit_pool->xmit_bufs[i].skb = NULL;
+
+	}
+	for (i = 0; i < recv_pool->pool_sz; i++) {
+		if (data->recv_pool.recv_bufs[i].skb)
+			dev_kfree_skb(recv_pool->recv_bufs[i].skb);
+		recv_pool->recv_bufs[i].skb = NULL;
+	}
+	vfree(data->local_storage);
+	if (region_data) {
+		dma_unmap_single(data->parent->config->ibdev->dma_device,
+				 data->regiondata_dma, 4, DMA_BIDIRECTIONAL);
+		kfree(region_data);
+	}
+
+	if (recv_pool->buf_pool) {
+		dma_unmap_single(data->parent->config->ibdev->dma_device,
+				 recv_pool->buf_pool_dma,
+				 recv_pool->buf_pool_len, DMA_TO_DEVICE);
+		kfree(recv_pool->buf_pool);
+	}
+
+	if (xmit_pool->buf_pool) {
+		dma_unmap_single(data->parent->config->ibdev->dma_device,
+				 xmit_pool->buf_pool_dma,
+				 xmit_pool->buf_pool_len, DMA_FROM_DEVICE);
+		kfree(xmit_pool->buf_pool);
+	}
+
+	if (xmit_pool->xmit_data) {
+		dma_unmap_single(data->parent->config->ibdev->dma_device,
+				 xmit_pool->xmitdata_dma,
+				 xmit_pool->xmitdata_len, DMA_TO_DEVICE);
+		kfree(xmit_pool->xmit_data);
+	}
+
+	return;
+}
+
+void data_cleanup(struct data *data)
+{
+	init_completion(&data->ib_conn.done);
+	if (ib_send_cm_dreq(data->ib_conn.cm_id, NULL, 0)) {
+		printk(KERN_DEBUG "data CM DREQ sending failed\n");
+	} else
+		wait_for_completion(&data->ib_conn.done);
+
+	ib_destroy_cm_id(data->ib_conn.cm_id);
+
+	ib_destroy_qp(data->ib_conn.qp);
+
+	ib_destroy_cq(data->ib_conn.cq);
+	ib_dereg_mr(data->mr);
+
+}
+
+static BOOLEAN data_alloc_xmit_buffer(struct data *data, struct sk_buff *skb,
+				      struct buff_pool_entry **pp_bpe,
+				      struct rdma_io **pp_rdma_io,
+				      BOOLEAN * last)
+{
+	struct xmit_pool *pool = &data->xmit_pool;
+	unsigned long flags;
+
+	DATA_FUNCTION("data_alloc_xmit_buffer()\n");
+
+	spin_lock_irqsave(&data->xmit_buf_lock, flags);
+	dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+				pool->buf_pool_dma, pool->buf_pool_len,
+				DMA_TO_DEVICE);
+
+	*last = FALSE;
+	*pp_rdma_io = &pool->xmit_bufs[pool->next_xmit_buf];
+	*pp_bpe = &pool->buf_pool[pool->next_xmit_pool];
+
+	if ((*pp_bpe)->valid && pool->next_xmit_buf != pool->last_comp_buf) {
+		INC(pool->next_xmit_buf, 1, pool->num_xmit_bufs);
+		INC(pool->next_xmit_pool, 1, pool->pool_sz);
+		if (!pool->buf_pool[pool->next_xmit_pool].valid) {
+			DATA_INFO("just used the last EIOU receive buffer\n");
+			*last = TRUE;
+			pool->need_buffers = TRUE;
+			viport_stop_xmit(data->parent);
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+			data->statistics.kick_reqs++;
+#endif	/* CONFIG_INFINIBAND_VNIC_STATS */
+		} else if (pool->next_xmit_buf == pool->last_comp_buf) {
+			DATA_INFO("just used our last xmit buffer\n");
+			pool->need_buffers = TRUE;
+			viport_stop_xmit(data->parent);
+		}
+		(*pp_rdma_io)->skb = skb;
+		(*pp_bpe)->valid = 0;
+		spin_unlock_irqrestore(&data->xmit_buf_lock, flags);
+		return TRUE;
+	} else {
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+		data->statistics.no_xmit_bufs++;
+#endif	/* CONFIG_INFINIBAND_VNIC_STATS */
+		DATA_ERROR("Out of xmit buffers\n");
+		viport_stop_xmit(data->parent);
+		dma_sync_single_for_device(data->parent->config->ibdev->
+					   dma_device, pool->buf_pool_dma,
+					   pool->buf_pool_len, DMA_TO_DEVICE);
+
+		spin_unlock_irqrestore(&data->xmit_buf_lock, flags);
+		return FALSE;
+	}
+}
+
+static void data_rdma_packet(struct data *data, struct buff_pool_entry *bpe,
+			     struct rdma_io *rdma_io)
+{
+	struct ib_send_wr *swr;
+	struct sk_buff *skb;
+	u8 *d;
+	dma_addr_t trailer_data_dma;
+	dma_addr_t skb_data_dma;
+	int len;
+	int fill_len;
+	struct xmit_pool *xmit_pool = &data->xmit_pool;
+	struct viport *viport = data->parent;
+
+	DATA_FUNCTION("data_rdma_packet()\n");
+	swr = &rdma_io->io.swr;
+	skb = rdma_io->skb;
+	len = ROUNDUPP2(rdma_io->len, VIPORT_TRAILER_ALIGNMENT);
+	fill_len = len - skb->len;
+
+	dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+				xmit_pool->xmitdata_dma,
+				xmit_pool->xmitdata_len, DMA_TO_DEVICE);
+
+	d = (u8 *) rdma_io->trailer - fill_len;
+	trailer_data_dma = rdma_io->trailer_dma - fill_len;
+	memset(d, '\0', fill_len);
+
+	swr->sg_list[0].length = skb->len;
+	if (skb->len <= min_xmt_skb) {
+		memcpy(rdma_io->data, skb->data, skb->len);
+		swr->sg_list[0].lkey = data->mr->lkey;
+		swr->sg_list[0].addr = rdma_io->data_dma;
+		dev_kfree_skb_any(skb);
+		rdma_io->skb = NULL;
+	} else {
+		swr->sg_list[0].lkey = data->mr->lkey;
+
+		skb_data_dma = dma_map_single(viport->config->ibdev->dma_device,
+					      skb->data, skb->len,
+					      DMA_TO_DEVICE);
+
+		if (dma_mapping_error(skb_data_dma)) {
+			DATA_ERROR("skb data dma map error\n");
+			return;
+		}
+
+		rdma_io->skb_data_dma = skb_data_dma;
+
+		swr->sg_list[0].addr = skb_data_dma;
+		skb_orphan(skb);
+	}
+	dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+				xmit_pool->buf_pool_dma,
+				xmit_pool->buf_pool_len, DMA_TO_DEVICE);
+
+	swr->sg_list[1].addr = trailer_data_dma;
+	swr->sg_list[1].length = fill_len + sizeof(struct viport_trailer);
+	swr->sg_list[0].lkey = data->mr->lkey;
+	swr->wr.rdma.remote_addr = ntoh64(bpe->remote_addr);
+	swr->wr.rdma.remote_addr += data->xmit_pool.buffer_sz;
+	swr->wr.rdma.remote_addr -= (sizeof(struct viport_trailer) + len);
+	swr->wr.rdma.rkey = ntoh32(bpe->r_key);
+
+	dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+				   xmit_pool->buf_pool_dma,
+				   xmit_pool->buf_pool_len, DMA_TO_DEVICE);
+
+	data->xmit_pool.notify_count++;
+	if (data->xmit_pool.notify_count >= data->xmit_pool.notify_bundle) {
+		data->xmit_pool.notify_count = 0;
+		swr->send_flags = IB_SEND_SIGNALED;
+	} else {
+		swr->send_flags = 0;
+	}
+	dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+				   xmit_pool->xmitdata_dma,
+				   xmit_pool->xmitdata_len, DMA_TO_DEVICE);
+	if (!vnic_ib_post_send(&data->ib_conn, &rdma_io->io)) {
+		DATA_ERROR("failed to post send for data RDMA write\n");
+		viport_failure(data->parent);
+		return;
+	}
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+	data->statistics.xmit_num++;
+#endif	/* CONFIG_INFINIBAND_VNIC_STATS */
+	return;
+}
+
+static void data_kick_timeout_handler(unsigned long arg)
+{
+	struct data *data = (struct data *)arg;
+
+	DATA_FUNCTION("data_kick_timeout_handler()\n");
+	data->kick_timer_on = FALSE;
+	data_send_kick_message(data);
+	return;
+}
+
+BOOLEAN data_xmit_packet(struct data *data, struct sk_buff *skb)
+{
+	struct xmit_pool *pool = &data->xmit_pool;
+	struct rdma_io *rdma_io;
+	struct buff_pool_entry *bpe;
+	struct viport_trailer *trailer;
+	BOOLEAN last;
+	unsigned int sz = skb->len;
+
+	DATA_FUNCTION("data_xmit_packet()\n");
+	if (sz > pool->buffer_sz) {
+		DATA_ERROR("outbound packet too large, size = %d\n", sz);
+		return FALSE;
+	}
+
+	if (!data_alloc_xmit_buffer(data, skb, &bpe, &rdma_io, &last)) {
+		DATA_ERROR("error in allocating data xmit buffer\n");
+		return FALSE;
+	}
+
+	dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+				pool->xmitdata_dma, pool->xmitdata_len,
+				DMA_TO_DEVICE);
+
+	trailer = rdma_io->trailer;
+
+	memset(trailer, '\0', sizeof(struct viport_trailer));
+	memcpy(trailer->dest_mac_addr, skb->data, ETH_ALEN);
+	if (skb->sk)
+		trailer->connection_hash_and_valid =
+		    0x40 | ((get_sksport(skb->sk) + get_skdport(skb->sk)) &
+			    0x3f);
+	trailer->connection_hash_and_valid |= hton8(CHV_VALID);
+	if ((sz > 16) && (*(u16 *) (skb->data + 12) == hton16(0x8100))) {
+		trailer->vlan = *(u16 *) (skb->data + 14);
+		memmove(skb->data + 4, skb->data, 12);
+		skb_pull(skb, 4);
+		trailer->pkt_flags |= PF_VLAN_INSERT;
+	}
+	if (last)
+		trailer->pkt_flags |= PF_KICK;
+	if (sz < 60) {
+		/* EIOU requires all packets to be
+		 * of ethernet minimum packet size.
+		 */
+		trailer->data_length = hton16(60);
+		rdma_io->len = 60;
+	} else {
+		trailer->data_length = hton16(sz);
+		rdma_io->len = sz;
+	}
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		trailer->tx_chksum_flags = TX_CHKSUM_FLAGS_CHECKSUM_V4
+		    | TX_CHKSUM_FLAGS_IP_CHECKSUM
+		    | TX_CHKSUM_FLAGS_TCP_CHECKSUM
+		    | TX_CHKSUM_FLAGS_UDP_CHECKSUM;
+	}
+
+	dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+				   pool->xmitdata_dma, pool->xmitdata_len,
+				   DMA_TO_DEVICE);
+
+	data_rdma_packet(data, bpe, rdma_io);
+
+	if (pool->send_kicks) {
+		/* EIOC needs kicks to inform it of sent packets */
+		pool->kick_count++;
+		pool->kick_byte_count += sz;
+		if ((pool->kick_count >= pool->kick_bundle)
+		    || (pool->kick_byte_count >= pool->kick_byte_bundle)) {
+			data_send_kick_message(data);
+		} else if (pool->kick_count == 1) {
+			init_timer(&data->kick_timer);
+			/* timeout_before_kick is in u_sec */
+			data->kick_timer.expires =
+			    (data->eioc_pool_parms.timeout_before_kick * HZ /
+			     1000000) + jiffies;
+			data->kick_timer.data = (unsigned long)data;
+			data->kick_timer.function = data_kick_timeout_handler;
+			add_timer(&data->kick_timer);
+			data->kick_timer_on = TRUE;
+		}
+	}
+	return TRUE;
+}
+
+static void data_check_xmit_buffers(struct data *data)
+{
+	struct xmit_pool *pool = &data->xmit_pool;
+	unsigned long flags;
+
+	DATA_FUNCTION("data_check_xmit_buffers()\n");
+	spin_lock_irqsave(&data->xmit_buf_lock, flags);
+	dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+				pool->buf_pool_dma, pool->buf_pool_len,
+				DMA_TO_DEVICE);
+
+	if (data->xmit_pool.need_buffers
+	    && pool->buf_pool[pool->next_xmit_pool].valid
+	    && pool->next_xmit_buf != pool->last_comp_buf) {
+		data->xmit_pool.need_buffers = FALSE;
+		viport_restart_xmit(data->parent);
+		DATA_INFO("there are free xmit buffers\n");
+	}
+	dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+				   pool->buf_pool_dma, pool->buf_pool_len,
+				   DMA_TO_DEVICE);
+
+	spin_unlock_irqrestore(&data->xmit_buf_lock, flags);
+	return;
+}
+
+static struct sk_buff *data_recv_to_skbuff(struct data *data,
+					   struct rdma_dest *rdma_dest)
+{
+	struct viport_trailer *trailer;
+	struct sk_buff *skb;
+	int start;
+	unsigned int len;
+	u8 rx_chksum_flags;
+
+	DATA_FUNCTION("data_recv_to_skbuff()\n");
+	trailer = rdma_dest->trailer;
+	start = data_offset(data, trailer);
+	len = data_len(data, trailer);
+#ifdef INBOUND_COPY
+	if (len <= min_rcv_skb) {
+		/* leave room for VLAN header */
+		skb = dev_alloc_skb(len + 6);
+		if (!skb)
+			goto no_copy;
+		skb_reserve(skb, 6);
+		memcpy(skb->data, rdma_dest->data + start, len);
+		skb_put(skb, len);
+	} else
+#endif
+	{
+no_copy:
+		skb = rdma_dest->skb;
+		rdma_dest->skb = NULL;
+		rdma_dest->trailer = NULL;
+		rdma_dest->data = NULL;
+		skb_pull(skb, start);
+		skb_trim(skb, len);
+	}
+
+	rx_chksum_flags = trailer->rx_chksum_flags;
+	DATA_INFO
+	    ("rx_chksum_flags = %d, LOOP = %c, IP = %c, TCP = %c, UDP = %c\n",
+	     rx_chksum_flags,
+	     (rx_chksum_flags & RX_CHKSUM_FLAGS_LOOPBACK) ? 'Y' : 'N',
+	     (rx_chksum_flags & RX_CHKSUM_FLAGS_IP_CHECKSUM_SUCCEEDED) ? 'Y'
+	     : (rx_chksum_flags & RX_CHKSUM_FLAGS_IP_CHECKSUM_FAILED) ? 'N' :
+	     '-',
+	     (rx_chksum_flags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED) ? 'Y'
+	     : (rx_chksum_flags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_FAILED) ? 'N' :
+	     '-',
+	     (rx_chksum_flags & RX_CHKSUM_FLAGS_UDP_CHECKSUM_SUCCEEDED) ? 'Y'
+	     : (rx_chksum_flags & RX_CHKSUM_FLAGS_UDP_CHECKSUM_FAILED) ? 'N' :
+	     '-');
+
+	if ((rx_chksum_flags & RX_CHKSUM_FLAGS_LOOPBACK)
+	    || ((rx_chksum_flags & RX_CHKSUM_FLAGS_IP_CHECKSUM_SUCCEEDED)
+		&& ((rx_chksum_flags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED)
+		    || (rx_chksum_flags &
+			RX_CHKSUM_FLAGS_UDP_CHECKSUM_SUCCEEDED))))
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	else
+		skb->ip_summed = CHECKSUM_NONE;
+	if (trailer->pkt_flags & PF_VLAN_INSERT) {
+		u8 *rv;
+
+		rv = skb_push(skb, 4);
+		memmove(rv, rv + 4, 12);
+		*(u16 *) (rv + 12) = hton16(0x8100);
+		if (trailer->pkt_flags & PF_PVID_OVERRIDDEN) {
+			*(u16 *) (rv + 14) = trailer->vlan & hton16(0xF000);
+		} else {
+			*(u16 *) (rv + 14) = trailer->vlan;
+		}
+	}
+
+	return skb;
+}
+
+static BOOLEAN data_incoming_recv(struct data *data)
+{
+	struct recv_pool *pool = &data->recv_pool;
+	struct rdma_dest *rdma_dest;
+	struct viport_trailer *trailer;
+	struct buff_pool_entry *bpe;
+	struct sk_buff *skb;
+
+	DATA_FUNCTION("data_incoming_recv()\n");
+	if (pool->next_full_buf == pool->next_free_buf)
+		return FALSE;
+	bpe = &pool->buf_pool[pool->next_full_buf];
+	rdma_dest = &pool->recv_bufs[bpe->valid - 1];
+	trailer = rdma_dest->trailer;
+	if ((trailer != NULL)
+	    && (trailer->connection_hash_and_valid & CHV_VALID)) {
+		/* received a packet */
+		if (trailer->pkt_flags & PF_KICK) {
+			pool->kick_on_free = TRUE;
+		}
+		if ((skb = data_recv_to_skbuff(data, rdma_dest)) != NULL) {
+			viport_recv_packet(data->parent, skb);
+			list_add(&rdma_dest->list_ptrs, &pool->avail_recv_bufs);
+		}
+		dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+					pool->buf_pool_dma, pool->buf_pool_len,
+					DMA_TO_DEVICE);
+
+		bpe->valid = 0;
+		dma_sync_single_for_device(data->parent->config->ibdev->
+					   dma_device, pool->buf_pool_dma,
+					   pool->buf_pool_len, DMA_TO_DEVICE);
+
+		INC(pool->next_full_buf, 1, pool->eioc_pool_sz);
+		pool->num_posted_bufs--;
+
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+		data->statistics.recv_num++;
+#endif	/* CONFIG_INFINIBAND_VNIC_STATS */
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
+static void data_received_kick(struct io *io)
+{
+	struct data *data = &io->viport->data;
+	unsigned long flags;
+
+	DATA_FUNCTION("data_received_kick()\n");
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+	recv_ref = get_cycles();
+#endif				/* CONFIG_INFINIBAND_VNIC_STATS */
+
+	spin_lock_irqsave(&data->recv_ios_lock, flags);
+	list_add(&io->list_ptrs, &data->recv_ios);
+	spin_unlock_irqrestore(&data->recv_ios_lock, flags);
+	data_post_recvs(data);
+
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+	data->statistics.kick_recvs++;
+#endif				/* CONFIG_INFINIBAND_VNIC_STATS */
+
+	data_check_xmit_buffers(data);
+
+	while (data_incoming_recv(data)) ;
+	if (data->connected == TRUE) {
+		data_alloc_buffers(data, FALSE);
+		data_send_free_recv_buffers(data);
+	}
+	return;
+}
+
+static void data_xmit_complete(struct io *io)
+{
+	struct rdma_io *rdma_io = (struct rdma_io *)io;
+	struct data *data = &io->viport->data;
+	struct xmit_pool *pool = &data->xmit_pool;
+	struct sk_buff *skb;
+
+	DATA_FUNCTION("data_xmit_complete()\n");
+
+	if (rdma_io->skb) {
+		dma_unmap_single(data->parent->config->ibdev->dma_device,
+				 rdma_io->skb_data_dma, rdma_io->skb->len,
+				 DMA_TO_DEVICE);
+	}
+
+	while (pool->last_comp_buf != rdma_io->index) {
+		INC(pool->last_comp_buf, 1, pool->num_xmit_bufs);
+		skb = pool->xmit_bufs[pool->last_comp_buf].skb;
+		if (skb != NULL) {
+			dev_kfree_skb_any(skb);
+		}
+		pool->xmit_bufs[pool->last_comp_buf].skb = NULL;
+	}
+#ifdef LIMIT_OUTSTANDING_SENDS
+	data_check_xmit_buffers(data);
+#endif	/* LIMIT_OUTSTANDING_SENDS */
+
+	return;
+}
diff --git a/drivers/infiniband/ulp/vnic/vnic_data.h b/drivers/infiniband/ulp/vnic/vnic_data.h
new file mode 100644
index 0000000..0588b09
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_data.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2006 SilverStorm Technologies Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef VNIC_DATA_H_INCLUDED
+#define VNIC_DATA_H_INCLUDED
+
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+#include <linux/timex.h>
+#endif	/* CONFIG_INFINIBAND_VNIC_STATS */
+
+#include "vnic_ib.h"
+#include "vnic_control_pkt.h"
+#include "vnic_trailer.h"
+
+struct rdma_dest {
+	struct list_head	list_ptrs;
+	struct sk_buff		*skb;
+	u8			*data;
+	struct viport_trailer	*trailer;
+};
+
+struct buff_pool_entry {
+	u64	remote_addr;
+	u32	r_key;
+	u32	valid;
+};
+
+struct recv_pool {
+	u32			buffer_sz;
+	u32			pool_sz;
+	u32			eioc_pool_sz;
+	uint32_t 		eioc_rdma_rkey;
+	u64 			eioc_rdma_addr;
+	u32 			next_full_buf;
+	u32 			next_free_buf;
+	u32 			num_free_bufs;
+	u32 			num_posted_bufs;
+	u32 			sz_free_bundle;
+	BOOLEAN 		kick_on_free;
+	struct buff_pool_entry	*buf_pool;
+	dma_addr_t		buf_pool_dma;
+	int			buf_pool_len;
+	struct rdma_dest	*recv_bufs;
+	struct list_head	avail_recv_bufs;
+};
+
+struct xmit_pool {
+	u32			buffer_sz;
+	u32 			pool_sz;
+	u32 			notify_count;
+	u32 			notify_bundle;
+	u32 			next_xmit_buf;
+	u32 			last_comp_buf;
+	u32 			num_xmit_bufs;
+	u32 			next_xmit_pool;
+	u32 			kick_count;
+	u32 			kick_byte_count;
+	u32 			kick_bundle;
+	u32 			kick_byte_bundle;
+	BOOLEAN 		need_buffers;
+	BOOLEAN 		send_kicks;
+	uint32_t 		rdma_rkey;
+	u64 			rdma_addr;
+	struct buff_pool_entry	*buf_pool;
+	dma_addr_t		buf_pool_dma;
+	int			buf_pool_len;
+	struct rdma_io		*xmit_bufs;
+	u8			*xmit_data;
+	dma_addr_t		xmitdata_dma;
+	int			xmitdata_len;
+};
+
+struct data {
+	struct viport			*parent;
+	struct data_config		*config;
+	struct ib_mr			*mr;
+	struct vnic_ib_conn		ib_conn;
+	u8				*local_storage;
+	struct vnic_recv_pool_config	host_pool_parms;
+	struct vnic_recv_pool_config	eioc_pool_parms;
+	struct recv_pool		recv_pool;
+	struct xmit_pool		xmit_pool;
+	u8				*region_data;
+	dma_addr_t			regiondata_dma;
+	struct rdma_io			free_bufs_io;
+	struct send_io			kick_io;
+	struct list_head		recv_ios;
+	spinlock_t			recv_ios_lock;
+	spinlock_t			xmit_buf_lock;
+	BOOLEAN				kick_timer_on;
+	BOOLEAN				connected;
+	struct timer_list		kick_timer;
+	struct completion		done;
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+	struct {
+		u32		xmit_num;
+		u32		recv_num;
+		u32		free_buf_sends;
+		u32		free_buf_num;
+		u32		free_buf_min;
+		u32		kick_recvs;
+		u32		kick_reqs;
+		u32		no_xmit_bufs;
+		cycles_t	no_xmit_buf_time;
+	} statistics;
+#endif	/* CONFIG_INFINIBAND_VNIC_STATS */
+};
+
+BOOLEAN data_init(struct data *data, struct viport *viport,
+		  struct data_config *config, struct ib_pd *pd, u64 guid);
+
+BOOLEAN data_connect(struct data *data);
+void data_connected(struct data *data);
+void data_disconnect(struct data *data);
+
+BOOLEAN data_xmit_packet(struct data *data, struct sk_buff *skb);
+
+void data_cleanup(struct data *data);
+
+#define data_is_connected(data) 	(ib_conn_connected(&((data)->ib_conn)))
+#define data_path_id(data)		(data)->config->path_id
+#define data_eioc_pool(data)		&(data)->eioc_pool_parms
+#define data_host_pool(data)		&(data)->host_pool_parms
+#define data_eioc_pool_min(data)	&(data)->config->eioc_min
+#define data_host_pool_min(data)	&(data)->config->host_min
+#define data_eioc_pool_max(data)	&(data)->config->eioc_max
+#define data_host_pool_max(data)	&(data)->config->host_max
+#define data_local_pool_addr(data)	(data)->xmit_pool.rdma_addr
+#define data_local_pool_rkey(data)	(data)->xmit_pool.rdma_rkey
+#define data_remote_pool_addr(data)	&(data)->recv_pool.eioc_rdma_addr
+#define data_remote_pool_rkey(data)	&(data)->recv_pool.eioc_rdma_rkey
+
+#define data_max_mtu(data)				\
+	MAX_PAYLOAD(min((data)->recv_pool.buffer_sz,	\
+	(data)->xmit_pool.buffer_sz)) - ETH_VLAN_HLEN
+
+#define data_len(data, trailer)		ntoh16(trailer->data_length)
+#define data_offset(data, trailer)					\
+	data->recv_pool.buffer_sz - sizeof(struct viport_trailer)	\
+	- ROUNDUPP2(data_len(data, trailer), VIPORT_TRAILER_ALIGNMENT)	\
+	+ ntoh8(trailer->data_alignment_offset)
+
+/* the following macros manipulate ring buffer indexes.
+ * the ring buffer size must be a power of 2.
+ */
+#define ADD(index, increment, size)	(((index) + (increment))&((size) - 1))
+#define NEXT(index, size)		ADD(index, 1, size)
+#define INC(index, increment, size)	(index) = ADD(index, increment, size)
+
+#endif	/* VNIC_DATA_H_INCLUDED */
diff --git a/drivers/infiniband/ulp/vnic/vnic_trailer.h b/drivers/infiniband/ulp/vnic/vnic_trailer.h
new file mode 100644
index 0000000..d6bd6c7
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_trailer.h
@@ -0,0 +1,63 @@
+#ifndef VNIC_TRAILER_H_INCLUDED
+#define VNIC_TRAILER_H_INCLUDED
+
+/* pkt_flags values */
+#define PF_CHASH_VALID		0x01
+#define PF_IPSEC_VALID		0x02
+#define PF_TCP_SEGMENT		0x04
+#define PF_KICK			0x08
+#define PF_VLAN_INSERT		0x10
+#define PF_PVID_OVERRIDDEN 	0x20
+#define PF_FCS_INCLUDED 	0x40
+#define PF_FORCE_ROUTE		0x80
+
+/* tx_chksum_flags values */
+#define TX_CHKSUM_FLAGS_CHECKSUM_V4		0x01
+#define TX_CHKSUM_FLAGS_CHECKSUM_V6		0x02
+#define TX_CHKSUM_FLAGS_TCP_CHECKSUM		0x04
+#define TX_CHKSUM_FLAGS_UDP_CHECKSUM		0x08
+#define TX_CHKSUM_FLAGS_IP_CHECKSUM		0x10
+
+/* rx_chksum_flags values */
+#define RX_CHKSUM_FLAGS_TCP_CHECKSUM_FAILED	0x01
+#define RX_CHKSUM_FLAGS_UDP_CHECKSUM_FAILED	0x02
+#define RX_CHKSUM_FLAGS_IP_CHECKSUM_FAILED	0x04
+#define RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED	0x08
+#define RX_CHKSUM_FLAGS_UDP_CHECKSUM_SUCCEEDED	0x10
+#define RX_CHKSUM_FLAGS_IP_CHECKSUM_SUCCEEDED	0x20
+#define RX_CHKSUM_FLAGS_LOOPBACK		0x40
+#define RX_CHKSUM_FLAGS_RESERVED		0x80
+
+/* connection_hash_and_valid values */
+#define CHV_VALID	0x80
+#define CHV_HASH_MASH	0x7f
+
+struct viport_trailer {
+	s8	data_alignment_offset;
+	u8	rndis_header_length;	/* reserved for use by edp */
+	u16	data_length;
+	u8	pkt_flags;
+	u8	tx_chksum_flags;
+	u8	rx_chksum_flags;
+	u8	ip_sec_flags;
+	u32	tcp_seq_no;
+	u32	ip_sec_offload_handle;
+	u32	ip_sec_next_offload_handle;
+	u8	dest_mac_addr[6];
+	u16	vlan;
+	u16	time_stamp;
+	u8	origin;
+	u8	connection_hash_and_valid;
+};
+
+#define VIPORT_TRAILER_ALIGNMENT	32
+
+#define BUFFER_SIZE(len)					\
+	(sizeof(struct viport_trailer) +  ROUNDUPP2((len),	\
+	 VIPORT_TRAILER_ALIGNMENT))
+
+#define MAX_PAYLOAD(len)					\
+	ROUNDDOWNP2((len) - sizeof(struct viport_trailer),	\
+	VIPORT_TRAILER_ALIGNMENT)
+
+#endif	/* VNIC_TRAILER_H_INCLUDED */





More information about the general mailing list