[ewg] [PATCH 5/9] [RFC] Add support for Xsigo configuration protocol manager (XCPM)

Hal Rosenstock hrosenstock at xsigo.com
Fri Apr 4 06:18:56 PDT 2008


Add support for the Xsigo configuration protocol manager (XCPM).
The Xsigo Configuration Protocol Manager (XCPM) manages sessions between
a host and the control plane of the Xsigo chassis. It is also the "hub"
for all control information flow between the host V* drivers and the
Xsigo chassis.

Signed-off-by: Hal Rosenstock <hal at xsigo.com>
---
 drivers/infiniband/ulp/xsigo/xscore/xcpm.c         | 1161 ++++++++++++++++++++
 drivers/infiniband/ulp/xsigo/xscore/xcpm_export.h  |   81 ++
 .../infiniband/ulp/xsigo/xscore/xcpm_interface.h   |  151 +++
 drivers/infiniband/ulp/xsigo/xscore/xcpm_priv.h    |  161 +++
 4 files changed, 1554 insertions(+), 0 deletions(-)
 create mode 100644 drivers/infiniband/ulp/xsigo/xscore/xcpm.c
 create mode 100644 drivers/infiniband/ulp/xsigo/xscore/xcpm_export.h
 create mode 100644 drivers/infiniband/ulp/xsigo/xscore/xcpm_interface.h
 create mode 100644 drivers/infiniband/ulp/xsigo/xscore/xcpm_priv.h

