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 <[EMAIL PROTECTED]>
---
 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



_______________________________________________
ewg mailing list
[email protected]
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/ewg

Reply via email to