[ofw] [PATCH 7/7] librdmacm: provide OFED compatability library
Sean Hefty
sean.hefty at intel.com
Fri Jan 16 15:00:57 PST 2009
Provide a port of librdmacm.
Because of the use of overlapped structures and events, the library
has a scalability limitation of about 60 connections. Since the
only known way around this limitation that I'm aware of requires
adding threads to the library, the scalability limit will be addressed
in a subsequent version, once the needs of a real application are
determined.
Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
diff -up -N trunk\ulp\librdmacm\include\rdma\/rdma_cma.h branches\winverbs\ulp\librdmacm\include\rdma/rdma_cma.h
--- trunk\ulp\librdmacm\include\rdma\/rdma_cma.h 1969-12-31 16:00:00.000000000 -0800
+++ branches\winverbs\ulp\librdmacm\include\rdma/rdma_cma.h 2009-01-12 14:41:27.573634000 -0800
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2005-2009 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under the OpenFabrics.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 AWV
+ * 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.
+ */
+
+#pragma once
+
+#if !defined(RDMA_CMA_H)
+#define RDMA_CMA_H
+
+#include <windows.h>
+#include <infiniband\verbs.h>
+#include <rdma\winverbs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Interfaces based on librdmacm 1.0.8.
+ */
+
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+
+/*
+ * Upon receiving a device removal event, users must destroy the associated
+ * RDMA identifier and release all resources allocated with the device.
+ */
+enum rdma_cm_event_type
+{
+ RDMA_CM_EVENT_ADDR_RESOLVED,
+ RDMA_CM_EVENT_ADDR_ERROR,
+ RDMA_CM_EVENT_ROUTE_RESOLVED,
+ RDMA_CM_EVENT_ROUTE_ERROR,
+ RDMA_CM_EVENT_CONNECT_REQUEST,
+ RDMA_CM_EVENT_CONNECT_RESPONSE,
+ RDMA_CM_EVENT_CONNECT_ERROR,
+ RDMA_CM_EVENT_UNREACHABLE,
+ RDMA_CM_EVENT_REJECTED,
+ RDMA_CM_EVENT_ESTABLISHED,
+ RDMA_CM_EVENT_DISCONNECTED,
+ RDMA_CM_EVENT_DEVICE_REMOVAL,
+ RDMA_CM_EVENT_MULTICAST_JOIN,
+ RDMA_CM_EVENT_MULTICAST_ERROR,
+ RDMA_CM_EVENT_ADDR_CHANGE,
+ RDMA_CM_EVENT_TIMEWAIT_EXIT
+};
+
+enum rdma_port_space
+{
+ RDMA_PS_IPOIB = 0x0002,
+ RDMA_PS_TCP = 0x0106,
+ RDMA_PS_UDP = 0x0111,
+};
+
+/*
+ * Global qkey value for UDP QPs and multicast groups created via the
+ * RDMA CM.
+ */
+#define RDMA_UDP_QKEY 0x01234567
+
+struct ib_addr
+{
+ union ibv_gid sgid;
+ union ibv_gid dgid;
+ uint16_t pkey;
+};
+
+struct rdma_addr
+{
+ struct sockaddr src_addr;
+ uint8_t src_pad[sizeof(SOCKADDR_IN6) -
+ sizeof(struct sockaddr)];
+ struct sockaddr dst_addr;
+ uint8_t dst_pad[sizeof(SOCKADDR_IN6) -
+ sizeof(struct sockaddr)];
+ union
+ {
+ struct ib_addr ibaddr;
+ } addr;
+};
+
+struct ibv_sa_path_rec
+{
+ uint8_t data[64];
+};
+
+struct rdma_route
+{
+ struct rdma_addr addr;
+ struct ibv_sa_path_rec *path_rec;
+ int num_paths;
+};
+
+struct rdma_event_channel
+{
+ uint32_t timeout;
+};
+
+struct rdma_cm_id
+{
+ struct ibv_context *verbs;
+ struct rdma_event_channel *channel;
+ void *context;
+ struct ibv_qp *qp;
+ struct rdma_route route;
+ enum rdma_port_space ps;
+ uint8_t port_num;
+
+ union {
+ IWVConnectEndpoint *connect;
+ IWVDatagramEndpoint *datagram;
+ } ep;
+ OVERLAPPED overlap;
+ uint32_t events_completed;
+};
+
+struct rdma_conn_param
+{
+ const void *private_data;
+ uint8_t private_data_len;
+ uint8_t responder_resources;
+ uint8_t initiator_depth;
+ uint8_t flow_control;
+ uint8_t retry_count; /* ignored when accepting */
+ uint8_t rnr_retry_count;
+ /* Fields below ignored if a QP is created on the rdma_cm_id. */
+ uint8_t srq;
+ uint32_t qp_num;
+};
+
+struct rdma_ud_param
+{
+ const void *private_data;
+ uint8_t private_data_len;
+ struct ibv_ah_attr ah_attr;
+ uint32_t qp_num;
+ uint32_t qkey;
+};
+
+struct rdma_cm_event
+{
+ struct rdma_cm_id *id;
+ struct rdma_cm_id *listen_id;
+ enum rdma_cm_event_type event;
+ int status;
+ union
+ {
+ struct rdma_conn_param conn;
+ struct rdma_ud_param ud;
+
+ } param;
+};
+
+/**
+ * rdma_create_event_channel - Open a channel used to report communication events.
+ * Description:
+ * Asynchronous events are reported to users through event channels. Each
+ * event channel maps to a file descriptor.
+ * Notes:
+ * All created event channels must be destroyed by calling
+ * rdma_destroy_event_channel. Users should call rdma_get_cm_event to
+ * retrieve events on an event channel.
+ * See also:
+ * rdma_get_cm_event, rdma_destroy_event_channel
+ */
+__declspec(dllexport)
+struct rdma_event_channel *rdma_create_event_channel(void);
+
+/**
+ * rdma_destroy_event_channel - Close an event communication channel.
+ * @channel: The communication channel to destroy.
+ * Description:
+ * Release all resources associated with an event channel and closes the
+ * associated file descriptor.
+ * Notes:
+ * All rdma_cm_id's associated with the event channel must be destroyed,
+ * and all returned events must be acked before calling this function.
+ * See also:
+ * rdma_create_event_channel, rdma_get_cm_event, rdma_ack_cm_event
+ */
+__declspec(dllexport)
+void rdma_destroy_event_channel(struct rdma_event_channel *channel);
+
+/**
+ * rdma_create_id - Allocate a communication identifier.
+ * @channel: The communication channel that events associated with the
+ * allocated rdma_cm_id will be reported on.
+ * @id: A reference where the allocated communication identifier will be
+ * returned.
+ * @context: User specified context associated with the rdma_cm_id.
+ * @ps: RDMA port space.
+ * Description:
+ * Creates an identifier that is used to track communication information.
+ * Notes:
+ * Rdma_cm_id's are conceptually equivalent to a socket for RDMA
+ * communication. The difference is that RDMA communication requires
+ * explicitly binding to a specified RDMA device before communication
+ * can occur, and most operations are asynchronous in nature. Communication
+ * events on an rdma_cm_id are reported through the associated event
+ * channel. Users must release the rdma_cm_id by calling rdma_destroy_id.
+ * See also:
+ * rdma_create_event_channel, rdma_destroy_id, rdma_get_devices,
+ * rdma_bind_addr, rdma_resolve_addr, rdma_connect, rdma_listen,
+ */
+__declspec(dllexport)
+int rdma_create_id(struct rdma_event_channel *channel,
+ struct rdma_cm_id **id, void *context,
+ enum rdma_port_space ps);
+
+/**
+ * rdma_destroy_id - Release a communication identifier.
+ * @id: The communication identifier to destroy.
+ * Description:
+ * Destroys the specified rdma_cm_id and cancels any outstanding
+ * asynchronous operation.
+ * Notes:
+ * Users must free any associated QP with the rdma_cm_id before
+ * calling this routine and ack an related events.
+ * See also:
+ * rdma_create_id, rdma_destroy_qp, rdma_ack_cm_event
+ */
+__declspec(dllexport)
+int rdma_destroy_id(struct rdma_cm_id *id);
+
+/**
+ * rdma_bind_addr - Bind an RDMA identifier to a source address.
+ * @id: RDMA identifier.
+ * @addr: Local address information. Wildcard values are permitted.
+ * Description:
+ * Associates a source address with an rdma_cm_id. The address may be
+ * wildcarded. If binding to a specific local address, the rdma_cm_id
+ * will also be bound to a local RDMA device.
+ * Notes:
+ * Typically, this routine is called before calling rdma_listen to bind
+ * to a specific port number, but it may also be called on the active side
+ * of a connection before calling rdma_resolve_addr to bind to a specific
+ * address.
+ * See also:
+ * rdma_create_id, rdma_listen, rdma_resolve_addr, rdma_create_qp
+ */
+__declspec(dllexport)
+int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr);
+
+/**
+ * rdma_resolve_addr - Resolve destination and optional source addresses.
+ * @id: RDMA identifier.
+ * @src_addr: Source address information. This parameter may be NULL.
+ * @dst_addr: Destination address information.
+ * @timeout_ms: Time to wait for resolution to complete.
+ * Description:
+ * Resolve destination and optional source addresses from IP addresses
+ * to an RDMA address. If successful, the specified rdma_cm_id will
+ * be bound to a local device.
+ * Notes:
+ * This call is used to map a given destination IP address to a usable RDMA
+ * address. If a source address is given, the rdma_cm_id is bound to that
+ * address, the same as if rdma_bind_addr were called. If no source
+ * address is given, and the rdma_cm_id has not yet been bound to a device,
+ * then the rdma_cm_id will be bound to a source address based on the
+ * local routing tables. After this call, the rdma_cm_id will be bound to
+ * an RDMA device. This call is typically made from the active side of a
+ * connection before calling rdma_resolve_route and rdma_connect.
+ * See also:
+ * rdma_create_id, rdma_resolve_route, rdma_connect, rdma_create_qp,
+ * rdma_get_cm_event, rdma_bind_addr
+ */
+__declspec(dllexport)
+int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
+ struct sockaddr *dst_addr, int timeout_ms);
+
+/**
+ * rdma_resolve_route - Resolve the route information needed to establish a connection.
+ * @id: RDMA identifier.
+ * @timeout_ms: Time to wait for resolution to complete.
+ * Description:
+ * Resolves an RDMA route to the destination address in order to establish
+ * a connection. The destination address must have already been resolved
+ * by calling rdma_resolve_addr.
+ * Notes:
+ * This is called on the client side of a connection after calling
+ * rdma_resolve_addr, but before calling rdma_connect.
+ * See also:
+ * rdma_resolve_addr, rdma_connect, rdma_get_cm_event
+ */
+__declspec(dllexport)
+int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms);
+
+/**
+ * rdma_create_qp - Allocate a QP.
+ * @id: RDMA identifier.
+ * @pd: protection domain for the QP.
+ * @qp_init_attr: initial QP attributes.
+ * Description:
+ * Allocate a QP associated with the specified rdma_cm_id and transition it
+ * for sending and receiving.
+ * Notes:
+ * The rdma_cm_id must be bound to a local RDMA device before calling this
+ * function, and the protection domain must be for that same device.
+ * QPs allocated to an rdma_cm_id are automatically transitioned by the
+ * librdmacm through their states. After being allocated, the QP will be
+ * ready to handle posting of receives. If the QP is unconnected, it will
+ * be ready to post sends.
+ * See also:
+ * rdma_bind_addr, rdma_resolve_addr, rdma_destroy_qp, ibv_create_qp,
+ * ibv_modify_qp
+ */
+__declspec(dllexport)
+int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd,
+ struct ibv_qp_init_attr *qp_init_attr);
+
+/**
+ * rdma_destroy_qp - Deallocate a QP.
+ * @id: RDMA identifier.
+ * Description:
+ * Destroy a QP allocated on the rdma_cm_id.
+ * Notes:
+ * Users must destroy any QP associated with an rdma_cm_id before
+ * destroying the ID.
+ * See also:
+ * rdma_create_qp, rdma_destroy_id, ibv_destroy_qp
+ */
+__declspec(dllexport)
+void rdma_destroy_qp(struct rdma_cm_id *id);
+
+/**
+ * rdma_connect - Initiate an active connection request.
+ * @id: RDMA identifier.
+ * @conn_param: connection parameters.
+ * Description:
+ * For a connected rdma_cm_id, this call initiates a connection request
+ * to a remote destination. For an unconnected rdma_cm_id, it initiates
+ * a lookup of the remote QP providing the datagram service.
+ * Notes:
+ * Users must have resolved a route to the destination address
+ * by having called rdma_resolve_route before calling this routine.
+ * See also:
+ * rdma_resolve_route, rdma_disconnect, rdma_listen, rdma_get_cm_event
+ */
+__declspec(dllexport)
+int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param);
+
+/**
+ * rdma_listen - Listen for incoming connection requests.
+ * @id: RDMA identifier.
+ * @backlog: backlog of incoming connection requests.
+ * Description:
+ * Initiates a listen for incoming connection requests or datagram service
+ * lookup. The listen will be restricted to the locally bound source
+ * address.
+ * Notes:
+ * Users must have bound the rdma_cm_id to a local address by calling
+ * rdma_bind_addr before calling this routine. If the rdma_cm_id is
+ * bound to a specific IP address, the listen will be restricted to that
+ * address and the associated RDMA device. If the rdma_cm_id is bound
+ * to an RDMA port number only, the listen will occur across all RDMA
+ * devices.
+ * See also:
+ * rdma_bind_addr, rdma_connect, rdma_accept, rdma_reject, rdma_get_cm_event
+ */
+__declspec(dllexport)
+int rdma_listen(struct rdma_cm_id *id, int backlog);
+
+/**
+ * rdma_accept - Called to accept a connection request.
+ * @id: Connection identifier associated with the request.
+ * @conn_param: Information needed to establish the connection.
+ * Description:
+ * Called from the listening side to accept a connection or datagram
+ * service lookup request.
+ * Notes:
+ * Unlike the socket accept routine, rdma_accept is not called on a
+ * listening rdma_cm_id. Instead, after calling rdma_listen, the user
+ * waits for a connection request event to occur. Connection request
+ * events give the user a newly created rdma_cm_id, similar to a new
+ * socket, but the rdma_cm_id is bound to a specific RDMA device.
+ * rdma_accept is called on the new rdma_cm_id.
+ * See also:
+ * rdma_listen, rdma_reject, rdma_get_cm_event
+ */
+__declspec(dllexport)
+int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param);
+
+/**
+ * rdma_reject - Called to reject a connection request.
+ * @id: Connection identifier associated with the request.
+ * @private_data: Optional private data to send with the reject message.
+ * @private_data_len: Size of the private_data to send, in bytes.
+ * Description:
+ * Called from the listening side to reject a connection or datagram
+ * service lookup request.
+ * Notes:
+ * After receiving a connection request event, a user may call rdma_reject
+ * to reject the request. If the underlying RDMA transport supports
+ * private data in the reject message, the specified data will be passed to
+ * the remote side.
+ * See also:
+ * rdma_listen, rdma_accept, rdma_get_cm_event
+ */
+__declspec(dllexport)
+int rdma_reject(struct rdma_cm_id *id, const void *private_data,
+ uint8_t private_data_len);
+
+/**
+ * rdma_notify - Notifies the librdmacm of an asynchronous event.
+ * @id: RDMA identifier.
+ * @event: Asynchronous event.
+ * Description:
+ * Used to notify the librdmacm of asynchronous events that have occurred
+ * on a QP associated with the rdma_cm_id.
+ * Notes:
+ * Asynchronous events that occur on a QP are reported through the user's
+ * device event handler. This routine is used to notify the librdmacm of
+ * communication events. In most cases, use of this routine is not
+ * necessary, however if connection establishment is done out of band
+ * (such as done through Infiniband), it's possible to receive data on a
+ * QP that is not yet considered connected. This routine forces the
+ * connection into an established state in this case in order to handle
+ * the rare situation where the connection never forms on its own.
+ * Events that should be reported to the CM are: IB_EVENT_COMM_EST.
+ * See also:
+ * rdma_connect, rdma_accept, rdma_listen
+ */
+__declspec(dllexport)
+int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event);
+
+/**
+ * rdma_disconnect - This function disconnects a connection.
+ * @id: RDMA identifier.
+ * Description:
+ * Disconnects a connection and transitions any associated QP to the
+ * error state.
+ * See also:
+ * rdma_connect, rdma_listen, rdma_accept
+ */
+__declspec(dllexport)
+int rdma_disconnect(struct rdma_cm_id *id);
+
+/**
+ * rdma_join_multicast - Joins a multicast group.
+ * @id: Communication identifier associated with the request.
+ * @addr: Multicast address identifying the group to join.
+ * @context: User-defined context associated with the join request.
+ * Description:
+ * Joins a multicast group and attaches an associated QP to the group.
+ * Notes:
+ * Before joining a multicast group, the rdma_cm_id must be bound to
+ * an RDMA device by calling rdma_bind_addr or rdma_resolve_addr. Use of
+ * rdma_resolve_addr requires the local routing tables to resolve the
+ * multicast address to an RDMA device. The user must call
+ * rdma_leave_multicast to leave the multicast group and release any
+ * multicast resources. The context is returned to the user through
+ * the private_data field in the rdma_cm_event.
+ * See also:
+ * rdma_leave_multicast, rdma_bind_addr, rdma_resolve_addr, rdma_create_qp
+ */
+__declspec(dllexport)
+int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
+ void *context);
+
+/**
+ * rdma_leave_multicast - Leaves a multicast group.
+ * @id: Communication identifier associated with the request.
+ * @addr: Multicast address identifying the group to leave.
+ * Description:
+ * Leaves a multicast group and detaches an associated QP from the group.
+ * Notes:
+ * Calling this function before a group has been fully joined results in
+ * canceling the join operation. Users should be aware that messages
+ * received from the multicast group may stilled be queued for
+ * completion processing immediately after leaving a multicast group.
+ * Destroying an rdma_cm_id will automatically leave all multicast groups.
+ * See also:
+ * rdma_join_multicast, rdma_destroy_qp
+ */
+__declspec(dllexport)
+int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr);
+
+/**
+ * rdma_get_cm_event - Retrieves the next pending communication event.
+ * @channel: Event channel to check for events.
+ * @event: Allocated information about the next communication event.
+ * Description:
+ * Retrieves a communication event. If no events are pending, by default,
+ * the call will block until an event is received.
+ * Notes:
+ * The default synchronous behavior of this routine can be changed by
+ * modifying the file descriptor associated with the given channel. All
+ * events that are reported must be acknowledged by calling rdma_ack_cm_event.
+ * Destruction of an rdma_cm_id will block until related events have been
+ * acknowledged.
+ * See also:
+ * rdma_ack_cm_event, rdma_create_event_channel, rdma_event_str
+ */
+__declspec(dllexport)
+int rdma_get_cm_event(struct rdma_event_channel *channel,
+ struct rdma_cm_event **event);
+
+/**
+ * rdma_ack_cm_event - Free a communication event.
+ * @event: Event to be released.
+ * Description:
+ * All events which are allocated by rdma_get_cm_event must be released,
+ * there should be a one-to-one correspondence between successful gets
+ * and acks.
+ * See also:
+ * rdma_get_cm_event, rdma_destroy_id
+ */
+__declspec(dllexport)
+int rdma_ack_cm_event(struct rdma_cm_event *event);
+
+static uint16_t rdma_get_src_port(struct rdma_cm_id *id)
+{
+ return id->route.addr.src_addr.sa_family == PF_INET6 ?
+ ((struct sockaddr_in6 *) &id->route.addr.src_addr)->sin6_port :
+ ((struct sockaddr_in *) &id->route.addr.src_addr)->sin_port;
+}
+
+static uint16_t rdma_get_dst_port(struct rdma_cm_id *id)
+{
+ return id->route.addr.dst_addr.sa_family == PF_INET6 ?
+ ((struct sockaddr_in6 *) &id->route.addr.dst_addr)->sin6_port :
+ ((struct sockaddr_in *) &id->route.addr.dst_addr)->sin_port;
+}
+
+static struct sockaddr *rdma_get_local_addr(struct rdma_cm_id *id)
+{
+ return &id->route.addr.src_addr;
+}
+
+static struct sockaddr *rdma_get_peer_addr(struct rdma_cm_id *id)
+{
+ return &id->route.addr.dst_addr;
+}
+
+/**
+ * rdma_get_devices - Get list of RDMA devices currently available.
+ * @num_devices: If non-NULL, set to the number of devices returned.
+ * Description:
+ * Return a NULL-terminated array of opened RDMA devices. Callers can use
+ * this routine to allocate resources on specific RDMA devices that will be
+ * shared across multiple rdma_cm_id's.
+ * Notes:
+ * The returned array must be released by calling rdma_free_devices. Devices
+ * remain opened while the librdmacm is loaded.
+ * See also:
+ * rdma_free_devices
+ */
+__declspec(dllexport)
+struct ibv_context **rdma_get_devices(int *num_devices);
+
+/**
+ * rdma_free_devices - Frees the list of devices returned by rdma_get_devices.
+ * @list: List of devices returned from rdma_get_devices.
+ * Description:
+ * Frees the device array returned by rdma_get_devices.
+ * See also:
+ * rdma_get_devices
+ */
+__declspec(dllexport)
+void rdma_free_devices(struct ibv_context **list);
+
+/**
+ * rdma_event_str - Returns a string representation of an rdma cm event.
+ * @event: Asynchronous event.
+ * Description:
+ * Returns a string representation of an asynchronous event.
+ * See also:
+ * rdma_get_cm_event
+ */
+__declspec(dllexport)
+const char *rdma_event_str(enum rdma_cm_event_type event);
+
+/* Option levels */
+enum
+{
+ RDMA_OPTION_ID = 0
+};
+
+/* Option details */
+enum
+{
+ RDMA_OPTION_ID_TOS = 0 /* uint8_t: RFC 2474 */
+};
+
+/**
+ * rdma_set_option - Set options for an rdma_cm_id.
+ * @id: Communication identifier to set option for.
+ * @level: Protocol level of the option to set.
+ * @optname: Name of the option to set.
+ * @optval: Reference to the option data.
+ * @optlen: The size of the %optval buffer.
+ */
+__declspec(dllexport)
+int rdma_set_option(struct rdma_cm_id *id, int level, int optname,
+ void *optval, size_t optlen);
+
+/**
+ * rdma_migrate_id - Move an rdma_cm_id to a new event channel.
+ * @id: Communication identifier to migrate.
+ * @channel: New event channel for rdma_cm_id events.
+ */
+__declspec(dllexport)
+int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RDMA_CMA_H */
diff -up -N trunk\ulp\librdmacm\src/cma.cpp branches\winverbs\ulp\librdmacm\src/cma.cpp
--- trunk\ulp\librdmacm\src/cma.cpp 1969-12-31 16:00:00.000000000 -0800
+++ branches\winverbs\ulp\librdmacm\src/cma.cpp 2009-01-16 12:34:02.139005300 -0800
@@ -0,0 +1,1084 @@
+/*
+ * Copyright (c) 2005-2009 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under 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 AWV
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <windows.h>
+#include <winsock2.h>
+#include <stdio.h>
+#include <iphlpapi.h>
+
+#include <rdma/rdma_cma.h>
+#include <infiniband/verbs.h>
+#include <iba/ibat.h>
+#include "cma.h"
+
+IWVProvider *prov;
+__declspec(dllexport)
+IWVProvider *ibv_get_winverbs(void);
+
+enum cma_state
+{
+ cma_idle,
+ cma_listening,
+ cma_get_request,
+ cma_addr_resolve,
+ cma_route_resolve,
+ cma_passive_connect,
+ cma_active_connect,
+ cma_active_accept,
+ cma_accepting,
+ cma_connected,
+ cma_active_disconnect,
+ cma_passive_disconnect,
+ cma_disconnected
+};
+
+#define CMA_DEFAULT_BACKLOG 16
+
+struct cma_id_private
+{
+ struct rdma_cm_id id;
+ enum cma_state state;
+ int channel_index;
+ struct cma_device *cma_dev;
+ int backlog;
+ int index;
+ struct rdma_cm_id **req_list;
+};
+
+struct cma_event_channel
+{
+ struct rdma_event_channel channel;
+ CRITICAL_SECTION lock;
+ struct cma_id_private *id[MAXIMUM_WAIT_OBJECTS];
+ HANDLE event[MAXIMUM_WAIT_OBJECTS];
+ int count;
+};
+
+struct cma_device
+{
+ struct ibv_context *verbs;
+ uint64_t guid;
+ int port_cnt;
+ uint8_t max_initiator_depth;
+ uint8_t max_responder_resources;
+};
+
+struct cma_event {
+ struct rdma_cm_event event;
+ uint8_t private_data[56];
+ struct cma_id_private *id_priv;
+};
+
+static struct cma_device *cma_dev_array;
+static int cma_dev_cnt;
+
+static void ucma_cleanup(void)
+{
+ if (cma_dev_cnt > 0) {
+ while (cma_dev_cnt > 0) {
+ ibv_close_device(cma_dev_array[--cma_dev_cnt].verbs);
+ }
+ delete cma_dev_array;
+ cma_dev_cnt = 0;
+ }
+ if (prov != NULL) {
+ prov->Release();
+ prov = NULL;
+ }
+}
+
+static int ucma_init(void)
+{
+ struct ibv_device **dev_list = NULL;
+ struct cma_device *cma_dev;
+ struct ibv_device_attr attr;
+ int i, ret;
+
+ EnterCriticalSection(&lock);
+ if (cma_dev_cnt > 0) {
+ goto out;
+ }
+
+ prov = ibv_get_winverbs();
+ if (prov == NULL) {
+ ret = -1;
+ goto err;
+ }
+
+ dev_list = ibv_get_device_list(&cma_dev_cnt);
+ if (dev_list == NULL) {
+ ret = -1;
+ goto err;
+ }
+
+ cma_dev_array = new struct cma_device[cma_dev_cnt];
+ if (cma_dev_array == NULL) {
+ ret = -1;
+ goto err;
+ }
+
+ for (i = 0; dev_list[i]; ++i) {
+ cma_dev = &cma_dev_array[i];
+
+ cma_dev->guid = ibv_get_device_guid(dev_list[i]);
+ cma_dev->verbs = ibv_open_device(dev_list[i]);
+ if (cma_dev->verbs == NULL) {
+ ret = -1;
+ goto err;
+ }
+
+ ret = ibv_query_device(cma_dev->verbs, &attr);
+ if (ret) {
+ goto err;
+ }
+
+ cma_dev->port_cnt = attr.phys_port_cnt;
+ cma_dev->max_initiator_depth = (uint8_t) attr.max_qp_init_rd_atom;
+ cma_dev->max_responder_resources = (uint8_t) attr.max_qp_rd_atom;
+ }
+ ibv_free_device_list(dev_list);
+out:
+ LeaveCriticalSection(&lock);
+ return 0;
+
+err:
+ ucma_cleanup();
+ LeaveCriticalSection(&lock);
+ if (dev_list) {
+ ibv_free_device_list(dev_list);
+ }
+ return ret;
+}
+
+__declspec(dllexport)
+struct ibv_context **rdma_get_devices(int *num_devices)
+{
+ struct ibv_context **devs = NULL;
+ int i;
+
+ if (!cma_dev_cnt && ucma_init()) {
+ goto out;
+ }
+
+ devs = new struct ibv_context *[cma_dev_cnt + 1];
+ if (devs == NULL) {
+ goto out;
+ }
+
+ for (i = 0; i < cma_dev_cnt; i++) {
+ devs[i] = cma_dev_array[i].verbs;
+ }
+ devs[i] = NULL;
+out:
+ if (num_devices != NULL) {
+ *num_devices = devs ? cma_dev_cnt : 0;
+ }
+ return devs;
+}
+
+__declspec(dllexport)
+void rdma_free_devices(struct ibv_context **list)
+{
+ delete list;
+}
+
+__declspec(dllexport)
+struct rdma_event_channel *rdma_create_event_channel(void)
+{
+ struct cma_event_channel *chan;
+
+ if (!cma_dev_cnt && ucma_init()) {
+ return NULL;
+ }
+
+ chan = new struct cma_event_channel;
+ if (chan == NULL) {
+ return NULL;
+ }
+
+ InitializeCriticalSection(&chan->lock);
+ chan->count = 0;
+ chan->channel.timeout = INFINITE;
+
+ return &chan->channel;
+}
+
+__declspec(dllexport)
+void rdma_destroy_event_channel(struct rdma_event_channel *channel)
+{
+ struct cma_event_channel *chan;
+
+ chan = CONTAINING_RECORD(channel, struct cma_event_channel, channel);
+ DeleteCriticalSection(&chan->lock);
+ delete chan;
+}
+
+static int cma_event_channel_insert_id(struct rdma_event_channel *channel,
+ struct cma_id_private *id_priv)
+{
+ struct cma_event_channel *chan;
+ int ret = 0;
+
+ chan = CONTAINING_RECORD(channel, struct cma_event_channel, channel);
+
+ EnterCriticalSection(&chan->lock);
+ if (chan->count == MAXIMUM_WAIT_OBJECTS) {
+ ret = -1;
+ goto out;
+ }
+
+ chan->id[chan->count] = id_priv;
+ chan->event[chan->count] = id_priv->id.overlap.hEvent;
+ id_priv->channel_index = chan->count++;
+out:
+ LeaveCriticalSection(&chan->lock);
+ return ret;
+}
+
+/*
+ * TODO: we cannot call cma_event_channel_remove_id() while another
+ * thread is calling rdma_get_event(). If this is needed, then we
+ * need to halt the rdma_get_event() thread, modify the event list,
+ * then restart the rdma_get_event() thread.
+ */
+static void cma_event_channel_remove_id(struct rdma_event_channel *channel,
+ struct cma_id_private *id_priv)
+{
+ struct cma_event_channel *chan;
+
+ chan = CONTAINING_RECORD(channel, struct cma_event_channel, channel);
+
+ EnterCriticalSection(&chan->lock);
+ chan->count--;
+ chan->id[id_priv->channel_index] = chan->id[chan->count];
+ chan->event[id_priv->channel_index] = chan->event[chan->count];
+ chan->id[id_priv->channel_index]->channel_index = id_priv->channel_index;
+ LeaveCriticalSection(&chan->lock);
+}
+
+__declspec(dllexport)
+int rdma_create_id(struct rdma_event_channel *channel,
+ struct rdma_cm_id **id, void *context,
+ enum rdma_port_space ps)
+{
+ struct cma_id_private *id_priv;
+ HRESULT hr;
+
+ hr = cma_dev_cnt ? 0 : ucma_init();
+ if (hr) {
+ return hr;
+ }
+
+ id_priv = new struct cma_id_private;
+ if (id_priv == NULL) {
+ return NULL;
+ }
+
+ RtlZeroMemory(id_priv, sizeof(struct cma_id_private));
+ id_priv->id.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (id_priv->id.overlap.hEvent == NULL) {
+ goto err1;
+ }
+
+ id_priv->id.context = context;
+ id_priv->id.channel = channel;
+ id_priv->id.ps = ps;
+
+ if (ps == RDMA_PS_TCP) {
+ hr = prov->CreateConnectEndpoint(&id_priv->id.ep.connect);
+ } else {
+ hr = prov->CreateDatagramEndpoint(&id_priv->id.ep.datagram);
+ }
+ if (FAILED(hr)) {
+ goto err2;
+ }
+
+ hr = cma_event_channel_insert_id(channel, id_priv);
+ if (FAILED(hr)) {
+ goto err3;
+ }
+
+ *id = &id_priv->id;
+ return 0;
+
+err3:
+ if (ps == RDMA_PS_TCP) {
+ id_priv->id.ep.connect->Release();
+ } else {
+ id_priv->id.ep.datagram->Release();
+ }
+err2:
+ CloseHandle(id_priv->id.overlap.hEvent);
+err1:
+ delete id_priv;
+ return -1;
+}
+
+static void ucma_destroy_listen(struct cma_id_private *id_priv)
+{
+ while (--id_priv->backlog >= 0) {
+ if (id_priv->req_list[id_priv->backlog] != NULL) {
+ rdma_destroy_id(id_priv->req_list[id_priv->backlog]);
+ }
+ }
+
+ delete id_priv->req_list;
+}
+
+__declspec(dllexport)
+int rdma_destroy_id(struct rdma_cm_id *id)
+{
+ struct cma_id_private *id_priv;
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ if (id->ps == RDMA_PS_TCP) {
+ id->ep.connect->CancelOverlappedRequests();
+ } else {
+ id->ep.datagram->CancelOverlappedRequests();
+ }
+
+ cma_event_channel_remove_id(id->channel, id_priv);
+
+ if (id_priv->backlog > 0) {
+ ucma_destroy_listen(id_priv);
+ }
+
+ if (id_priv->id.ps == RDMA_PS_TCP) {
+ id_priv->id.ep.connect->Release();
+ } else {
+ id_priv->id.ep.datagram->Release();
+ }
+
+ delete id_priv;
+ return 0;
+}
+
+static int ucma_addrlen(struct sockaddr *addr)
+{
+ if (addr->sa_family == PF_INET) {
+ return sizeof(struct sockaddr_in);
+ } else {
+ return sizeof(struct sockaddr_in6);
+ }
+}
+
+static int ucma_get_device(struct cma_id_private *id_priv, uint64_t guid)
+{
+ struct cma_device *cma_dev;
+ int i;
+
+ for (i = 0; i < cma_dev_cnt; i++) {
+ cma_dev = &cma_dev_array[i];
+ if (cma_dev->guid == guid) {
+ id_priv->cma_dev = cma_dev;
+ id_priv->id.verbs = cma_dev->verbs;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int ucma_query_connect(struct rdma_cm_id *id, struct rdma_conn_param *param)
+{
+ struct cma_id_private *id_priv;
+ WV_CONNECT_ATTRIBUTES attr;
+ HRESULT hr;
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ hr = id->ep.connect->Query(&attr);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ RtlCopyMemory(&id->route.addr.src_addr, &attr.LocalAddress,
+ sizeof attr.LocalAddress);
+ RtlCopyMemory(&id->route.addr.dst_addr, &attr.PeerAddress,
+ sizeof attr.PeerAddress);
+
+ if (param != NULL) {
+ RtlCopyMemory((void *) param->private_data, attr.Param.Data,
+ attr.Param.DataLength);
+ param->private_data_len = (uint8_t) attr.Param.DataLength;
+ param->responder_resources = (uint8_t) attr.Param.ResponderResources;
+ param->initiator_depth = (uint8_t) attr.Param.InitiatorDepth;
+ param->flow_control = 1;
+ param->retry_count = attr.Param.RetryCount;
+ param->rnr_retry_count = attr.Param.RnrRetryCount;
+ }
+
+ if (id_priv->cma_dev == NULL && attr.Device.DeviceGuid != 0) {
+ hr = ucma_get_device(id_priv, attr.Device.DeviceGuid);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ id->route.addr.addr.ibaddr.pkey = attr.Device.Pkey;
+ id_priv->id.port_num = attr.Device.PortNumber;
+ }
+
+ return 0;
+}
+
+static int ucma_query_datagram(struct rdma_cm_id *id, struct rdma_ud_param *param)
+{
+ struct cma_id_private *id_priv;
+ WV_DATAGRAM_ATTRIBUTES attr;
+ HRESULT hr;
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ hr = id->ep.datagram->Query(&attr);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ RtlCopyMemory(&id->route.addr.src_addr, &attr.LocalAddress,
+ sizeof attr.LocalAddress);
+ RtlCopyMemory(&id->route.addr.dst_addr, &attr.PeerAddress,
+ sizeof attr.PeerAddress);
+
+ if (param != NULL) {
+ RtlCopyMemory((void *) param->private_data, attr.Param.Data,
+ attr.Param.DataLength);
+ param->private_data_len = (uint8_t) attr.Param.DataLength;
+ // ucma_convert_av(&attr.Param.AddressVector, param->ah_attr)
+ param->qp_num = attr.Param.Qpn;
+ param->qkey = attr.Param.Qkey;
+ }
+
+ if (id_priv->cma_dev == NULL && attr.Device.DeviceGuid != 0) {
+ hr = ucma_get_device(id_priv, attr.Device.DeviceGuid);
+ if (FAILED(hr))
+ return hr;
+ id->route.addr.addr.ibaddr.pkey = attr.Device.Pkey;
+ id_priv->id.port_num = attr.Device.PortNumber;
+ }
+ return 0;
+}
+
+__declspec(dllexport)
+int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
+{
+ HRESULT hr;
+
+ if (id->ps == RDMA_PS_TCP) {
+ hr = id->ep.connect->BindAddress(addr);
+ if (SUCCEEDED(hr)) {
+ hr = ucma_query_connect(id, NULL);
+ }
+ } else {
+ hr = id->ep.datagram->BindAddress(addr);
+ if (SUCCEEDED(hr)) {
+ hr = ucma_query_datagram(id, NULL);
+ }
+ }
+
+ return hr;
+}
+
+__declspec(dllexport)
+int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
+ struct sockaddr *dst_addr, int timeout_ms)
+{
+ struct cma_id_private *id_priv;
+ WV_SOCKADDR addr;
+ SOCKET s;
+ DWORD size;
+ HRESULT hr;
+
+ if (src_addr == NULL) {
+ if (id->ps == RDMA_PS_TCP) {
+ s = socket(dst_addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
+ } else {
+ s = socket(dst_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+ }
+ if (s == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ hr = WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY, dst_addr, ucma_addrlen(dst_addr),
+ &addr, sizeof addr, &size, NULL, NULL);
+ closesocket(s);
+ if (FAILED(hr)) {
+ return WSAGetLastError();
+ }
+ src_addr = &addr.Sa;
+ }
+
+ hr = rdma_bind_addr(id, src_addr);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ RtlCopyMemory(&id->route.addr.dst_addr, dst_addr, ucma_addrlen(dst_addr));
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ id_priv->state = cma_addr_resolve;
+ SetEvent(id->overlap.hEvent);
+ return 0;
+}
+
+__declspec(dllexport)
+int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
+{
+ struct cma_id_private *id_priv;
+ IBAT_PATH_BLOB path;
+ HRESULT hr;
+
+ hr = IBAT::Resolve(&id->route.addr.src_addr, &id->route.addr.dst_addr, &path);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ hr = (id->ps == RDMA_PS_TCP) ?
+ id->ep.connect->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path) :
+ id->ep.datagram->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ id_priv->state = cma_route_resolve;
+ SetEvent(id->overlap.hEvent);
+ return 0;
+}
+
+static int ucma_modify_qp_init(struct cma_id_private *id_priv, struct ibv_qp *qp)
+{
+ struct ibv_qp_attr qp_attr;
+ DWORD index;
+ HRESULT hr;
+
+ RtlZeroMemory(&qp_attr, sizeof qp_attr);
+ qp_attr.qp_state = IBV_QPS_INIT;
+ qp_attr.port_num = id_priv->id.port_num;
+ hr = qp->context->cmd_if->FindPkey(id_priv->id.port_num,
+ id_priv->id.route.addr.addr.ibaddr.pkey,
+ &index);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ qp_attr.pkey_index = (uint16_t) index;
+ return ibv_modify_qp(qp, &qp_attr, (enum ibv_qp_attr_mask)
+ (IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT));
+}
+
+static int ucma_init_ud_qp(struct cma_id_private *id_priv, struct ibv_qp *qp)
+{
+ struct ibv_qp_attr qp_attr;
+ int qp_attr_mask, ret;
+
+ ret = ucma_modify_qp_init(id_priv, qp);
+ if (ret) {
+ return ret;
+ }
+
+ qp_attr.qp_state = IBV_QPS_RTR;
+ ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE);
+ if (ret) {
+ return ret;
+ }
+
+ qp_attr.qp_state = IBV_QPS_RTS;
+ qp_attr.sq_psn = 0;
+ return ibv_modify_qp(qp, &qp_attr, (enum ibv_qp_attr_mask)
+ (IBV_QP_STATE | IBV_QP_SQ_PSN));
+}
+
+__declspec(dllexport)
+int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd,
+ struct ibv_qp_init_attr *qp_init_attr)
+{
+ struct cma_id_private *id_priv;
+ struct ibv_qp *qp;
+ int ret;
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ if (id->verbs != pd->context) {
+ return -1;
+ }
+
+ qp = ibv_create_qp(pd, qp_init_attr);
+ if (!qp) {
+ return -1;
+ }
+
+ if (id->ps == RDMA_PS_TCP) {
+ ret = ucma_modify_qp_init(id_priv, qp);
+ } else {
+ ret = ucma_init_ud_qp(id_priv, qp);
+ }
+ if (ret) {
+ goto err;
+ }
+
+ id->qp = qp;
+ return 0;
+err:
+ ibv_destroy_qp(qp);
+ return ret;
+}
+
+__declspec(dllexport)
+void rdma_destroy_qp(struct rdma_cm_id *id)
+{
+ ibv_destroy_qp(id->qp);
+}
+
+static int ucma_valid_param(struct cma_id_private *id_priv,
+ struct rdma_conn_param *conn_param)
+{
+ if (id_priv->id.ps != RDMA_PS_TCP) {
+ return 0;
+ }
+
+ if ((conn_param->responder_resources > id_priv->cma_dev->max_responder_resources) ||
+ (conn_param->initiator_depth > id_priv->cma_dev->max_initiator_depth)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+__declspec(dllexport)
+int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
+{
+ struct cma_id_private *id_priv;
+ WV_CONNECT_PARAM attr;
+ HRESULT hr;
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ hr = ucma_valid_param(id_priv, conn_param);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ RtlZeroMemory(&attr, sizeof attr);
+ attr.ResponderResources = conn_param->responder_resources;
+ attr.InitiatorDepth = conn_param->initiator_depth;
+ attr.RetryCount = conn_param->retry_count;
+ attr.RnrRetryCount = conn_param->rnr_retry_count;
+ if ((attr.DataLength = conn_param->private_data_len)) {
+ RtlCopyMemory(attr.Data, conn_param->private_data, attr.DataLength);
+ }
+
+ id_priv->state = cma_active_connect;
+ hr = id->ep.connect->Connect(id->qp->conn_handle, &id->route.addr.dst_addr,
+ &attr, &id->overlap);
+ if (FAILED(hr) && hr != WV_IO_PENDING) {
+ id_priv->state = cma_route_resolve;
+ return hr;
+ }
+
+ return 0;
+}
+
+static int ucma_get_request(struct cma_id_private *listen, int index)
+{
+ struct cma_id_private *id_priv;
+ HRESULT hr;
+
+ hr = rdma_create_id(listen->id.channel, &listen->req_list[index],
+ listen, listen->id.ps);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ id_priv = CONTAINING_RECORD(listen->req_list[index], struct cma_id_private, id);
+ id_priv->index = index;
+ id_priv->state = cma_get_request;
+
+ if (listen->id.ps == RDMA_PS_TCP) {
+ hr = listen->id.ep.connect->GetRequest(id_priv->id.ep.connect,
+ &id_priv->id.overlap);
+ } else {
+ hr = listen->id.ep.datagram->GetRequest(id_priv->id.ep.datagram,
+ &id_priv->id.overlap);
+ }
+
+ return (FAILED(hr) && hr != WV_IO_PENDING) ? hr : 0;
+}
+
+__declspec(dllexport)
+int rdma_listen(struct rdma_cm_id *id, int backlog)
+{
+ struct cma_id_private *id_priv, *req_id;
+ HRESULT hr;
+ int i;
+
+ if (backlog <= 0 || backlog > CMA_DEFAULT_BACKLOG) {
+ backlog = CMA_DEFAULT_BACKLOG;
+ }
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ id_priv->req_list = new struct rdma_cm_id*[backlog];
+ if (id_priv->req_list == NULL) {
+ return -1;
+ }
+
+ RtlZeroMemory(id_priv->req_list, sizeof(struct rdma_cm_id *) * backlog);
+ id_priv->backlog = backlog;
+
+ id_priv->state = cma_listening;
+ hr = (id->ps == RDMA_PS_TCP) ?
+ id->ep.connect->Listen(backlog) : id->ep.datagram->Listen(backlog);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ for (i = 0; i < backlog; i++) {
+ hr = ucma_get_request(id_priv, i);
+ if (FAILED(hr)) {
+ return hr;
+ }
+ }
+
+ return 0;
+}
+
+__declspec(dllexport)
+int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
+{
+ struct cma_id_private *id_priv;
+ WV_CONNECT_PARAM attr;
+ HRESULT hr;
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ hr = ucma_valid_param(id_priv, conn_param);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ RtlZeroMemory(&attr, sizeof attr);
+ attr.ResponderResources = conn_param->responder_resources;
+ attr.InitiatorDepth = conn_param->initiator_depth;
+ attr.RetryCount = conn_param->retry_count;
+ attr.RnrRetryCount = conn_param->rnr_retry_count;
+ if ((attr.DataLength = conn_param->private_data_len)) {
+ RtlCopyMemory(attr.Data, conn_param->private_data, attr.DataLength);
+ }
+
+ id_priv->state = cma_accepting;
+ hr = id->ep.connect->Accept(id->qp->conn_handle, &attr, &id->overlap);
+ if (FAILED(hr) && hr != WV_IO_PENDING) {
+ id_priv->state = cma_disconnected;
+ return hr;
+ }
+
+ return 0;
+}
+
+__declspec(dllexport)
+int rdma_reject(struct rdma_cm_id *id, const void *private_data,
+ uint8_t private_data_len)
+{
+ struct cma_id_private *id_priv;
+ HRESULT hr;
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ id_priv->state = cma_disconnected;
+ hr = id->ep.connect->Reject(private_data, private_data_len);
+ if (FAILED(hr)) {
+ return hr;
+ }
+ return 0;
+}
+
+__declspec(dllexport)
+int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event)
+{
+ return 0;
+}
+
+__declspec(dllexport)
+int rdma_disconnect(struct rdma_cm_id *id)
+{
+ struct cma_id_private *id_priv;
+ HRESULT hr;
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ if (id_priv->state == cma_connected) {
+ id_priv->state = cma_active_disconnect;
+ } else {
+ id_priv->state = cma_disconnected;
+ }
+ hr = id->ep.connect->Disconnect();
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ return 0;
+}
+
+__declspec(dllexport)
+int rdma_ack_cm_event(struct rdma_cm_event *event)
+{
+ struct cma_event *evt;
+
+ evt = CONTAINING_RECORD(event, struct cma_event, event);
+ delete evt;
+ return 0;
+}
+
+static int ucma_process_conn_req(struct cma_event *event)
+{
+ struct cma_id_private *listen;
+ HRESULT hr = 0;
+
+ listen = (struct cma_id_private *) event->id_priv->id.context;
+
+ if (SUCCEEDED(event->event.status)) {
+ event->event.status = ucma_query_connect(&event->id_priv->id,
+ &event->event.param.conn);
+ }
+
+ if (SUCCEEDED(event->event.status)) {
+ event->event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
+ event->id_priv->state = cma_passive_connect;
+
+ listen->req_list[event->id_priv->index] = NULL;
+ ucma_get_request(listen, event->id_priv->index);
+ } else {
+ hr = listen->id.ep.connect->GetRequest(event->id_priv->id.ep.connect,
+ &event->id_priv->id.overlap);
+ if (hr == WV_IO_PENDING) {
+ hr = 0;
+ }
+ }
+
+ return hr;
+}
+
+static int ucma_process_conn_resp(struct cma_event *event)
+{
+ struct rdma_cm_id *id;
+ WV_CONNECT_PARAM attr;
+ HRESULT hr;
+
+ if (FAILED(event->event.status)) {
+ goto err;
+ }
+
+ RtlZeroMemory(&attr, sizeof(attr));
+ event->id_priv->state = cma_accepting;
+
+ id = &event->id_priv->id;
+ hr = id->ep.connect->Accept(id->qp->conn_handle, &attr, &id->overlap);
+ if (FAILED(hr) && hr != WV_IO_PENDING) {
+ event->event.status = hr;
+ goto err;
+ }
+
+ return WV_IO_PENDING;
+
+err:
+ event->event.event = (event->event.status == WV_REJECTED) ?
+ RDMA_CM_EVENT_REJECTED :
+ RDMA_CM_EVENT_CONNECT_ERROR;
+ event->id_priv->state = cma_disconnected;
+ return 0;
+}
+
+static void ucma_process_establish(struct cma_event *event)
+{
+ if (SUCCEEDED(event->event.status)) {
+ event->event.status = ucma_query_connect(&event->id_priv->id,
+ &event->event.param.conn);
+ }
+
+ if (SUCCEEDED(event->event.status)) {
+ event->event.event = RDMA_CM_EVENT_ESTABLISHED;
+ event->id_priv->state = cma_connected;
+
+ event->id_priv->id.ep.connect->NotifyDisconnect(&event->id_priv->id.overlap);
+ } else {
+ event->event.event = RDMA_CM_EVENT_CONNECT_ERROR;
+ event->id_priv->state = cma_disconnected;
+ }
+}
+
+static int ucma_process_event(struct cma_event *event)
+{
+ WV_CONNECT_ATTRIBUTES attr;
+ HRESULT hr = 0;
+
+ switch (event->id_priv->state) {
+ case cma_get_request:
+ hr = ucma_process_conn_req(event);
+ break;
+ case cma_addr_resolve:
+ event->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
+ break;
+ case cma_route_resolve:
+ event->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
+ break;
+ case cma_active_connect:
+ hr = ucma_process_conn_resp(event);
+ break;
+ case cma_accepting:
+ ucma_process_establish(event);
+ break;
+ case cma_connected:
+ event->event.event = RDMA_CM_EVENT_DISCONNECTED;
+ event->id_priv->state = cma_passive_disconnect;
+ break;
+ case cma_active_disconnect:
+ event->event.event = RDMA_CM_EVENT_DISCONNECTED;
+ event->id_priv->state = cma_disconnected;
+ break;
+ default:
+ return -1;
+ }
+
+ return hr;
+}
+
+__declspec(dllexport)
+int rdma_get_cm_event(struct rdma_event_channel *channel,
+ struct rdma_cm_event **event)
+{
+ struct cma_event_channel *chan;
+ struct cma_event *evt;
+ struct cma_id_private *id_priv;
+ struct rdma_cm_id *id;
+ DWORD bytes;
+ HRESULT hr;
+
+ evt = new struct cma_event;
+ if (evt == NULL) {
+ return -1;
+ }
+
+ do {
+ RtlZeroMemory(evt, sizeof(struct cma_event));
+
+ chan = CONTAINING_RECORD(channel, struct cma_event_channel, channel);
+ hr = WaitForMultipleObjects(chan->count, chan->event, FALSE,
+ chan->channel.timeout);
+ if (hr == WAIT_TIMEOUT) {
+ return hr;
+ } else if (hr == WAIT_FAILED) {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ EnterCriticalSection(&chan->lock);
+ evt->id_priv = chan->id[hr];
+ LeaveCriticalSection(&chan->lock);
+
+ id = &evt->id_priv->id;
+ evt->event.id = id;
+ evt->event.param.conn.private_data = evt->private_data;
+ if (id->ep.connect->GetOverlappedResult(&id->overlap, &bytes, FALSE) == 0) {
+ evt->event.status = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ hr = ucma_process_event(evt);
+ } while (FAILED(hr));
+
+ *event = &evt->event;
+ return 0;
+}
+
+
+__declspec(dllexport)
+int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
+ void *context)
+{
+ return WV_NOT_SUPPORTED;
+}
+
+__declspec(dllexport)
+int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
+{
+ return WV_NOT_SUPPORTED;
+}
+
+__declspec(dllexport)
+const char *rdma_event_str(enum rdma_cm_event_type event)
+{
+ switch (event) {
+ case RDMA_CM_EVENT_ADDR_RESOLVED:
+ return "RDMA_CM_EVENT_ADDR_RESOLVED";
+ case RDMA_CM_EVENT_ADDR_ERROR:
+ return "RDMA_CM_EVENT_ADDR_ERROR";
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:
+ return "RDMA_CM_EVENT_ROUTE_RESOLVED";
+ case RDMA_CM_EVENT_ROUTE_ERROR:
+ return "RDMA_CM_EVENT_ROUTE_ERROR";
+ case RDMA_CM_EVENT_CONNECT_REQUEST:
+ return "RDMA_CM_EVENT_CONNECT_REQUEST";
+ case RDMA_CM_EVENT_CONNECT_RESPONSE:
+ return "RDMA_CM_EVENT_CONNECT_RESPONSE";
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ return "RDMA_CM_EVENT_CONNECT_ERROR";
+ case RDMA_CM_EVENT_UNREACHABLE:
+ return "RDMA_CM_EVENT_UNREACHABLE";
+ case RDMA_CM_EVENT_REJECTED:
+ return "RDMA_CM_EVENT_REJECTED";
+ case RDMA_CM_EVENT_ESTABLISHED:
+ return "RDMA_CM_EVENT_ESTABLISHED";
+ case RDMA_CM_EVENT_DISCONNECTED:
+ return "RDMA_CM_EVENT_DISCONNECTED";
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ return "RDMA_CM_EVENT_DEVICE_REMOVAL";
+ case RDMA_CM_EVENT_MULTICAST_JOIN:
+ return "RDMA_CM_EVENT_MULTICAST_JOIN";
+ case RDMA_CM_EVENT_MULTICAST_ERROR:
+ return "RDMA_CM_EVENT_MULTICAST_ERROR";
+ case RDMA_CM_EVENT_ADDR_CHANGE:
+ return "RDMA_CM_EVENT_ADDR_CHANGE";
+ case RDMA_CM_EVENT_TIMEWAIT_EXIT:
+ return "RDMA_CM_EVENT_TIMEWAIT_EXIT";
+ default:
+ return "UNKNOWN EVENT";
+ }
+}
+
+__declspec(dllexport)
+int rdma_set_option(struct rdma_cm_id *id, int level, int optname,
+ void *optval, size_t optlen)
+{
+ return WV_NOT_SUPPORTED;
+}
+
+__declspec(dllexport)
+int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel)
+{
+ struct cma_id_private *id_priv;
+
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);
+ cma_event_channel_remove_id(id->channel, id_priv);
+ /*
+ * TODO: To support calling this routine while processing events on the old
+ * channel, we need to wait for all old events to be acknowledged.
+ */
+ id->channel = channel;
+ cma_event_channel_insert_id(channel, id_priv);
+
+ return 0;
+}
diff -up -N trunk\ulp\librdmacm\src/cma.h branches\winverbs\ulp\librdmacm\src/cma.h
--- trunk\ulp\librdmacm\src/cma.h 1969-12-31 16:00:00.000000000 -0800
+++ branches\winverbs\ulp\librdmacm\src/cma.h 2009-01-12 14:41:27.698629200 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2008-2009 Intel Corp. All rights reserved.
+ *
+ * This software is available to you under 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 AWV
+ * 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 CMA_H
+#define CMA_H
+
+extern CRITICAL_SECTION lock;
+
+__inline void* __cdecl operator new(size_t size)
+{
+ return HeapAlloc(GetProcessHeap(), 0, size);
+}
+
+__inline void __cdecl operator delete(void *pObj)
+{
+ HeapFree(GetProcessHeap(), 0, pObj);
+}
+
+#endif /* CMA_H */
diff -up -N trunk\ulp\librdmacm\src/cma.rc branches\winverbs\ulp\librdmacm\src/cma.rc
--- trunk\ulp\librdmacm\src/cma.rc 1969-12-31 16:00:00.000000000 -0800
+++ branches\winverbs\ulp\librdmacm\src/cma.rc 2008-11-25 14:34:22.956029500 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include <oib_ver.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+
+#ifdef _DEBUG_
+#define VER_FILEDESCRIPTION_STR "LibRdmaCm (Debug)"
+#define VER_INTERNALNAME_STR "librdmacmd.dll"
+#define VER_ORIGINALFILENAME_STR "librdmacmd.dll"
+#else
+#define VER_FILEDESCRIPTION_STR "LibRdmaCm"
+#define VER_INTERNALNAME_STR "librdmacm.dll"
+#define VER_ORIGINALFILENAME_STR "librdmacm.dll"
+#endif
+
+#include <common.ver>
diff -up -N trunk\ulp\librdmacm\src/cma_export.def branches\winverbs\ulp\librdmacm\src/cma_export.def
--- trunk\ulp\librdmacm\src/cma_export.def 1969-12-31 16:00:00.000000000 -0800
+++ branches\winverbs\ulp\librdmacm\src/cma_export.def 2008-11-25 14:38:13.423014100 -0800
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under 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 AWV
+ * 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.
+ */
+
+LIBRARY LIBRDMACM.DLL
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
diff -up -N trunk\ulp\librdmacm\src/cma_exports.src branches\winverbs\ulp\librdmacm\src/cma_exports.src
--- trunk\ulp\librdmacm\src/cma_exports.src 1969-12-31 16:00:00.000000000 -0800
+++ branches\winverbs\ulp\librdmacm\src/cma_exports.src 2008-11-25 14:43:03.289402300 -0800
@@ -0,0 +1,33 @@
+#if DBG
+LIBRARY librdmacmd.dll
+#else
+LIBRARY librdmacm.dll
+#endif
+
+#ifndef _WIN64
+EXPORTS
+rdma_create_event_channel
+rdma_destroy_event_channel
+rdma_create_id
+rdma_destroy_id
+rdma_bind_addr
+rdma_resolve_addr
+rdma_resolve_route
+rdma_create_qp
+rdma_destroy_qp
+rdma_connect
+rdma_listen
+rdma_accept
+rdma_reject
+rdma_notify
+rdma_disconnect
+rdma_join_multicast
+rdma_leave_multicast
+rdma_get_cm_event
+rdma_ack_cm_event
+rdma_get_devices
+rdma_free_devices
+rdma_event_str
+rdma_set_option
+rdma_migrate_id
+#endif
diff -up -N trunk\ulp\librdmacm\src/cma_main.cpp branches\winverbs\ulp\librdmacm\src/cma_main.cpp
--- trunk\ulp\librdmacm\src/cma_main.cpp 1969-12-31 16:00:00.000000000 -0800
+++ branches\winverbs\ulp\librdmacm\src/cma_main.cpp 2009-01-12 14:41:27.261146000 -0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008-2009 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under 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 AWV
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <windows.h>
+#include "cma.h"
+
+CRITICAL_SECTION lock;
+
+BOOLEAN WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+ UNREFERENCED_PARAMETER(hInstance);
+ UNREFERENCED_PARAMETER(dwReason);
+ UNREFERENCED_PARAMETER(lpReserved);
+
+ InitializeCriticalSection(&lock);
+
+ return TRUE;
+}
diff -up -N trunk\ulp\librdmacm\src/makefile branches\winverbs\ulp\librdmacm\src/makefile
--- trunk\ulp\librdmacm\src/makefile 1969-12-31 16:00:00.000000000 -0800
+++ branches\winverbs\ulp\librdmacm\src/makefile 2008-03-01 09:25:11.557027000 -0800
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the OpenIB Windows project.
+#
+
+!INCLUDE ..\..\..\inc\openib.def
diff -up -N trunk\ulp\librdmacm\src/Sources branches\winverbs\ulp\librdmacm\src/Sources
--- trunk\ulp\librdmacm\src/Sources 1969-12-31 16:00:00.000000000 -0800
+++ branches\winverbs\ulp\librdmacm\src/Sources 2008-12-18 18:02:59.514027900 -0800
@@ -0,0 +1,40 @@
+!if $(FREEBUILD)
+TARGETNAME = librdmacm
+!else
+TARGETNAME = librdmacmd
+!endif
+
+TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR)
+TARGETTYPE = DYNLINK
+
+!if $(_NT_TOOLS_VERSION) == 0x700
+DLLDEF = $O\cma_exports.def
+!else
+DLLDEF = $(OBJ_PATH)\$O\cma_exports.def
+!endif
+
+DLLENTRY = DllMain
+USE_MSVCRT = 1
+
+SOURCES = \
+ cma.rc \
+ cma_main.cpp \
+ cma.cpp
+
+INCLUDES = ..\include;..\..\..\inc;..\..\..\inc\user;..\..\libibverbs\include
+
+USER_C_FLAGS = $(USER_C_FLAGS) -DEXPORT_CMA_SYMBOLS
+
+TARGETLIBS = \
+ $(SDK_LIB_PATH)\kernel32.lib \
+ $(SDK_LIB_PATH)\uuid.lib \
+ $(SDK_LIB_PATH)\ws2_32.lib \
+ $(SDK_LIB_PATH)\iphlpapi.lib \
+ $(TARGETPATH)\*\ibat.lib \
+!if $(FREEBUILD)
+ $(TARGETPATH)\*\libibverbs.lib \
+ $(TARGETPATH)\*\winverbs.lib
+!else
+ $(TARGETPATH)\*\libibverbsd.lib \
+ $(TARGETPATH)\*\winverbsd.lib
+!endif
More information about the ofw
mailing list