diff --git a/drivers/infiniband/ulp/xsigo/xscore/xcpm.c b/drivers/infiniband/ulp/xsigo/xscore/xcpm.c
new file mode 100644
index 0000000..5d3cbe3
--- /dev/null
+++ b/drivers/infiniband/ulp/xsigo/xscore/xcpm.c
@@ -0,0 +1,1161 @@
+/*
+ * Copyright (c) 2006-2008 Xsigo Systems 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.
+ *
+ */
+
+/*
+ * The Xsigo Configuration Protocol Manager (XCPM) manages sessions between
+ * a host and the control plane of the Xsigo chassis. It is also the "hub"
+ * for all control information flow between the host V* drivers and the
+ * Xsigo chassis.
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <rdma/ib_cache.h>
+
+#include "ib_if.h"
+#include "xsmp.h"
+#include "xcpm_priv.h"
+#include "xcpm_export.h"
+#include "xcpm_stats.h"
+
+#define XCPM_VERSION	"0.21"
+
+#define XCPM_STACK_DELAY (2 * HZ)
+
+static int check_recv_seq_number(int link, u32 recv_seq_number);
+static void seq_number_action(int link, u32 recv_seq_number);
+
+/* Delay the start of the init sequence, allow the stack to stabilize */
+static void xcpm_startup_work_handler(struct work_struct *work);
+
+/* The XCPM data structure */
+struct xcpm_info *xcpm = NULL;
+
+/* Support timeouts on links */
+static int noconntimeout = 0;
+module_param(noconntimeout, int, 0);
+
+/* Disable recovery/reconnect to the peer */
+static int norecovery = 0;
+module_param(norecovery, int, 0);
+
+#ifdef CONFIG_XSCORE_DEBUG
+int xcpm_debug_level = 0;
+module_param(xcpm_debug_level, int, 0);
+#endif
+
+static int stats_frequency = 20;
+module_param(stats_frequency, int, 0);
+
+static int port_sweep_timeout = XCPM_PORT_SWEEP_INTERVAL_SECS;
+module_param(port_sweep_timeout, int, 0);
+
+int boot_flag = 0;
+module_param(boot_flag, int, 0);
+
+wait_queue_head_t xcpm_wait;
+
+struct workqueue_struct *xcpm_wq = NULL;
+
+extern struct kmem_cache *xsmp_cachep;
+
+
+/* Send out a message on the send queue of the 'link' */
+int transmit_to_xcm(int link, u8 *data, int length)
+{
+	struct link_info *plink = &xcpm->links[link];
+	unsigned long flags;
+	int ret;
+
+	if (length <= 0) {
+		xcpm_debug(KERN_ERR, "Invalid length: %d\n", length);
+		log_link_error(link, XSMP_MESSAGE_LENGTH_INVALID);
+		ret = -EINVAL;
+		goto transmit_exit;
+	}
+
+	spin_lock_irqsave(&xcpm->link_lock, flags);
+
+	/* Allow only in LINK_INIT and LINK_UP states */
+	if (plink->link_state != LINK_UP &&
+	    plink->link_state != LINK_INIT) {
+		spin_unlock_irqrestore(&xcpm->link_lock, flags);
+		xcpm_debug(KERN_DEBUG,
+			   "Attempting to transmit, link <0x%x> is down or "
+			   "non-existent\n", link);
+		ret = -ENOLINK;
+		goto transmit_exit;
+	}
+
+	/* Add a sequence number to the message */
+	xsmp_set_seq_number(data, plink->send_seq_number);
+	plink->send_seq_number++;
+
+	/* Set the source and the destination IDs (GUIDs) */
+	xsmp_set_source_dest_ids(link, data);
+
+	/* Send the message onto the send queue */
+	ret = ib_if_send_msg(&plink->ib_link, data, length);
+
+	spin_unlock_irqrestore(&xcpm->link_lock, flags);
+
+transmit_exit:
+	/* Free the buffer from the cache if the transmit did not succeed */
+	if (ret && xsmp_is_local_msg(data))
+		kmem_cache_free(xsmp_cachep, data);
+
+	return ret;
+}
+
+void log_link_error(int link, int error_type)
+{
+	xcpm->links[link].error_counts[error_type]++;
+}
+
+void send_service_status(link)
+{
+	if (xcpm->links[link].link_state == LINK_UP)
+		xsmp_send_resource_list(link, xcpm->resource_flags);
+}
+
+/* Tell all XCMs what all services (V* drivers) are active */
+void broadcast_service_status(void)
+{
+	int count;
+
+	for (count = 0; count < MAX_NUM_LINKS; count++)
+		if (xcpm->links[count].link_state == LINK_UP)
+			xsmp_send_resource_list(count, xcpm->resource_flags);
+}
+
+int send_error_counts(int link)
+{
+	xcpm_debug(KERN_INFO, "Sending error counts for link %d\n", link);
+
+	return xsmp_send_error_counts(link, xcpm->links[link].error_counts);
+}
+
+/*
+ * Interface functions that the service drivers
+ * use to communicate to the XCPM
+ */
+int xcpm_register_service(struct service_type_info *s_info)
+{
+	int ret = 0;
+	int count;
+	int index;
+	unsigned long flags;
+
+	if (!s_info) {
+		ret = -EINVAL;
+		goto register_service_exit;
+	}
+
+	/* Check for duplicates */
+	for (count = 0; count < MAX_NUM_SVCS; count++)
+		if (xcpm->svcs[count].ctrl_message_type == s_info->ctrl_message_type &&
+		    xcpm->svcs[count].svc_state == SERVICE_UP) {
+			ret = -EALREADY;
+			goto register_service_exit;
+		}
+
+	spin_lock_irqsave(&xcpm->interface_lock, flags);
+
+	/* Find an empty slot */
+	for (index = 0; index < MAX_NUM_SVCS; index++)
+		if (xcpm->svcs[index].svc_state != SERVICE_UP)
+			break;
+
+	if (index == MAX_NUM_SVCS) {
+		spin_unlock_irqrestore(&xcpm->interface_lock, flags);
+		ret = -ENOMEM;
+		goto register_service_exit;
+	}
+
+	xcpm->svcs[index].ctrl_message_type = s_info->ctrl_message_type;
+	xcpm->svcs[index].resource_flag_index = s_info->resource_flag_index;
+	xcpm->svcs[index].receive_handler = s_info->receive_handler;
+	xcpm->svcs[index].abort_handler = s_info->abort_handler;
+	xcpm->svcs[index].svc_state = SERVICE_UP;
+	spin_lock_init(&xcpm->svcs[index].callup_lock);
+
+	/*
+	 * On the next XSMP register, the presence of
+	 * the new service gets reflected
+	 */
+	xcpm->resource_flags |= (1 << xcpm->svcs[index].resource_flag_index);
+
+	spin_unlock_irqrestore(&xcpm->interface_lock, flags);
+
+	ret = index;
+
+	/* Tell all connected XCFMs that we have a new service up */
+	broadcast_service_status();
+register_service_exit:
+	return ret;
+}
+EXPORT_SYMBOL(xcpm_register_service);
+
+int xcpm_unregister_service(int service_id)
+{
+	int ret;
+
+	if (service_id < 0 || service_id >= MAX_NUM_SVCS) {
+		ret = -EINVAL;
+		goto unregister_service_exit;
+	}
+
+	if (xcpm->svcs[service_id].svc_state != SERVICE_UP) {
+		ret = -EHOSTDOWN;
+		goto unregister_service_exit;
+	}
+
+	/* Service no longer available */
+	xcpm->svcs[service_id].svc_state = SERVICE_DOWN;
+
+	/* Show the service as down on the next 'register' */
+	xcpm->resource_flags &= ~(1 << xcpm->svcs[service_id].resource_flag_index);
+
+	/* Tell all XCFMs that a service is down */
+	broadcast_service_status();
+
+	ret = 0;
+
+unregister_service_exit:
+	return ret;
+}
+EXPORT_SYMBOL(xcpm_unregister_service);
+
+int xcpm_send_message(int link, int service_id, u8 *data, int length)
+{
+	int ret;
+
+	if (link < 0 || link >= MAX_NUM_LINKS) {
+		ret = -EINVAL;
+		goto send_message_exit;
+	}
+
+	if (service_id < 0 || service_id >= MAX_NUM_SVCS) {
+		ret = -EINVAL;
+		goto send_message_exit;
+	}
+
+	if (xcpm->svcs[service_id].svc_state != SERVICE_UP) {
+		ret = -EHOSTDOWN;
+		goto send_message_exit;
+	}
+
+	/* Transmit the message over the link specified */
+	ret = transmit_to_xcm(link, data, length);
+send_message_exit:
+	return ret;
+}
+EXPORT_SYMBOL(xcpm_send_message);
+
+int xcpm_query_link(int link, struct query_link_info *q_info)
+{
+	int ret;
+	union ib_gid gid;
+
+	if (link < 0 || link >= MAX_NUM_LINKS || !q_info) {
+		ret = -EINVAL;
+		goto query_link_exit;
+	}
+	if (xcpm->links[link].link_state == LINK_DEAD) {
+		ret = -ENOLINK;
+		goto query_link_exit;
+	}
+
+	q_info->device = xcpm->links[link].ib_link.port->device;
+	q_info->port = xcpm->links[link].ib_link.port->port_num;
+	q_info->pd = xcpm->links[link].ib_link.port->pd;
+	q_info->mr = xcpm->links[link].ib_link.port->mr;
+
+	ret = ib_get_cached_gid(xcpm->links[link].ib_link.port->device,
+				xcpm->links[link].ib_link.port->port_num,
+				0, &gid);
+	if (ret)
+		q_info->dgid.global.subnet_prefix = cpu_to_be64(DEFAULT_SUBNET_PREFIX);
+	else
+		q_info->dgid.global.subnet_prefix = gid.global.subnet_prefix;
+
+	q_info->dgid.global.interface_id = xcpm->links[link].ib_link.link_xcm.port_id;
+	q_info->dlid = xcpm->links[link].ib_link.link_xcm.xcm_lid;
+	q_info->sgid = xcpm->links[link].ib_link.port->gid;
+	q_info->slid = xcpm->links[link].ib_link.port->lid;
+
+query_link_exit:
+	return ret;
+}
+EXPORT_SYMBOL(xcpm_query_link);
+
+/*
+ * Handler that executes when there has been no communication from the XCM
+ * for a certain time period. This indicates that the link is down
+ */
+static void linkstate_timer_handler(struct work_struct *work)
+{
+	struct link_info *plink = container_of(work, struct link_info,
+					       linkstate_timer.work);
+	int link = (int)(plink - &xcpm->links[0]);
+	struct timeval tv;
+	unsigned long flags;
+
+	/* Don't do anything if the link already got deleted */
+	if (plink->link_state == LINK_DEAD)
+		return;
+
+	spin_lock_irqsave(&xcpm->link_lock, flags);
+	plink->link_state = LINK_DOWN;
+	spin_unlock_irqrestore(&xcpm->link_lock, flags);
+
+	do_gettimeofday(&tv);
+	xcpm_debug(KERN_WARNING, "Session Timeout, link %d [secs: %d]\n",
+		   link, (int) tv.tv_sec);
+	plink->session_timeouts++;
+
+	if (!atomic_read(&xcpm->xcpm_down)) {
+		/* Disconnect the link */
+		bring_down_link(link);
+
+		/* Restart the link timer */
+		queue_delayed_work(xcpm_wq, &plink->linkstate_timer,
+				   plink->linkstate_timeout * HZ);
+
+		/* Start the datapath timer if it isn't already */
+		if (!plink->datapath_timer_on &&
+		    !plink->datapath_timeout_disabled) {
+			plink->datapath_timer_on = 1;
+			queue_delayed_work(xcpm_wq, &plink->datapath_timer,
+					   plink->datapath_timeout * HZ);
+		}
+
+		/* We need this for messages to go out and be received back */
+		spin_lock_irqsave(&xcpm->link_lock, flags);
+		plink->link_state = LINK_INIT;
+		spin_unlock_irqrestore(&xcpm->link_lock, flags);
+
+		plink->send_seq_number = plink->recv_seq_number = 0;
+		plink->hellos_received = plink->hellos_sent = 0;
+		plink->confirmed = 0;
+
+		/* Try connecting again */
+		ib_if_link_connect(link, &xcpm->links[link].ib_link);
+	}
+}
+
+static void set_linkstate(int link, int state)
+{
+	struct link_info *plink = &xcpm->links[link];
+	unsigned long flags;
+
+	spin_lock_irqsave(&xcpm->link_lock, flags);
+	plink->link_state = state;
+	spin_unlock_irqrestore(&xcpm->link_lock, flags);
+}
+
+static void datapath_timer_handler(struct work_struct *work)
+{
+	struct link_info *plink = container_of(work, struct link_info,
+					       datapath_timer.work);
+	int link = (int)(plink - &xcpm->links[0]);
+
+	xcpm_debug(KERN_WARNING, "Datapath Timeout, link %d\n", link);
+
+	flush_workqueue(xcpm_wq);
+
+	cancel_delayed_work(&plink->linkstate_timer);
+	cancel_delayed_work(&plink->datapath_timer);
+
+	abort_datapaths_on_link(link);
+	bring_down_link(link);
+
+	/*
+	 * The link is disabled
+	 * may be restarted next time we hear from the SM/SA
+	 */
+	set_linkstate(link, LINK_DISABLED);
+}
+
+/*
+ * Process an incoming message
+ * Either dispatch it to a service driver or use it locally
+ */
+void process_incoming_msg(int link, u8 *buf, int length)
+{
+	int count;
+	int delivered = 0;
+
+	if (length == 0 || buf == 0) {
+		xcpm_debug(KERN_ERR, "Empty message received\n");
+		if (length == 0)
+			log_link_error(link, XSMP_MESSAGE_LENGTH_INVALID);
+		goto process_incoming_msg_exit;
+	}
+
+	/* Make sure that the arriving message has a sequence number in order */
+	if (!check_recv_seq_number(link, xsmp_get_seq_number(buf)))
+		seq_number_action(link, xsmp_get_seq_number(buf));
+
+	if (xsmp_is_local_msg(buf)) {
+		xsmp_process_local_msg(link, buf, length);
+		delivered = 1;
+		goto process_incoming_msg_exit;
+	}
+
+	/*
+	 * The message belongs to a service driver
+	 * Find the service and deliver the message
+	 */
+	for (count = 0; count < MAX_NUM_SVCS; count++) {
+		struct svc_info *service = &xcpm->svcs[count];
+
+		/* If the service is active and the msg belongs to this service */
+		if (service->svc_state == SERVICE_UP &&
+		    xsmp_msg_belongs(service->ctrl_message_type, buf)) {
+			if (xcpm->links[link].link_state == LINK_UP &&
+			    xcpm->svcs[count].receive_handler)
+				xcpm->svcs[count].receive_handler(link, buf, length);
+			delivered = 1;
+			break;
+		}
+	}
+
+	if (!delivered) {
+		xcpm_debug(KERN_WARNING, "Undeliverable message, dropping...\n");
+		log_link_error(link, XSMP_UNDELIVERABLE_MSG_ERROR);
+	}
+
+process_incoming_msg_exit:
+	return;
+}
+
+/*
+ * Executed by the IB completion handler to process the messages
+ * Runs in the context of a work queue
+ */
+static void receive_and_process_msgs(struct work_struct *work)
+{
+	struct link_info *link_s = container_of(work, struct link_info,
+						msg_dispatch_work);
+	int link = (int)(link_s - &xcpm->links[0]);
+	struct ib_cq *cq;
+
+	/* Ignore messages if the link is down */
+	if (link_s->link_state == LINK_DOWN || link_s->link_state == LINK_DEAD)
+		return;
+
+	cq = ib_if_get_recv_cq(&link_s->ib_link);
+
+	ib_if_recv_comp_handler(&xcpm->links[link].ib_link, cq);
+}
+
+int is_link_alive(int link)
+{
+	if (link >= MAX_NUM_LINKS || link < 0) {
+		xcpm_debug(KERN_WARNING,
+			   "Checking state of invalid link index %d\n", link);
+		return 0;
+	}
+
+	return (xcpm->links[link].link_state == LINK_UP);
+}
+
+/* Check if the link got a confirmation */
+int is_link_confirmed(int link)
+{
+	if (link >= MAX_NUM_LINKS || link < 0) {
+		xcpm_debug(KERN_WARNING,
+			   "Checking state of invalid link index %d\n", link);
+		return 0;
+	}
+
+	return xcpm->links[link].confirmed;
+}
+
+/* Update the expiry time of the timer */
+void update_linkstate(int link)
+{
+	struct link_info *plink = &xcpm->links[link];
+	struct delayed_work *work = &plink->linkstate_timer;
+	unsigned long flags;
+
+	if (!cancel_delayed_work(work))
+		flush_workqueue(xcpm_wq);
+
+	if (plink->link_state == LINK_DOWN) {
+		xcpm_debug(KERN_WARNING,
+			   "Link %d is down, cannot restart the timer\n", link);
+		return;
+	}
+
+	spin_lock_irqsave(&xcpm->link_lock, flags);
+	plink->link_state = LINK_UP;
+	spin_unlock_irqrestore(&xcpm->link_lock, flags);
+
+	if (!atomic_read(&xcpm->xcpm_down))
+		queue_delayed_work(xcpm_wq, work,
+				   plink->linkstate_timeout * HZ);
+}
+
+/* Allocate and initialize a link */
+static void link_init(int link_number)
+{
+	struct link_info *link = &xcpm->links[link_number];
+
+	link->link_index = link_number;
+
+	INIT_WORK(&link->msg_dispatch_work, &receive_and_process_msgs);
+	INIT_DELAYED_WORK(&link->linkstate_timer, &linkstate_timer_handler);
+	INIT_DELAYED_WORK(&link->datapath_timer, &datapath_timer_handler);
+
+	link->datapath_timer_on = 0;
+	link->send_seq_number = link->recv_seq_number = 0;
+	link->hellos_received = link->hellos_sent = 0;
+	link->confirmed = 0;
+	link->linkstate_timeout = 3 * XCPM_DEFAULT_HELLO_INTERVAL;
+	link->datapath_timeout = XCPM_LINK_DATAPATH_TIMEOUT_SECS;
+};
+
+/*
+ * Check to see if the recv sequence number is in order
+ * Increment it as a side effect
+ */
+static int check_recv_seq_number(int link, u32 recv_seq_number)
+{
+	int ret;
+	struct link_info *plink = &xcpm->links[link];
+
+	ret = (recv_seq_number >= plink->recv_seq_number);
+
+	plink->recv_seq_number = recv_seq_number + 1;
+
+	return ret;
+}
+
+/*
+ * Action taken when the receive sequence number are detected
+ * out of order on a link
+ */
+static void seq_number_action(int link, u32 recv_seq_number)
+{
+	xcpm_debug(KERN_ERR,
+		   "Receive sequence number %d out of order on link: %d...\n",
+		   recv_seq_number, link);
+	if (xcpm->links[link].link_state != LINK_UP)
+		printk(KERN_WARNING PFX "link %d not up, so ignoring\n", link);
+	else {
+		printk(KERN_DEBUG PFX "link %d is up\n", link);
+		printk(KERN_DEBUG PFX
+		       "issuing a shutdown and aborting datapaths\n");
+
+		xsmp_send_shutdown(link);
+		abort_datapaths_on_link(link);
+		bring_down_link(link);
+	}
+}
+
+/*
+ * Obtain the 'guid' for the port that the logical link resides on
+ * In network byte order
+ */
+u64 get_link_guid(int link)
+{
+	struct link_info *plink = &xcpm->links[link];
+
+	return cpu_to_be64(plink->ib_link.port->guid);
+}
+
+/*
+ * Return the GUID for the destination
+ * In network byte order
+ */
+u64 get_dest_guid(int link)
+{
+	struct link_info *plink = &xcpm->links[link];
+
+	return plink->ib_link.link_xcm.port_id;
+}
+
+/*
+ * Abort the datapaths that were installed via this link
+ * Needs to be used before the link goes down
+ */
+void abort_datapaths_on_link(int link)
+{
+	int count;
+
+	for (count = 0; count < MAX_NUM_SVCS; count++) {
+		if (xcpm->svcs[count].svc_state != SERVICE_UP)
+			continue;
+		if (xcpm->svcs[count].abort_handler)
+			xcpm->svcs[count].abort_handler(link);
+	}
+}
+
+void schedule_port_sweep(struct ib_port_info *port, int fast_poll)
+{
+	unsigned long delay;
+
+	/* Need to query the SA for this port */
+	port->queried = 0;
+
+	/*
+	 * Schedule the port sweep operation to restart the link later
+	 * If recovery is not disabled
+	 */
+	if (!port->port_down && !norecovery) {
+		if (fast_poll)
+			delay = 5 * HZ;
+		else
+			delay = port_sweep_timeout * HZ;
+		queue_delayed_work(xcpm_wq, &port->port_sweep_work, delay);
+	}
+}
+
+/*
+ * Bring down the link: link state will be down
+ * and the link will be unconnected
+ */
+void bring_down_link(int link)
+{
+	struct link_info *plink = &xcpm->links[link];
+	unsigned long flags;
+
+	spin_lock_irqsave(&xcpm->link_lock, flags);
+	if (plink->link_state != LINK_DEAD)
+		plink->link_state = LINK_DOWN;
+	spin_unlock_irqrestore(&xcpm->link_lock, flags);
+
+	plink->send_seq_number = 0;
+	plink->recv_seq_number = 0;
+
+	ib_if_link_exit(&plink->ib_link);
+}
+
+/* Bring down, disconnect, and remove the sysfs entries */
+void delete_link(int link)
+{
+	struct link_info *plink = &xcpm->links[link];
+	unsigned long flags;
+
+	if (plink->link_state == LINK_DEAD)
+		return;
+
+	spin_lock_irqsave(&xcpm->link_lock, flags);
+	plink->link_state = LINK_DEAD;
+	spin_unlock_irqrestore(&xcpm->link_lock, flags);
+
+	abort_datapaths_on_link(link);
+
+	bring_down_link(link);
+
+	/*
+	 * The flush is unconditional to make sure that non-delayed
+	 * queued work for the link is also completed
+	 */
+	cancel_delayed_work(&plink->linkstate_timer);
+	cancel_delayed_work(&plink->datapath_timer);
+
+	flush_workqueue(xcpm_wq);
+
+	cancel_delayed_work(&plink->linkstate_timer);
+	cancel_delayed_work(&plink->datapath_timer);
+
+	xcpm_link_remove_sysfs(link);
+
+	atomic_dec(&xcpm->num_links);
+	xcpm_debug(KERN_INFO, "Number of links now: %d\n",
+		   atomic_read(&xcpm->num_links));
+
+	/* Mark as an unused slot */
+	memset(plink, 0, sizeof(*plink));
+	plink->used = 0;
+}
+
+void set_link_ready(int link, int hello_interval, int datapath_timeout)
+{
+	struct link_info *plink = &xcpm->links[link];
+	unsigned long flags;
+
+	spin_lock_irqsave(&xcpm->link_lock, flags);
+	plink->link_state = LINK_UP;
+	spin_unlock_irqrestore(&xcpm->link_lock, flags);
+
+	xcpm_debug(KERN_INFO, "Received a REG_CONFIRM, link %d is up\n",
+		   link);
+
+	if (hello_interval < XCPM_MIN_HELLO_INTERVAL)
+		hello_interval = XCPM_MIN_HELLO_INTERVAL;
+	plink->linkstate_timeout = hello_interval * 3;
+
+	xcpm_debug(KERN_INFO, "Hello interval for link %d is %d seconds\n",
+		   link, hello_interval);
+
+	if (datapath_timeout == -1) {
+		plink->datapath_timeout_disabled = 1;
+
+		xcpm_debug(KERN_INFO, "Datapath timeout disabled for link %d\n",
+			   link);
+	} else {
+		if (datapath_timeout < 2 * plink->linkstate_timeout)
+			datapath_timeout = 2 * plink->linkstate_timeout;
+
+		xcpm_debug(KERN_INFO,
+			   "Datapath timeout for link %d is %d seconds\n", link,
+			   datapath_timeout);
+	}
+
+	plink->datapath_timeout = datapath_timeout;
+
+	plink->confirmed = 1;	/* Got a CONFIRM */
+
+	flush_workqueue(xcpm_wq);
+	cancel_delayed_work(&plink->datapath_timer);
+	plink->datapath_timer_on = 0;
+}
+
+struct ib_port_info *get_ib_port(int port_index)
+{
+	return &xcpm->ports[port_index];
+}
+
+static void xcpm_add_one(struct ib_device *device)
+{
+	int port_num, start_port, end_port;
+
+	xcpm->pd = ib_alloc_pd(device);
+	if (IS_ERR(xcpm->pd)) {
+		printk(KERN_ERR PFX "PD allocation failed %d\n",
+		       (int) PTR_ERR(xcpm->pd));
+		return;
+	}
+
+	xcpm->mr = ib_get_dma_mr(xcpm->pd, IB_ACCESS_LOCAL_WRITE |
+					   IB_ACCESS_REMOTE_READ |
+					   IB_ACCESS_REMOTE_WRITE);
+	if (IS_ERR(xcpm->mr)) {
+		printk(KERN_ERR PFX "MR allocation failed %d\n",
+		       (int) PTR_ERR(xcpm->mr));
+		ib_dealloc_pd(xcpm->pd);
+		xcpm->pd = 0;
+		return;
+	}
+
+	if (device->node_type == RDMA_NODE_IB_SWITCH) {
+		start_port = 0;
+		end_port = 0;
+	} else {
+		start_port = 1;
+		end_port = device->phys_port_cnt;
+	}
+	for (port_num = start_port; port_num <= end_port; port_num++) {
+		int port_index;
+		struct ib_port_info *ib_port = 0;
+
+		for (port_index = 0; port_index < MAX_NUM_PORTS; port_index++)
+			if (!xcpm->ports[port_index].used)
+				break;
+
+		if (port_index == MAX_NUM_PORTS) {
+			printk(KERN_WARNING PFX "MAX_NUM_PORTS exceeded\n");
+			return;
+		}
+
+		ib_port = &xcpm->ports[port_index];
+		ib_port->used = 1;
+
+		ib_if_port_init(device, port_num, xcpm->pd, xcpm->mr, ib_port,
+				&ib_port->xds_handle);
+
+		/* Attempt to retrieve all the assigned XCMs */
+		ib_if_sa_query_xds(ib_port);
+
+		atomic_inc(&xcpm->num_ports);
+	}
+}
+
+void increment_hellos_received(int link)
+{
+	xcpm->links[link].hellos_received++;
+	if (xcpm->links[link].hellos_received % stats_frequency ==
+	    stats_frequency - 1)
+		send_error_counts(link);
+}
+
+void increment_hellos_sent(int link)
+{
+	xcpm->links[link].hellos_sent++;
+}
+
+int initialize_and_connect_link(int index, struct xcfm_record *xcfm_record,
+				struct ib_port_info *ib_port,
+				struct ib_link_info *ib_link)
+{
+	int ret;
+	struct link_info *plink = &xcpm->links[index];
+
+	ib_if_link_init(index, xcfm_record, ib_port, ib_link);
+
+	/*
+	 * Setup a new link, increment the link count,
+	 * set link state to 'LINK_INIT'
+	 */
+	link_init(index);
+
+	set_linkstate(index, LINK_INIT);
+
+	if (!atomic_read(&xcpm->xcpm_down)) {
+		if (!noconntimeout)
+			queue_delayed_work(xcpm_wq,
+					   &xcpm->links[index].
+					   linkstate_timer,
+					   plink->linkstate_timeout * HZ);
+	}
+
+	/* Connect to the XCM using the CM and register with the XCM */
+	if ((ret = ib_if_link_connect(index, &xcpm->links[index].ib_link))) {
+		bring_down_link(index);
+		printk(KERN_WARNING PFX "link connect error %d\n", ret);
+	}
+
+	return ret;
+}
+
+int add_link(int index, struct xcfm_record *xcfm_record,
+	     struct ib_port_info *ib_port, struct ib_link_info *ib_link)
+{
+	int ret = initialize_and_connect_link(index, xcfm_record, ib_port,
+					      ib_link);
+	if (!ret) {
+		xcpm_link_add_sysfs(index);
+		atomic_inc(&xcpm->num_links);
+	}
+	return ret;
+}
+
+/*
+ * For a given device and port, we have received a list of XCMs
+ * so we allocate the port and the links here
+ */
+void allocate_port_and_links(struct ib_port_info *ib_port,
+			     struct xcm_list *list)
+{
+	int count, index;
+	u8 link_seen[MAX_NUM_LINKS];
+	unsigned long flags;
+
+	memset(link_seen, 0, MAX_NUM_LINKS);
+
+	/* For all the XCMs for this port */
+	for (count = 0; count < list->count; count++) {
+		int exists = 0;
+
+		/* Let's see if a link for this record already exists */
+
+		/* For all existing links */
+		for (index = 0; index < MAX_NUM_LINKS; index++) {
+
+			/*
+			 * Don't even look at the unused slots
+			 * If the info comes again, a new link will be
+			 * created
+			 */
+			if (!xcpm->links[index].used)
+				continue;
+
+			/* A different port */
+			if (xcpm->links[index].ib_link.port != ib_port)
+				continue;
+
+			/* No match */
+			if (!(ib_if_link_match(&list->xcms[count],
+					       &xcpm->links[index].ib_link)))
+				continue;
+
+			exists = 1;
+
+			/* Mark the existing matched link as seen */
+			link_seen[index] = 1;
+
+			/* Match, but the link is in use */
+			if (xcpm->links[index].link_state != LINK_DISABLED)
+				continue;
+
+			/* Match and the link is down */
+
+			/* Restart the link */
+			if (initialize_and_connect_link(index,
+							&list->xcms[count],
+							ib_port,
+							&xcpm->links[index].
+							ib_link))
+				continue;
+		}
+
+		/* We had a match earlier */
+		if (exists)
+			continue;
+
+		spin_lock_irqsave(&xcpm->link_lock, flags);
+
+		/* Find an unused slot */
+		for (index = 0; index < MAX_NUM_LINKS; index++) {
+			if (!xcpm->links[index].used) {
+				xcpm->links[index].used = 1;
+				break;
+			}
+		}
+
+		spin_unlock_irqrestore(&xcpm->link_lock, flags);
+
+		if (index == MAX_NUM_LINKS) {
+			xcpm_debug(KERN_ERR,
+				   "Limit reached for the number of links: %d\n",
+				   MAX_NUM_LINKS);
+			break;
+		}
+
+		/* Mark the new link as seen */
+		link_seen[index] = 1;
+
+		/* Add the newly discovered link */
+		if (add_link(index, &list->xcms[count], ib_port,
+			     &xcpm->links[index].ib_link))
+			continue;
+
+		xcpm_debug(KERN_INFO, "Number of links now: %d\n",
+			   atomic_read(&xcpm->num_links));
+	}
+
+	/* Delete all the stale links that don't match the list */
+	for (index = 0; index < MAX_NUM_LINKS; index++) {
+		if (!link_seen[index] &&
+		    xcpm->links[index].ib_link.port &&
+		    xcpm->links[index].ib_link.port == ib_port &&
+		    xcpm->links[index].link_state != LINK_DEAD) {
+			xcpm_debug(KERN_INFO, "Deleting stale link: %d\n", index);
+			delete_link(index);
+		}
+	}
+
+}
+
+void startup_link(int index, u64 fw_ver, u32 hw_ver, u32 vendor_part_id)
+{
+	xsmp_link_connect_send(index, xcpm->resource_flags, fw_ver, hw_ver,
+			       vendor_part_id);
+}
+
+static void xcpm_remove_one(struct ib_device *device)
+{
+	int port_num, link_index, port_index, start_port, end_port;
+
+	if (device->node_type == RDMA_NODE_IB_SWITCH) {
+		start_port = 0;
+		end_port = 0;
+	} else {
+		start_port = 1;
+		end_port = device->phys_port_cnt;
+	}
+
+	for (port_num = start_port; port_num <= end_port; port_num++) {
+		struct ib_port_info *ib_port = 0;
+
+		xcpm_debug(KERN_INFO, "Number of links: %d\n",
+			   atomic_read(&xcpm->num_links));
+
+		/* Find the port */
+		for (port_index = 0; port_index < MAX_NUM_PORTS; port_index++)
+			/* If there is a port match */
+			if (xcpm->ports[port_index].device == device &&
+			    xcpm->ports[port_index].port_num == port_num &&
+			    xcpm->ports[port_index].used)
+				ib_port = &xcpm->ports[port_index];
+
+		if (!ib_port)
+			continue;
+
+		ib_port->port_down = 1;
+
+		if (!wait_event_timeout(xcpm_wait,
+	    				!atomic_read(&ib_port->refcount),
+					10 * HZ))
+			xcpm_debug(KERN_WARNING,
+				   "Warning: Timed out waiting for the reference count\n");
+
+		/* All the links */
+		for (link_index = 0; link_index < MAX_NUM_LINKS; link_index++)
+			/* If the link goes on this port */
+			if (xcpm->links[link_index].link_state != LINK_DEAD &&
+			    xcpm->links[link_index].ib_link.port->device == device &&
+			    xcpm->links[link_index].ib_link.port->port_num == port_num)
+				delete_link(link_index);
+
+		ib_if_port_exit(ib_port);
+		atomic_dec(&xcpm->num_ports);
+		ib_port->used = 0;
+	}
+
+	/* Don't exit in the middle of executing work functions */
+	flush_workqueue(xcpm_wq);
+
+	if (xcpm->mr) {
+		ib_dereg_mr(xcpm->mr);
+		xcpm->mr = 0;
+	}
+	if (xcpm->pd) {
+		ib_dealloc_pd(xcpm->pd);
+		xcpm->pd = 0;
+	}
+}
+
+static struct ib_client xcpm_client = {
+	.name = "xcpm",
+	.add = xcpm_add_one,
+	.remove = xcpm_remove_one
+};
+
+static void xcpm_startup_work_handler(struct work_struct *work)
+{
+	ib_if_init(&xcpm_client);
+}
+
+int xcpm_init(void)
+{
+	int ret = -ENOMEM;
+	int count;
+
+	xcpm_debug(KERN_ERR, "XCPM version %s\n", XCPM_VERSION);
+
+	/* Allocate the xcpm data structure */
+	xcpm = kmalloc(sizeof(*xcpm), GFP_KERNEL);
+	if (!xcpm) {
+		xcpm_debug(KERN_ERR, "xcpm_info struct allocation failed\n");
+		goto init_done;
+	}
+
+	memset(xcpm, 0, sizeof(*xcpm));
+
+	spin_lock_init(&xcpm->interface_lock);
+
+	/* Lock to serialize link slot allocation */
+	spin_lock_init(&xcpm->link_lock);
+
+	/* All services and links are unusable to begin with */
+	for (count = 0; count < MAX_NUM_SVCS; count++)
+		xcpm->svcs[count].svc_state = SERVICE_DOWN;
+
+	for (count = 0; count < MAX_NUM_LINKS; count++) {
+		xcpm->links[count].link_state = LINK_DEAD;
+		xcpm->links[count].used = 0;
+	}
+
+	atomic_set(&xcpm->num_links, 0);
+	atomic_set(&xcpm->num_ports, 0);
+
+	xcpm->resource_flags = 0;
+
+	init_waitqueue_head(&xcpm_wait);
+
+	xcpm_wq = create_singlethread_workqueue("xscorcpmwq");
+	if (!xcpm_wq)
+		goto leave_err;
+
+	INIT_DELAYED_WORK(&xcpm->startup_work, xcpm_startup_work_handler);
+
+	atomic_set(&xcpm->xcpm_down, 0);
+
+	ret = xcpm_register_sysfs();
+	if (ret)
+		goto leave_err2;
+
+	if (alloc_xsmp_mem_pool())
+		goto leave_err3;
+
+	if (alloc_ib_if_mem_pool()) {
+		dealloc_xsmp_mem_pool();
+		goto leave_err3;
+	}
+
+	queue_delayed_work(xcpm_wq, &xcpm->startup_work, XCPM_STACK_DELAY);
+
+	ret = 0;
+	goto init_done;
+
+leave_err3:
+	xcpm_unregister_sysfs();
+leave_err2:
+	destroy_workqueue(xcpm_wq);
+leave_err:
+	kfree(xcpm);
+
+init_done:
+	return ret;
+}
+
+void xcpm_exit(void)
+{
+	/* Kill the scheduled startup_work, if any */
+	int startup_work_stopped = cancel_delayed_work(&xcpm->startup_work);
+
+	/* The module is going down, no more scheduling */
+	atomic_set(&xcpm->xcpm_down, 1);
+
+	/* If we completely initialized (startup_work executed), then exit */
+	if (!startup_work_stopped)
+		ib_if_exit(&xcpm_client);
+
+	flush_workqueue(xcpm_wq);
+	destroy_workqueue(xcpm_wq);
+
+	dealloc_ib_if_mem_pool();
+
+	dealloc_xsmp_mem_pool();
+
+	xcpm_unregister_sysfs();
+
+	kfree(xcpm);
+
+	xcpm_debug(KERN_INFO, "exit complete\n");
+}
diff --git a/drivers/infiniband/ulp/xsigo/xscore/xcpm_export.h b/drivers/infiniband/ulp/xsigo/xscore/xcpm_export.h
new file mode 100644
index 0000000..5ac8810
--- /dev/null
+++ b/drivers/infiniband/ulp/xsigo/xscore/xcpm_export.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006-2008 Xsigo Systems 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 __XCPM_EXPORT_H__
+#define __XCPM_EXPORT_H__
+
+#define PFX "xscore/xcpm: "
+
+struct ib_cq;
+struct xcm_list;
+struct ib_port_info;
+
+extern wait_queue_head_t xcpm_wait;
+extern int boot_flag;
+
+#ifdef CONFIG_XSCORE_DEBUG 
+extern int xcpm_debug_level;
+
+#define xcpm_debug(level, fmt, args...) 				\
+            do {                                    			\
+                    if (xcpm_debug_level > 0)     			\
+			printk(level "<xscore:xcpm> %s: " fmt, __FUNCTION__ , ## args); \
+            } while (0)
+#else
+#define xcpm_debug(level, fmt, args...)
+#endif
+
+int transmit_to_xcm(int link, u8 *data, int length);
+void update_linkstate(int link);
+void abort_datapaths_on_link(int link);
+void bring_down_link(int link);
+void allocate_port_and_links(struct ib_port_info *ib_port,
+			     struct xcm_list *list);
+struct ib_port_info *get_ib_port(int port_index);
+void set_link_ready(int link, int hello_interval, int datapath_timeout);
+void startup_link(int index, u64 fw_ver, u32 hw_ver, u32 vendor_part_id);
+void process_incoming_msg(int link, u8 * buf, int length);
+int is_link_alive(int link);
+int is_link_confirmed(int link);
+void broadcast_service_status(void);
+u64 get_link_guid(int link);
+u64 get_dest_guid(int link);
+void send_service_status(int link);
+int send_error_counts(int link);
+void schedule_port_sweep(struct ib_port_info *port, int fast_poll);
+void increment_hellos_received(int link);
+void increment_hellos_sent(int link);
+void log_link_error(int link, int error_type);
+void delete_link(int link);
+
+#endif	/* __XCPM_EXPORT_H__ */
diff --git a/drivers/infiniband/ulp/xsigo/xscore/xcpm_interface.h b/drivers/infiniband/ulp/xsigo/xscore/xcpm_interface.h
new file mode 100644
index 0000000..45db24c
--- /dev/null
+++ b/drivers/infiniband/ulp/xsigo/xscore/xcpm_interface.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2006-2008 Xsigo Systems 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 __XCPM_INTERFACE_H__
+#define __XCPM_INTERFACE_H__
+
+/* The interface functions of the XCPM, used by the services */
+
+/*
+ * Semantics of the interface commands from the XCPM to a service driver
+ * using callback functions
+ * Exported by the service drivers, used by the XCPM
+ */
+
+/**
+ * xcpm_receive_message_handler - callback handler for received XCPM message
+ * @link: the link on which the message was received
+ * @data: received message data (in network byte order)
+ *   Data is owned by a receive buffer.
+ *   Data is NOT to be freed by the service driver.
+ * @length: length of the received data
+ */
+typedef void (*xcpm_receive_message_handler)(int link, u8 *data, int length);
+
+/**
+ * xcpm_abort_link_handler - callback handler for aborted XCPM link
+ * @link: the link that is being aborted
+ */
+typedef void (*xcpm_abort_link_handler)(int link);
+
+/**
+ * service_type_info - Passed by the service driver to XCPM
+ *   to register a new service
+ * @receive_handler: service driver receive message callback handler
+ *   (may be NULL)
+ * @abort_handler: service driver abort callback handler (may be NULL)
+ * @ctrl_message_type: XSMP message type (see xsmp_common.h) 
+ * @resource_flag_index: XSMP resource flag index (see xsmp_common.h) 
+ */
+struct service_type_info {
+	xcpm_receive_message_handler receive_handler;
+	xcpm_abort_link_handler abort_handler;
+	u16 ctrl_message_type;
+	u16 resource_flag_index;
+};
+
+/* Semantics of the interface commands from a service driver to the XCPM: */
+
+/**
+ * xcpm_register_service - Register service with XCPM
+ * @s_info: service type info for service driver being registered with XCPM 
+ *
+ * Return value:        a new service id allocated to the service driver.
+ *                      -EALREADY if the service is already up.
+ *                      -ENOMEM if a new service id cannot be allocated.
+ *                      -EINVAL if the input parameter is invalid.
+ */
+int xcpm_register_service(struct service_type_info *s_info);
+
+/**
+ * xcpm_unregister_service - Unregister service with XCPM
+ * @service_id: service_id allocated earlier to the service driver
+ *   when service was registered.
+ *
+ * Return value:        0 on success.
+ *                      -EHOSTDOWN if the service is not up
+ *                      (as seen by XCPM).
+ *                      -EINVAL if the input parameter is invalid.
+ */
+int xcpm_unregister_service(int service_id);
+
+/**
+ * xcpm_send_message - Send message to XCPM 
+ * @link: the logical link on which to send the message.
+ *   (on which the corresponding Vdevice was created).
+ * @service_id: service_id allocated earlier to the service driver
+ *   when service was registered.
+ * @data: message data to send (network byte order).
+ *   Data is freed by the XCPM.
+ * @length: length of the data to send.
+ *
+ * Return value:        0 on success.
+ *                      -ENOLINK if the link is down or non-existent.
+ *                      -EINVAL if the input parameters are invalid.
+ *                      other errors from ib_post_send on transmission
+ *                       failures on active links.
+ */
+int xcpm_send_message(int link, int service_id, u8 *data, int length);
+
+/**
+ * query_link_info - Passed to a service driver as information related
+ *  to an XCPM control link
+ */
+struct query_link_info {
+	struct ib_device *device;
+	int port;
+	struct ib_pd *pd;
+	struct ib_mr *mr;
+
+	/* Local address parameters */
+	u16 slid;
+	union ib_gid sgid;
+
+	/* Remote address parameters */
+	u16 dlid;
+	union ib_gid dgid;
+};
+
+/**
+ * xcpm_query_link - Query XCPM link
+ * @link: the XCPM link index for which the query is made.
+ * @q_info: pointer to 'struct query_link_info' where queried link info
+ *   is returned. 
+ *
+ * Return value:        0 on success.
+ *                      -EINVAL if the input parameters are invalid.
+ *                      -ENOLINK if the link does not exist.
+ */
+int xcpm_query_link(int link, struct query_link_info *q_info);
+
+#endif	/* __XCPM_INTERFACE_H__ */
diff --git a/drivers/infiniband/ulp/xsigo/xscore/xcpm_priv.h b/drivers/infiniband/ulp/xsigo/xscore/xcpm_priv.h
new file mode 100644
index 0000000..14783dc
--- /dev/null
+++ b/drivers/infiniband/ulp/xsigo/xscore/xcpm_priv.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2006-2008 Xsigo Systems 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 __XCPM_PRIV_H__
+#define __XCPM_PRIV_H__
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/if_infiniband.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "ib_if.h"
+#include "xcpm_interface.h"
+#include "xsmp_session.h"
+
+#define MAX_NUM_SVCS	32
+#define MAX_NUM_LINKS	32
+#define MAX_NUM_PORTS	32
+
+#define XCPM_LINK_TIMEOUT_SECS		9
+#define XCPM_DEFAULT_HELLO_INTERVAL	5
+#define XCPM_MIN_HELLO_INTERVAL		3
+#define XCPM_LINK_DATAPATH_TIMEOUT_SECS	45
+#define XCPM_PORT_SWEEP_INTERVAL_SECS	15
+
+enum xcpm_link_state {
+	LINK_DEAD = 0,
+	LINK_INIT,
+	LINK_UP,
+	LINK_DISABLED,
+	LINK_DOWN
+};
+
+enum xcpm_service_state {
+	SERVICE_DOWN = 10,
+	SERVICE_UP
+};
+
+/* Describes a particular service */
+struct svc_info {
+	enum xcpm_service_state svc_state; /* Service state: active or not */
+
+	/* The callbacks for the control messages */
+	xcpm_receive_message_handler receive_handler;
+	xcpm_abort_link_handler abort_handler;
+
+	u16 ctrl_message_type; /* This is to identify control messages that belong to this service */
+
+	/*
+	 * Index into the resource flag field passed to the XCFM
+	 * indicating which services are up
+	 */
+	u16 resource_flag_index;
+
+	/*
+	 * Spinlock to serialize access to the service
+	 * driver's interface function
+	 */
+	spinlock_t callup_lock;
+};
+
+/* One logical link from the host to the XCM */
+struct link_info {
+	int link_index;
+
+	struct ib_link_info ib_link; /* Local details of the logical link */
+
+	struct class_device link_class_dev;
+
+	/*
+	 * Spinlock to synchronize access to the transmit path
+	 * of the link (the queue pair)
+	 */
+	spinlock_t tx_lock;
+
+	enum xcpm_link_state link_state;	/* The state of the link */
+
+	struct delayed_work linkstate_timer; /* Timer to track the link state */
+
+	struct delayed_work datapath_timer; /* Timer to track the datapath expiry time */
+
+	int datapath_timer_on;	/* Tells us whether the timer is currently active or not */
+	int linkstate_timeout;	/* Timeout after which a link is declared inactive */
+	int datapath_timeout;	/* Timeout after which datapaths established over the link are aborted */
+	int datapath_timeout_disabled; /* Whether we want to have a datapath timeout at all */
+
+	struct work_struct msg_dispatch_work; /* Work queue to offload message processing from the interrupt handler */
+
+	u64 send_seq_number, recv_seq_number; /* Sequence numbers for the messages */
+	int confirmed;	/* Flag to indicate whether we got a confirm back */
+	u32 error_counts[XSMP_MAX_ERROR_TYPES]; /* Error counts on the link */
+
+	/* Count of the number of HELLOs that went across */
+	int hellos_received;
+	int hellos_sent;
+
+	int used;	/* Whether the slot is in use */
+	int session_timeouts;
+};
+
+/* The xcpm data structure */
+struct xcpm_info {
+	struct svc_info svcs[MAX_NUM_SVCS]; /* All the services supported on this server, one entry per type */
+
+	struct link_info links[MAX_NUM_LINKS]; /* All logical links with the XCMs */
+
+	/*
+	 * Count of the links to the XCMs
+	 * 0 to num_links - 1 are always valid links (whether up or down)
+	 * To the contrary, the service list can have 'holes'
+	 */
+	atomic_t num_links;
+
+	struct ib_port_info ports[MAX_NUM_PORTS]; /* The physical ports on the various HCAs */
+
+	atomic_t num_ports;	/* Number of ports */
+	spinlock_t interface_lock; /* Synchronize calls to the interface function exported by the XCPM */
+	u32 resource_flags;	/* Track which services are up */
+
+	struct delayed_work startup_work;
+
+	atomic_t xcpm_down;	/* A global flag indicating that the module is going down */
+	spinlock_t link_lock;
+	struct ib_pd *pd;
+	struct ib_mr *mr;
+};
+
+#endif	/* __XCPM_PRIV_H__ */
-- 
1.5.2






More information about the ewg mailing list