[openib-general] [PATCH v2 6/11] IB core stack interaction

Ramachandra K ramachandra.kuchimanchi at qlogic.com
Tue Nov 14 06:56:55 PST 2006


Adds the files that implement interaction with the core IB stack.


Signed-off-by: Ramachandra K <ramachandra.kuchimanchi at qlogic.com>
---

 drivers/infiniband/ulp/vnic/vnic_ib.c |  691 +++++++++++++++++++++++++++++++++
 drivers/infiniband/ulp/vnic/vnic_ib.h |  170 ++++++++
 2 files changed, 861 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/ulp/vnic/vnic_ib.c b/drivers/infiniband/ulp/vnic/vnic_ib.c
new file mode 100644
index 0000000..71f02cf
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_ib.c
@@ -0,0 +1,691 @@
+/*
+ * Copyright (c) 2006 QLogic, 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 <linux/string.h>
+#include <linux/random.h>
+#include <linux/netdevice.h>
+#include <linux/list.h>
+#include <rdma/ib_cache.h>
+
+#include "vnic_util.h"
+#include "vnic_config.h"
+#include "vnic_ib.h"
+#include "vnic_viport.h"
+#include "vnic_sys.h"
+#include "vnic_main.h"
+#include "vnic_stats.h"
+
+static int vnic_ib_inited = 0;
+
+static void vnic_add_one(struct ib_device *device);
+static void vnic_remove_one(struct ib_device *device);
+
+static struct ib_client vnic_client = {
+	.name = "vnic",
+	.add = vnic_add_one,
+	.remove = vnic_remove_one
+};
+
+static struct ib_sa_client vnic_sa_client;
+
+static CLASS_DEVICE_ATTR(create_primary, S_IWUSR, NULL,
+			 vnic_create_primary);
+static CLASS_DEVICE_ATTR(create_secondary, S_IWUSR, NULL,
+			 vnic_create_secondary);
+
+static CLASS_DEVICE_ATTR(delete_vnic, S_IWUSR, NULL, vnic_delete);
+
+static struct vnic_ib_port *vnic_add_port(struct vnic_ib_device *device,
+					  u8 port_num)
+{
+	struct vnic_ib_port *port;
+
+	port = kzalloc(sizeof *port, GFP_KERNEL);
+	if (!port)
+		return NULL;
+
+	init_completion(&port->cdev_info.released);
+	port->dev = device;
+	port->port_num = port_num;
+
+	port->cdev_info.class_dev.class = &vnic_class;
+	port->cdev_info.class_dev.dev = device->dev->dma_device;
+	snprintf(port->cdev_info.class_dev.class_id, BUS_ID_SIZE,
+		 "vnic-%s-%d", device->dev->name, port_num);
+
+	if (class_device_register(&port->cdev_info.class_dev))
+		goto free_port;
+
+	if (class_device_create_file(&port->cdev_info.class_dev,
+				     &class_device_attr_create_primary))
+		goto err_class;
+	if (class_device_create_file(&port->cdev_info.class_dev,
+				     &class_device_attr_create_secondary))
+		goto err_class;
+
+	return port;
+err_class:
+	class_device_unregister(&port->cdev_info.class_dev);
+free_port:
+	kfree(port);
+
+	return NULL;
+}
+
+static void vnic_add_one(struct ib_device *device)
+{
+	struct vnic_ib_device *vnic_dev;
+	struct vnic_ib_port *port;
+	int s, e, p;
+
+	vnic_dev = kmalloc(sizeof *vnic_dev, GFP_KERNEL);
+	if (!vnic_dev)
+		return;
+
+	vnic_dev->dev = device;
+	INIT_LIST_HEAD(&vnic_dev->port_list);
+
+	if (device->node_type == RDMA_NODE_IB_SWITCH) {
+		s = 0;
+		e = 0;
+
+	} else {
+		s = 1;
+		e = device->phys_port_cnt;
+
+	}
+
+	for (p = s; p <= e; p++) {
+		port = vnic_add_port(vnic_dev, p);
+		if (port)
+			list_add_tail(&port->list, &vnic_dev->port_list);
+	}
+
+	ib_set_client_data(device, &vnic_client, vnic_dev);
+
+}
+
+static void vnic_remove_one(struct ib_device *device)
+{
+	struct vnic_ib_device *vnic_dev;
+	struct vnic_ib_port *port, *tmp_port;
+
+	vnic_dev = ib_get_client_data(device, &vnic_client);
+	list_for_each_entry_safe(port, tmp_port,
+				 &vnic_dev->port_list, list) {
+		class_device_unregister(&port->cdev_info.class_dev);
+		/*
+		 * wait for sysfs entries to go away, so that no new vnics
+		 * are created
+		 */
+		wait_for_completion(&port->cdev_info.released);
+		kfree(port);
+
+	}
+	kfree(vnic_dev);
+}
+
+int vnic_ib_init(void)
+{
+	int ret = -1;
+
+	IB_FUNCTION("vnic_ib_init()\n");
+
+	/* class has to be registered before
+	 * calling ib_register_client() because, that call
+	 * will trigger vnic_add_port() which will register
+	 * class_device for the port with the parent class
+	 * as vnic_class
+	 */
+	ret = class_register(&vnic_class);
+	if (ret) {
+		printk(KERN_ERR PFX "couldn't register class"
+		       " infiniband_vnic; error %d", ret);
+		goto out;
+	}
+
+	ib_sa_register_client(&vnic_sa_client);
+	ret = ib_register_client(&vnic_client);
+	if (ret) {
+		printk(KERN_ERR PFX "couldn't register IB client;"
+		       " error %d", ret);
+		goto err_ib_reg;
+	}
+
+	interface_cdev.class_dev.class = &vnic_class;
+	snprintf(interface_cdev.class_dev.class_id,
+		 BUS_ID_SIZE, "interfaces");
+	init_completion(&interface_cdev.released);
+	ret = class_device_register(&interface_cdev.class_dev);
+	if (ret) {
+		printk(KERN_ERR PFX "couldn't register class interfaces;"
+		       " error %d", ret);
+		goto err_class_dev;
+	}
+	ret = class_device_create_file(&interface_cdev.class_dev,
+				       &class_device_attr_delete_vnic);
+	if (ret) {
+		printk(KERN_ERR PFX "couldn't create class file"
+		       " 'delete_vnic'; error %d", ret);
+		goto err_class_file;
+	}
+
+	vnic_ib_inited = 1;
+
+	return ret;
+err_class_file:
+	class_device_unregister(&interface_cdev.class_dev);
+err_class_dev:
+	ib_unregister_client(&vnic_client);
+err_ib_reg:
+	ib_sa_unregister_client(&vnic_sa_client);
+	class_unregister(&vnic_class);
+out:
+	return ret;
+}
+
+void vnic_ib_cleanup(void)
+{
+	IB_FUNCTION("vnic_ib_cleanup()\n");
+
+	if (!vnic_ib_inited)
+		return;
+
+	class_device_unregister(&interface_cdev.class_dev);
+	wait_for_completion(&interface_cdev.released);
+
+	ib_unregister_client(&vnic_client);
+	ib_sa_unregister_client(&vnic_sa_client);
+	class_unregister(&vnic_class);
+}
+
+static void vnic_path_rec_completion(int status,
+				     struct ib_sa_path_rec *pathrec,
+				     void *context)
+{
+	struct vnic_ib_path_info *p = context;
+	p->status = status;
+	if (!status)
+		p->path = *pathrec;
+
+	complete(&p->done);
+}
+
+int vnic_ib_get_path(struct netpath *netpath, struct vnic * vnic)
+{
+	struct viport_config *config = netpath->viport->config;
+	int ret = 0;
+
+	init_completion(&config->path_info.done);
+	IB_INFO("Using SA path rec get time out value of %d\n",
+	       config->sa_path_rec_get_timeout);
+	config->path_info.path_query_id =
+			 ib_sa_path_rec_get(&vnic_sa_client,
+					    config->ibdev,
+					    config->port,
+					    &config->path_info.path,
+					    IB_SA_PATH_REC_DGID      |
+					    IB_SA_PATH_REC_SGID      |
+					    IB_SA_PATH_REC_NUMB_PATH |
+					    IB_SA_PATH_REC_PKEY,
+					    config->sa_path_rec_get_timeout,
+					    GFP_KERNEL,
+					    vnic_path_rec_completion,
+					    &config->path_info,
+					    &config->path_info.path_query);
+
+	if (config->path_info.path_query_id < 0) {
+		IB_ERROR("SA path record query failed; error %d\n",
+			 config->path_info.path_query_id);
+		ret= config->path_info.path_query_id;
+		goto out;
+	}
+
+	wait_for_completion(&config->path_info.done);
+
+	if (config->path_info.status < 0) {
+		printk(KERN_WARNING PFX "path record query failed for dgid "
+		       "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+		       (int)be16_to_cpu(*(__be16 *) &config->path_info.path.
+					dgid.raw[0]),
+		       (int)be16_to_cpu(*(__be16 *) &config->path_info.path.
+					dgid.raw[2]),
+		       (int)be16_to_cpu(*(__be16 *) &config->path_info.path.
+					dgid.raw[4]),
+		       (int)be16_to_cpu(*(__be16 *) &config->path_info.path.
+					dgid.raw[6]),
+		       (int)be16_to_cpu(*(__be16 *) &config->path_info.path.
+					dgid.raw[8]),
+		       (int)be16_to_cpu(*(__be16 *) &config->path_info.path.
+					dgid.raw[10]),
+		       (int)be16_to_cpu(*(__be16 *) &config->path_info.path.
+					dgid.raw[12]),
+		       (int)be16_to_cpu(*(__be16 *) &config->path_info.path.
+					dgid.raw[14]));
+
+		if (config->path_info.status == -ETIMEDOUT)
+			printk(KERN_WARNING PFX
+			       "reason: path record query timed out\n");
+		else if (config->path_info.status == -EIO)
+			printk(KERN_WARNING PFX
+			       "reason: error in sending path record query\n");
+		else
+			printk(KERN_WARNING PFX "reason: error %d in sending"
+			       " path record query\n",
+			       config->path_info.status);
+
+		netpath_timer(netpath, vnic->config->no_path_timeout);
+		ret = config->path_info.status;
+	}
+out:
+	return ret;
+}
+
+static void ib_qp_event(struct ib_event *event, void *context)
+{
+	IB_ERROR("QP event %d\n", event->event);
+}
+
+static void vnic_ib_completion(struct ib_cq *cq, void *ptr)
+{
+	struct ib_wc wc;
+	struct io *io;
+	struct vnic_ib_conn *ib_conn = ptr;
+	cycles_t           comp_time;
+	u32              comp_num = 0;
+
+	vnic_ib_note_comptime_stats(&comp_time);
+	vnic_ib_callback_stats(ib_conn);
+
+	ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+	while (ib_poll_cq(cq, 1, &wc) > 0) {
+		io = (struct io *)(wc.wr_id);
+		vnic_ib_comp_stats(ib_conn, &comp_num);
+		if (wc.status) {
+#if 0
+			IB_ERROR("completion error  wc.status %d"
+				 " wc.opcode %d vendor err 0x%x\n",
+				 wc.status, wc.opcode, wc.vendor_err);
+#endif
+		} else if (io) {
+			vnic_ib_io_stats(io, ib_conn, comp_time);
+			if (io->routine)
+				(*io->routine) (io);
+		}
+	}
+	vnic_ib_maxio_stats(ib_conn, comp_num);
+}
+
+static int vnic_ib_mod_qp_to_rts(struct ib_cm_id * cm_id,
+			     struct vnic_ib_conn * ib_conn)
+{
+	int attr_mask = 0;
+	int ret;
+	struct ib_qp_attr *qp_attr = NULL;
+
+	qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL);
+	if (!qp_attr)
+		return -ENOMEM;
+
+	qp_attr->qp_state = IB_QPS_RTR;
+
+	if ((ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask)))
+		goto out;
+
+	if((ret = ib_modify_qp(ib_conn->qp, qp_attr, attr_mask)))
+		goto out;
+
+	IB_INFO("QP RTR\n");
+
+	qp_attr->qp_state = IB_QPS_RTS;
+
+	if((ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask)))
+		goto out;
+
+	if((ret=ib_modify_qp(ib_conn->qp, qp_attr, attr_mask)))
+		goto out;
+
+	IB_INFO("QP RTS\n");
+
+	if((ret = ib_send_cm_rtu(cm_id, NULL, 0)))
+		goto out;
+out:
+	kfree(qp_attr);
+	return ret;
+}
+
+int vnic_ib_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
+{
+	struct vnic_ib_conn *ib_conn = cm_id->context;
+	struct viport *viport = ib_conn->viport;
+	int err = 0;
+	int disconn = 0;
+
+	switch (event->event) {
+	case IB_CM_REQ_ERROR:
+		IB_ERROR("sending CM REQ failed\n");
+		disconn = 1;
+		break;
+	case IB_CM_REP_RECEIVED:
+		IB_INFO("CM REP recvd\n");
+		if (vnic_ib_mod_qp_to_rts(cm_id, ib_conn))
+			err = 1;
+		else {
+			ib_conn->state = IB_CONN_CONNECTED;
+			vnic_ib_connected_time_stats(ib_conn);
+			IB_INFO("RTU SENT\n");
+		}
+		break;
+	case IB_CM_REJ_RECEIVED:
+		printk(KERN_ERR PFX "CM rejected control connection \n");
+		if (event->param.rej_rcvd.reason ==
+		    IB_CM_REJ_INVALID_SERVICE_ID)
+			printk(KERN_ERR "reason: invalid service ID. "
+			       "IOCGUID value specified may be incorrect\n");
+		else
+			printk(KERN_ERR "reason code : 0x%x\n",
+			       event->param.rej_rcvd.reason);
+
+		disconn = 1;
+		break;
+	case IB_CM_MRA_RECEIVED:
+		IB_INFO("CM MRA received\n");
+		break;
+
+	case IB_CM_DREP_RECEIVED:
+		IB_INFO("CM DREP recvd\n");
+		ib_conn->state = IB_CONN_DISCONNECTED;
+		break;
+
+	case IB_CM_TIMEWAIT_EXIT:
+		IB_ERROR("CM timewait exit\n");
+		err = 1;
+		break;
+
+	default:
+		IB_INFO("unhandled CM event %d\n", event->event);
+		break;
+
+	}
+
+	if (err) {
+		ib_conn->state = IB_CONN_DISCONNECTED;
+		viport_failure(viport);
+	}
+
+	if (disconn) {
+		ib_conn->state = IB_CONN_DISCONNECTED;
+		viport_disconnect(viport);
+
+	}
+	complete(&ib_conn->done);
+	return 0;
+}
+
+
+int vnic_ib_cm_connect(struct vnic_ib_conn *ib_conn)
+{
+	struct ib_cm_req_param	*req = NULL;
+	struct viport		*viport;
+	int 			ret = -1;
+
+	if (!vnic_ib_conn_initted(ib_conn)) {
+		IB_ERROR("IB Connection out of state for CM connect (%d)\n",
+			 ib_conn->state);
+		return -EINVAL;
+	}
+
+	vnic_ib_conntime_stats(ib_conn);
+	req = kzalloc(sizeof *req, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	viport	= ib_conn->viport;
+
+	req->primary_path	= &viport->config->path_info.path;
+	req->alternate_path	= NULL;
+	req->qp_num		= ib_conn->qp->qp_num;
+	req->qp_type		= ib_conn->qp->qp_type;
+	req->service_id 	= ib_conn->ib_config->service_id;
+	req->private_data	= &ib_conn->ib_config->conn_data;
+	req->private_data_len	= sizeof(struct vnic_connection_data);
+	req->flow_control	= 1;
+
+	get_random_bytes(&req->starting_psn, 4);
+	req->starting_psn &= 0xffffff;
+
+	/*
+	 * Both responder_resources and initiator_depth are set to zero
+	 * as we do not need RDMA read.
+	 *
+	 * They also must be set to zero, otherwise data connections
+	 * are rejected by VEx.
+	 */
+	req->responder_resources 	= 0;
+	req->initiator_depth		= 0;
+	req->remote_cm_response_timeout = 20;
+	req->local_cm_response_timeout  = 20;
+	req->retry_count		= ib_conn->ib_config->retry_count;
+	req->rnr_retry_count		= ib_conn->ib_config->rnr_retry_count;
+	req->max_cm_retries		= 15;
+
+	ib_conn->state = IB_CONN_CONNECTING;
+
+	ret = ib_send_cm_req(ib_conn->cm_id, req);
+
+	kfree(req);
+
+	if (ret) {
+		IB_ERROR("CM REQ sending failed; error %d \n", ret);
+		ib_conn->state = IB_CONN_DISCONNECTED;
+	}
+
+	return ret;
+}
+
+static int vnic_ib_init_qp(struct vnic_ib_conn * ib_conn,
+			   struct vnic_ib_config *config,
+			   struct ib_pd	*pd,
+			   struct viport_config * viport_config)
+{
+	struct ib_qp_init_attr	*init_attr;
+	struct ib_qp_attr	*attr;
+	int			ret;
+
+	init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL);
+	if (!init_attr)
+		return -ENOMEM;
+
+	init_attr->event_handler	= ib_qp_event;
+	init_attr->cap.max_send_wr	= config->num_sends;
+	init_attr->cap.max_recv_wr	= config->num_recvs;
+	init_attr->cap.max_recv_sge	= config->recv_scatter;
+	init_attr->cap.max_send_sge	= config->send_gather;
+	init_attr->sq_sig_type		= IB_SIGNAL_ALL_WR;
+	init_attr->qp_type		= IB_QPT_RC;
+	init_attr->send_cq		= ib_conn->cq;
+	init_attr->recv_cq		= ib_conn->cq;
+
+	ib_conn->qp = ib_create_qp(pd, init_attr);
+
+	if (IS_ERR(ib_conn->qp)) {
+		ret = -1;
+		IB_ERROR("could not create QP\n");
+		goto free_init_attr;
+	}
+
+	attr = kmalloc(sizeof *attr, GFP_KERNEL);
+	if (!attr) {
+		ret = -ENOMEM;
+		goto destroy_qp;
+	}
+
+	ret = ib_find_cached_pkey(viport_config->ibdev,
+				  viport_config->port,
+				  be16_to_cpu(viport_config->path_info.path.
+					      pkey),
+				  &attr->pkey_index);
+	if (ret) {
+		printk(KERN_WARNING PFX "ib_find_cached_pkey() failed; "
+		       "error %d\n", ret);
+		goto freeattr;
+	}
+
+	attr->qp_state		= IB_QPS_INIT;
+	attr->qp_access_flags	= IB_ACCESS_REMOTE_WRITE;
+	attr->port_num		= viport_config->port;
+
+	ret = ib_modify_qp(ib_conn->qp, attr,
+			   IB_QP_STATE |
+			   IB_QP_PKEY_INDEX |
+			   IB_QP_ACCESS_FLAGS | IB_QP_PORT);
+	if (ret) {
+		printk(KERN_WARNING PFX "could not modify QP; error %d \n",
+		       ret);
+		goto freeattr;
+	}
+
+	kfree(attr);
+	kfree(init_attr);
+	return ret;
+
+freeattr:
+	kfree(attr);
+destroy_qp:
+	ib_destroy_qp(ib_conn->qp);
+free_init_attr:
+	kfree(init_attr);
+	return ret;
+}
+
+int vnic_ib_conn_init(struct vnic_ib_conn *ib_conn, struct viport *viport,
+		      struct ib_pd *pd, struct vnic_ib_config *config)
+{
+	struct viport_config	*viport_config = viport->config;
+	int		ret = -1;
+	unsigned int	cq_size = config->num_sends + config->num_recvs;
+
+
+	if (!vnic_ib_conn_uninitted(ib_conn)) {
+		IB_ERROR("IB Connection out of state for init (%d)\n",
+			 ib_conn->state);
+		return -EINVAL;
+	}
+
+	ib_conn->cq = ib_create_cq(viport_config->ibdev, vnic_ib_completion,
+				   NULL, ib_conn, cq_size);
+	if (IS_ERR(ib_conn->cq)) {
+		IB_ERROR("could not create CQ\n");
+		goto out;
+	}
+
+	ib_req_notify_cq(ib_conn->cq, IB_CQ_NEXT_COMP);
+
+	ret = vnic_ib_init_qp(ib_conn, config, pd, viport_config);
+
+	if(ret)
+		goto destroy_cq;
+
+	ib_conn->conn_lock  = SPIN_LOCK_UNLOCKED;
+	ib_conn->state = IB_CONN_INITTED;
+
+	return ret;
+
+destroy_cq:
+	ib_destroy_cq(ib_conn->cq);
+out:
+	return ret;
+}
+
+int vnic_ib_post_recv(struct vnic_ib_conn * ib_conn, struct io * io)
+{
+	cycles_t		post_time;
+	struct ib_recv_wr	*bad_wr;
+	int			ret = -1;
+	unsigned long		flags;
+
+	IB_FUNCTION("vnic_ib_post_recv()\n");
+
+	spin_lock_irqsave(&ib_conn->conn_lock, flags);
+
+	if (!vnic_ib_conn_initted(ib_conn) &&
+	    !vnic_ib_conn_connected(ib_conn))
+		return -EINVAL;
+
+	vnic_ib_pre_rcvpost_stats(ib_conn, io, &post_time);
+	io->type = RECV;
+	ret = ib_post_recv(ib_conn->qp, &io->rwr, &bad_wr);
+	if (ret) {
+		IB_ERROR("error in posting rcv wr; error %d\n", ret);
+		goto out;
+	}
+
+	vnic_ib_post_rcvpost_stats(ib_conn, post_time);
+out:
+	spin_unlock_irqrestore(&ib_conn->conn_lock, flags);
+	return ret;
+
+}
+
+int vnic_ib_post_send(struct vnic_ib_conn * ib_conn, struct io * io)
+{
+	cycles_t		post_time;
+	unsigned long		flags;
+	struct ib_send_wr	*bad_wr;
+	int			ret = -1;
+
+	IB_FUNCTION("vnic_ib_post_send()\n");
+
+	spin_lock_irqsave(&ib_conn->conn_lock, flags);
+	if (!vnic_ib_conn_connected(ib_conn)) {
+		IB_ERROR("IB Connection out of state for"
+			 " posting sends (%d)\n", ib_conn->state);
+		goto out;
+	}
+
+	vnic_ib_pre_sendpost_stats(io, &post_time);
+	if (io->swr.opcode == IB_WR_RDMA_WRITE)
+		io->type = RDMA;
+	else
+		io->type = SEND;
+
+	ret = ib_post_send(ib_conn->qp, &io->swr, &bad_wr);
+	if (ret) {
+		IB_ERROR("error in posting send wr; error %d\n", ret);
+		goto out;
+	}
+
+	vnic_ib_post_sendpost_stats(ib_conn, io, post_time);
+out:
+	spin_unlock_irqrestore(&ib_conn->conn_lock, flags);
+	return ret;
+}
diff --git a/drivers/infiniband/ulp/vnic/vnic_ib.h b/drivers/infiniband/ulp/vnic/vnic_ib.h
new file mode 100644
index 0000000..f009876
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_ib.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2006 QLogic, 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_IB_H_INCLUDED
+#define VNIC_IB_H_INCLUDED
+
+#include <linux/timex.h>
+#include <linux/completion.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/ib_sa.h>
+#include <rdma/ib_cm.h>
+
+#include "vnic_sys.h"
+#include "vnic_netpath.h"
+#define PFX	"ib_vnic: "
+
+struct io;
+typedef void (comp_routine_t) (struct io * io);
+
+enum vnic_ib_conn_state {
+	IB_CONN_UNINITTED	= 0,
+	IB_CONN_INITTED		= 1,
+	IB_CONN_CONNECTING	= 2,
+	IB_CONN_CONNECTED	= 3,
+	IB_CONN_DISCONNECTED	= 4
+};
+
+struct vnic_ib_conn {
+	struct viport		*viport;
+	struct vnic_ib_config	*ib_config;
+	spinlock_t		conn_lock;
+	enum vnic_ib_conn_state	state;
+	struct ib_qp		*qp;
+	struct ib_cq		*cq;
+	struct ib_cm_id		*cm_id;
+	struct completion	done;
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+	struct {
+		cycles_t	connection_time;
+		cycles_t	rdma_post_time;
+		u32		rdma_post_ios;
+		cycles_t	rdma_comp_time;
+		u32		rdma_comp_ios;
+		cycles_t	send_post_time;
+		u32		send_post_ios;
+		cycles_t	send_comp_time;
+		u32		send_comp_ios;
+		cycles_t	recv_post_time;
+		u32		recv_post_ios;
+		cycles_t	recv_comp_time;
+		u32		recv_comp_ios;
+		u32		num_ios;
+		u32		num_callbacks;
+		u32		max_ios;
+	} statistics;
+#endif	/* CONFIG_INFINIBAND_VNIC_STATS */
+};
+
+struct vnic_ib_path_info {
+	struct ib_sa_path_rec	path;
+	struct ib_sa_query	*path_query;
+	int			path_query_id;
+	int			status;
+	struct			completion done;
+};
+
+struct vnic_ib_device {
+	struct ib_device	*dev;
+	struct list_head	port_list;
+};
+
+struct vnic_ib_port {
+	struct vnic_ib_device	*dev;
+	u8			port_num;
+	struct class_dev_info	cdev_info;
+	struct list_head	list;
+};
+
+struct io {
+	struct list_head	list_ptrs;
+	struct viport		*viport;
+	comp_routine_t		*routine;
+	struct ib_recv_wr	rwr;
+	struct ib_send_wr	swr;
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+	cycles_t		time;
+#endif	/* CONFIG_INFINIBAND_VNIC_STATS */
+	enum {RECV, RDMA, SEND}	type;
+};
+
+struct rdma_io {
+	struct io		io;
+	struct ib_sge		list[2];
+	u16			index;
+	u16			len;
+	u8			*data;
+	dma_addr_t		data_dma;
+	struct sk_buff		*skb;
+	dma_addr_t		skb_data_dma;
+	struct viport_trailer 	*trailer;
+	dma_addr_t 		trailer_dma;
+};
+
+struct send_io {
+	struct io	io;
+	struct ib_sge	list;
+	u8		*virtual_addr;
+};
+
+struct recv_io {
+	struct io	io;
+	struct ib_sge	list;
+	u8		*virtual_addr;
+};
+
+int	vnic_ib_init(void);
+void	vnic_ib_cleanup(void);
+
+struct vnic;
+int vnic_ib_get_path(struct netpath *netpath, struct vnic * vnic);
+int vnic_ib_conn_init(struct vnic_ib_conn *ib_conn, struct viport *viport,
+		      struct ib_pd *pd, struct vnic_ib_config *config);
+
+int vnic_ib_post_recv(struct vnic_ib_conn *ib_conn, struct io *io);
+int vnic_ib_post_send(struct vnic_ib_conn *ib_conn, struct io *io);
+int vnic_ib_cm_connect(struct vnic_ib_conn *ib_conn);
+int vnic_ib_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
+
+#define	vnic_ib_conn_uninitted(ib_conn)			\
+	((ib_conn)->state == IB_CONN_UNINITTED)
+#define	vnic_ib_conn_initted(ib_conn)			\
+	((ib_conn)->state == IB_CONN_INITTED)
+#define	vnic_ib_conn_connecting(ib_conn)		\
+	((ib_conn)->state == IB_CONN_CONNECTING)
+#define	vnic_ib_conn_connected(ib_conn)			\
+	((ib_conn)->state == IB_CONN_CONNECTED)
+#define	vnic_ib_conn_disconnected(ib_conn)		\
+	((ib_conn)->state == IB_CONN_DISCONNECTED)
+
+#endif	/* VNIC_IB_H_INCLUDED */






More information about the general mailing list