-/*
- * Copyright (c) 2005 Voltaire Inc. All rights reserved.
- * Copyright (c) 2005-2007 Intel Corporation. All rights reserved.
- * Copyright (c) 2004-2005, Mellanox Technologies, Inc. All rights reserved.
- * Copyright (c) 2003 Topspin Corporation. All rights reserved.
- * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- *
- * This Software is licensed under one of the following licenses:
- *
- * 1) under the terms of the "Common Public License 1.0" a copy of which is
- * available from the Open Source Initiative, see
- * http://www.opensource.org/licenses/cpl.php.
- *
- * 2) under the terms of the "The BSD License" a copy of which is
- * available from the Open Source Initiative, see
- * http://www.opensource.org/licenses/bsd-license.php.
- *
- * 3) under the terms of the "GNU General Public License (GPL) Version 2" a
- * copy of which is available from the Open Source Initiative, see
- * http://www.opensource.org/licenses/gpl-license.php.
- *
- * Licensee has the right to choose one of the above licenses.
- *
- * Redistributions of source code must retain the above copyright
- * notice and one of the license notices.
- *
- * Redistributions in binary form must reproduce both the above copyright
- * notice, one of the license notices in the documentation
- * and/or other materials provided with the distribution.
- */
-
-/**********************************************************************
- *
- * MODULE: dapl_ib_cm.c
- *
- * PURPOSE: The OFED provider - uCMA, name and route resolution
- *
- * $Id: $
- *
- **********************************************************************/
-
-#include "dapl.h"
-#include "dapl_adapter_util.h"
-#include "dapl_evd_util.h"
-#include "dapl_cr_util.h"
-#include "dapl_name_service.h"
-#include "dapl_ib_util.h"
-#include "dapl_vendor.h"
-#include "dapl_osd.h"
-
-extern struct rdma_event_channel *g_cm_events;
-
-/* local prototypes */
-static struct dapl_cm_id *dapli_req_recv(struct dapl_cm_id *conn,
- struct rdma_cm_event *event);
-static void dapli_cm_active_cb(struct dapl_cm_id *conn,
- struct rdma_cm_event *event);
-static void dapli_cm_passive_cb(struct dapl_cm_id *conn,
- struct rdma_cm_event *event);
-static void dapli_addr_resolve(struct dapl_cm_id *conn);
-static void dapli_route_resolve(struct dapl_cm_id *conn);
-
-/* cma requires 16 bit SID, in network order */
-#define IB_PORT_MOD 32001
-#define IB_PORT_BASE (65535 - IB_PORT_MOD)
-#define SID_TO_PORT(SID) \
- (SID > 0xffff ? \
- htons((unsigned short)((SID % IB_PORT_MOD) + IB_PORT_BASE)) :\
- htons((unsigned short)SID))
-
-#define PORT_TO_SID(p) ntohs(p)
-
-/* private data header to validate consumer rejects versus abnormal events */
-struct dapl_pdata_hdr {
- DAT_UINT32 version;
-};
-
-static void dapli_addr_resolve(struct dapl_cm_id *conn)
-{
- int ret;
-#ifdef DAPL_DBG
- struct rdma_addr *ipaddr = &conn->cm_id->route.addr;
-#endif
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " addr_resolve: cm_id %p SRC %x DST %x\n",
- conn->cm_id, ntohl(((struct sockaddr_in *)
- &ipaddr->src_addr)->sin_addr.s_addr),
- ntohl(((struct sockaddr_in *)
- &ipaddr->dst_addr)->sin_addr.s_addr));
-
- ret = rdma_resolve_route(conn->cm_id, conn->route_timeout);
- if (ret) {
- dapl_log(DAPL_DBG_TYPE_ERR,
- " dapl_cma_connect: rdma_resolve_route ERR 0x%x %s\n",
- ret, strerror(errno));
- dapl_evd_connection_callback(conn,
- IB_CME_LOCAL_FAILURE,
- NULL, conn->ep);
- }
-}
-
-static void dapli_route_resolve(struct dapl_cm_id *conn)
-{
- int ret;
-#ifdef DAPL_DBG
- struct rdma_addr *ipaddr = &conn->cm_id->route.addr;
- struct ib_addr *ibaddr = &conn->cm_id->route.addr.addr.ibaddr;
-#endif
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " route_resolve: cm_id %p SRC %x DST %x PORT %d\n",
- conn->cm_id, ntohl(((struct sockaddr_in *)
- &ipaddr->src_addr)->sin_addr.s_addr),
- ntohl(((struct sockaddr_in *)
- &ipaddr->dst_addr)->sin_addr.s_addr),
- ntohs(((struct sockaddr_in *)
- &ipaddr->dst_addr)->sin_port));
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " route_resolve: SRC GID subnet %016llx id %016llx\n",
- (unsigned long long)
- ntohll(ibaddr->sgid.global.subnet_prefix),
- (unsigned long long)
- ntohll(ibaddr->sgid.global.interface_id));
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " route_resolve: DST GID subnet %016llx id %016llx\n",
- (unsigned long long)
- ntohll(ibaddr->dgid.global.subnet_prefix),
- (unsigned long long)
- ntohll(ibaddr->dgid.global.interface_id));
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " route_resolve: cm_id %p pdata %p plen %d rr %d ind %d\n",
- conn->cm_id,
- conn->params.private_data,
- conn->params.private_data_len,
- conn->params.responder_resources,
- conn->params.initiator_depth);
-
- ret = rdma_connect(conn->cm_id, &conn->params);
- if (ret) {
- dapl_log(DAPL_DBG_TYPE_ERR,
- " dapl_cma_connect: rdma_connect ERR %d %s\n",
- ret, strerror(errno));
- goto bail;
- }
- return;
-
- bail:
- dapl_evd_connection_callback(conn,
- IB_CME_LOCAL_FAILURE, NULL, conn->ep);
-}
-
-dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep)
-{
- dp_ib_cm_handle_t conn;
- struct rdma_cm_id *cm_id;
-
- /* Allocate CM and initialize lock */
- if ((conn = dapl_os_alloc(sizeof(*conn))) == NULL)
- return NULL;
-
- dapl_os_memzero(conn, sizeof(*conn));
- dapl_os_lock_init(&conn->lock);
- conn->refs++;
-
- /* create CM_ID, bind to local device, create QP */
- if (rdma_create_id(g_cm_events, &cm_id, (void *)conn, RDMA_PS_TCP)) {
- dapl_os_free(conn, sizeof(*conn));
- return NULL;
- }
- conn->cm_id = cm_id;
-
- /* setup timers for address and route resolution */
- conn->arp_timeout = dapl_os_get_env_val("DAPL_CM_ARP_TIMEOUT_MS",
- IB_ARP_TIMEOUT);
- conn->arp_retries = dapl_os_get_env_val("DAPL_CM_ARP_RETRY_COUNT",
- IB_ARP_RETRY_COUNT);
- conn->route_timeout = dapl_os_get_env_val("DAPL_CM_ROUTE_TIMEOUT_MS",
- IB_ROUTE_TIMEOUT);
- conn->route_retries = dapl_os_get_env_val("DAPL_CM_ROUTE_RETRY_COUNT",
- IB_ROUTE_RETRY_COUNT);
- if (ep != NULL) {
- conn->ep = ep;
- conn->hca = ((DAPL_IA *)ep->param.ia_handle)->hca_ptr;
- }
-
- return conn;
-}
-
-/*
- * Only called from consumer thread via dat_ep_free()
- * accept, reject, or connect.
- * Cannot be called from callback thread.
- * rdma_destroy_id will block until rdma_get_cm_event is acked.
- */
-void dapls_ib_cm_free(dp_ib_cm_handle_t conn, DAPL_EP *ep)
-{
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " destroy_conn: conn %p id %d\n",
- conn, conn->cm_id);
-
- dapl_os_lock(&conn->lock);
- conn->refs--;
- dapl_os_unlock(&conn->lock);
-
- /* block until event thread complete */
- while (conn->refs)
- dapl_os_sleep_usec(10000);
-
- if (ep) {
- ep->cm_handle = NULL;
- ep->qp_handle = NULL;
- ep->qp_state = IB_QP_STATE_ERROR;
- }
-
- if (conn->cm_id) {
- if (conn->cm_id->qp)
- rdma_destroy_qp(conn->cm_id);
- rdma_destroy_id(conn->cm_id);
- }
-
- dapl_os_free(conn, sizeof(*conn));
-}
-
-static struct dapl_cm_id *dapli_req_recv(struct dapl_cm_id *conn,
- struct rdma_cm_event *event)
-{
- struct dapl_cm_id *new_conn;
-#ifdef DAPL_DBG
- struct rdma_addr *ipaddr = &event->id->route.addr;
-#endif
-
- if (conn->sp == NULL) {
- dapl_dbg_log(DAPL_DBG_TYPE_ERR,
- " dapli_rep_recv: on invalid listen " "handle\n");
- return NULL;
- }
-
- /* allocate new cm_id and merge listen parameters */
- new_conn = dapl_os_alloc(sizeof(*new_conn));
- if (new_conn) {
- (void)dapl_os_memzero(new_conn, sizeof(*new_conn));
- dapl_os_lock_init(&new_conn->lock);
- new_conn->cm_id = event->id; /* provided by uCMA */
- event->id->context = new_conn; /* update CM_ID context */
- new_conn->sp = conn->sp;
- new_conn->hca = conn->hca;
- new_conn->refs++;
-
- /* Get requesters connect data, setup for accept */
- new_conn->params.responder_resources =
- DAPL_MIN(event->param.conn.responder_resources,
- conn->hca->ib_trans.rd_atom_in);
- new_conn->params.initiator_depth =
- DAPL_MIN(event->param.conn.initiator_depth,
- conn->hca->ib_trans.rd_atom_out);
-
- new_conn->params.flow_control = event->param.conn.flow_control;
- new_conn->params.rnr_retry_count =
- event->param.conn.rnr_retry_count;
- new_conn->params.retry_count = event->param.conn.retry_count;
-
- /* save private data */
- if (event->param.conn.private_data_len) {
- dapl_os_memcpy(new_conn->p_data,
- event->param.conn.private_data,
- event->param.conn.private_data_len);
- new_conn->params.private_data = new_conn->p_data;
- new_conn->params.private_data_len =
- event->param.conn.private_data_len;
- }
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " passive_cb: "
- "REQ: SP %p PORT %d LID %d "
- "NEW CONN %p ID %p pdata %p,%d\n",
- new_conn->sp, ntohs(((struct sockaddr_in *)
- &ipaddr->src_addr)->sin_port),
- event->listen_id, new_conn, event->id,
- event->param.conn.private_data,
- event->param.conn.private_data_len);
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " passive_cb: "
- "REQ: IP SRC %x PORT %d DST %x PORT %d "
- "rr %d init %d\n", ntohl(((struct sockaddr_in *)
- &ipaddr->src_addr)->
- sin_addr.s_addr),
- ntohs(((struct sockaddr_in *)
- &ipaddr->src_addr)->sin_port),
- ntohl(((struct sockaddr_in *)
- &ipaddr->dst_addr)->sin_addr.s_addr),
- ntohs(((struct sockaddr_in *)
- &ipaddr->dst_addr)->sin_port),
- new_conn->params.responder_resources,
- new_conn->params.initiator_depth);
- }
- return new_conn;
-}
-
-static void dapli_cm_active_cb(struct dapl_cm_id *conn,
- struct rdma_cm_event *event)
-{
- DAPL_OS_LOCK *lock = &conn->lock;
- ib_cm_events_t ib_cm_event;
- const void *pdata = NULL;
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " active_cb: conn %p id %d event %d\n",
- conn, conn->cm_id, event->event);
-
- /* There is a chance that we can get events after
- * the consumer calls disconnect in a pending state
- * since the IB CM and uDAPL states are not shared.
- * In some cases, IB CM could generate either a DCONN
- * or CONN_ERR after the consumer returned from
- * dapl_ep_disconnect with a DISCONNECTED event
- * already queued. Check state here and bail to
- * avoid any events after a disconnect.
- */
- if (DAPL_BAD_HANDLE(conn->ep, DAPL_MAGIC_EP))
- return;
-
- dapl_os_lock(&conn->ep->header.lock);
- if (conn->ep->param.ep_state == DAT_EP_STATE_DISCONNECTED) {
- dapl_os_unlock(&conn->ep->header.lock);
- return;
- }
- if (event->event == RDMA_CM_EVENT_DISCONNECTED)
- conn->ep->param.ep_state = DAT_EP_STATE_DISCONNECTED;
-
- dapl_os_unlock(&conn->ep->header.lock);
- dapl_os_lock(lock);
-
- switch (event->event) {
- case RDMA_CM_EVENT_UNREACHABLE:
- case RDMA_CM_EVENT_CONNECT_ERROR:
- dapl_log(DAPL_DBG_TYPE_WARN,
- "dapl_cma_active: CONN_ERR event=0x%x"
- " status=%d %s DST %s, %d\n",
- event->event, event->status,
- (event->status == -ETIMEDOUT) ? "TIMEOUT" : "",
- inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_addr),
- ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_port));
-
- /* per DAT SPEC provider always returns UNREACHABLE */
- ib_cm_event = IB_CME_DESTINATION_UNREACHABLE;
- break;
- case RDMA_CM_EVENT_REJECTED:
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " dapli_cm_active_handler: REJECTED reason=%d\n",
- event->status);
-
- /* valid REJ from consumer will always contain private data */
- if (event->status == 28 &&
- event->param.conn.private_data_len) {
- ib_cm_event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA;
- pdata =
- (unsigned char *)event->param.conn.
- private_data +
- sizeof(struct dapl_pdata_hdr);
- } else {
- ib_cm_event = IB_CME_DESTINATION_REJECT;
- dapl_log(DAPL_DBG_TYPE_WARN,
- "dapl_cma_active: non-consumer REJ,"
- " reason=%d, DST %s, %d\n",
- event->status,
- inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.
- dst_addr)->sin_addr),
- ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.
- dst_addr)->sin_port));
- }
- break;
- case RDMA_CM_EVENT_ESTABLISHED:
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " active_cb: cm_id %d PORT %d CONNECTED to %s!\n",
- conn->cm_id, ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.
- dst_addr)->sin_port),
- inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_addr));
-
- /* setup local and remote ports for ep query */
- conn->ep->param.remote_port_qual =
- PORT_TO_SID(rdma_get_dst_port(conn->cm_id));
- conn->ep->param.local_port_qual =
- PORT_TO_SID(rdma_get_src_port(conn->cm_id));
-
- ib_cm_event = IB_CME_CONNECTED;
- pdata = event->param.conn.private_data;
- break;
- case RDMA_CM_EVENT_DISCONNECTED:
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " active_cb: DISC EVENT - EP %p\n",conn->ep);
- rdma_disconnect(conn->cm_id); /* required for DREP */
- ib_cm_event = IB_CME_DISCONNECTED;
- /* validate EP handle */
- if (DAPL_BAD_HANDLE(conn->ep, DAPL_MAGIC_EP))
- conn = NULL;
- break;
- default:
- dapl_dbg_log(DAPL_DBG_TYPE_ERR,
- " dapli_cm_active_cb_handler: Unexpected CM "
- "event %d on ID 0x%p\n", event->event,
- conn->cm_id);
- conn = NULL;
- break;
- }
-
- dapl_os_unlock(lock);
- if (conn)
- dapl_evd_connection_callback(conn, ib_cm_event, pdata, conn->ep);
-}
-
-static void dapli_cm_passive_cb(struct dapl_cm_id *conn,
- struct rdma_cm_event *event)
-{
- ib_cm_events_t ib_cm_event;
- struct dapl_cm_id *conn_recv = conn;
- const void *pdata = NULL;
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " passive_cb: conn %p id %d event %d\n",
- conn, event->id, event->event);
-
- dapl_os_lock(&conn->lock);
-
- switch (event->event) {
- case RDMA_CM_EVENT_CONNECT_REQUEST:
- /* create new conn object with new conn_id from event */
- conn_recv = dapli_req_recv(conn, event);
- ib_cm_event = IB_CME_CONNECTION_REQUEST_PENDING;
- pdata = event->param.conn.private_data;
- break;
- case RDMA_CM_EVENT_UNREACHABLE:
- case RDMA_CM_EVENT_CONNECT_ERROR:
- dapl_log(DAPL_DBG_TYPE_WARN,
- "dapl_cm_passive: CONN_ERR event=0x%x status=%d %s,"
- " DST %s,%d\n",
- event->event, event->status,
- (event->status == -ETIMEDOUT) ? "TIMEOUT" : "",
- inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_addr), ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.
- dst_addr)->sin_port));
- ib_cm_event = IB_CME_DESTINATION_UNREACHABLE;
- break;
- case RDMA_CM_EVENT_REJECTED:
- /* will alwasys be abnormal NON-consumer from active side */
- dapl_log(DAPL_DBG_TYPE_WARN,
- "dapl_cm_passive: non-consumer REJ, reason=%d,"
- " DST %s, %d\n",
- event->status,
- inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_addr),
- ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_port));
- ib_cm_event = IB_CME_DESTINATION_REJECT;
- break;
- case RDMA_CM_EVENT_ESTABLISHED:
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " passive_cb: cm_id %p PORT %d CONNECTED from 0x%x!\n",
- conn->cm_id, ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.
- src_addr)->sin_port),
- ntohl(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_addr.s_addr));
- ib_cm_event = IB_CME_CONNECTED;
- break;
- case RDMA_CM_EVENT_DISCONNECTED:
- rdma_disconnect(conn->cm_id); /* required for DREP */
- ib_cm_event = IB_CME_DISCONNECTED;
- /* validate SP handle context */
- if (DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_PSP) &&
- DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_RSP))
- conn_recv = NULL;
- break;
- default:
- dapl_dbg_log(DAPL_DBG_TYPE_ERR, " passive_cb: "
- "Unexpected CM event %d on ID 0x%p\n",
- event->event, conn->cm_id);
- conn_recv = NULL;
- break;
- }
-
- dapl_os_unlock(&conn->lock);
- if (conn_recv)
- dapls_cr_callback(conn_recv, ib_cm_event, pdata, conn_recv->sp);
-}
-
-/************************ DAPL provider entry points **********************/
-
-/*
- * dapls_ib_connect
- *
- * Initiate a connection with the passive listener on another node
- *
- * Input:
- * ep_handle,
- * remote_ia_address,
- * remote_conn_qual,
- * prd_size size of private data and structure
- * prd_prt pointer to private data structure
- *
- * Output:
- * none
- *
- * Returns:
- * DAT_SUCCESS
- * DAT_INSUFFICIENT_RESOURCES
- * DAT_INVALID_PARAMETER
- *
- */
-DAT_RETURN dapls_ib_connect(IN DAT_EP_HANDLE ep_handle,
- IN DAT_IA_ADDRESS_PTR r_addr,
- IN DAT_CONN_QUAL r_qual,
- IN DAT_COUNT p_size, IN void *p_data)
-{
- struct dapl_ep *ep_ptr = ep_handle;
- struct dapl_cm_id *conn = ep_ptr->cm_handle;
- int ret;
-
- /* Sanity check */
- if (NULL == ep_ptr)
- return DAT_SUCCESS;
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " connect: rSID 0x%llx rPort %d, pdata %p, ln %d\n",
- r_qual, ntohs(SID_TO_PORT(r_qual)), p_data, p_size);
-
- /* rdma conn and cm_id pre-bound; reference via ep_ptr->cm_handle */
-
- /* Setup QP/CM parameters and private data in cm_id */
- (void)dapl_os_memzero(&conn->params, sizeof(conn->params));
- conn->params.responder_resources =
- ep_ptr->param.ep_attr.max_rdma_read_in;
- conn->params.initiator_depth = ep_ptr->param.ep_attr.max_rdma_read_out;
- conn->params.flow_control = 1;
- conn->params.rnr_retry_count = IB_RNR_RETRY_COUNT;
- conn->params.retry_count = IB_RC_RETRY_COUNT;
- if (p_size) {
- dapl_os_memcpy(conn->p_data, p_data, p_size);
- conn->params.private_data = conn->p_data;
- conn->params.private_data_len = p_size;
- }
-
- /* copy in remote address, need a copy for retry attempts */
- dapl_os_memcpy(&conn->r_addr, r_addr, sizeof(*r_addr));
-
- /* Resolve remote address, src already bound during QP create */
- ((struct sockaddr_in *)&conn->r_addr)->sin_port = SID_TO_PORT(r_qual);
- ((struct sockaddr_in *)&conn->r_addr)->sin_family = AF_INET;
-
- ret = rdma_resolve_addr(conn->cm_id, NULL,
- (struct sockaddr *)&conn->r_addr,
- conn->arp_timeout);
- if (ret) {
- dapl_log(DAPL_DBG_TYPE_ERR,
- " dapl_cma_connect: rdma_resolve_addr ERR 0x%x %s\n",
- ret, strerror(errno));
- return dapl_convert_errno(errno, "ib_connect");
- }
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " connect: resolve_addr: cm_id %p -> %s port %d\n",
- conn->cm_id,
- inet_ntoa(((struct sockaddr_in *)&conn->r_addr)->sin_addr),
- ((struct sockaddr_in *)&conn->r_addr)->sin_port);
-
- return DAT_SUCCESS;
-}
-
-/*
- * dapls_ib_disconnect
- *
- * Disconnect an EP
- *
- * Input:
- * ep_handle,
- * disconnect_flags
- *
- * Output:
- * none
- *
- * Returns:
- * DAT_SUCCESS
- *
- */
-DAT_RETURN
-dapls_ib_disconnect(IN DAPL_EP * ep_ptr, IN DAT_CLOSE_FLAGS close_flags)
-{
- dp_ib_cm_handle_t conn = ep_ptr->cm_handle;
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " disconnect(ep %p, conn %p, id %d flags %x)\n",
- ep_ptr, conn, (conn ? conn->cm_id : 0), close_flags);
-
- if ((conn == IB_INVALID_HANDLE) || (conn->cm_id == NULL))
- return DAT_SUCCESS;
-
- /* no graceful half-pipe disconnect option */
- rdma_disconnect(conn->cm_id);
-
- /*
- * DAT event notification occurs from the callback
- * Note: will fire even if DREQ goes unanswered on timeout
- */
- return DAT_SUCCESS;
-}
-
-/*
- * dapls_ib_disconnect_clean
- *
- * Clean up outstanding connection data. This routine is invoked
- * after the final disconnect callback has occurred. Only on the
- * ACTIVE side of a connection.
- *
- * Input:
- * ep_ptr DAPL_EP
- * active Indicates active side of connection
- *
- * Output:
- * none
- *
- * Returns:
- * void
- *
- */
-void
-dapls_ib_disconnect_clean(IN DAPL_EP * ep_ptr,
- IN DAT_BOOLEAN active,
- IN const ib_cm_events_t ib_cm_event)
-{
- /* nothing to do */
- return;
-}
-
-/*
- * dapl_ib_setup_conn_listener
- *
- * Have the CM set up a connection listener.
- *
- * Input:
- * ibm_hca_handle HCA handle
- * qp_handle QP handle
- *
- * Output:
- * none
- *
- * Returns:
- * DAT_SUCCESS
- * DAT_INSUFFICIENT_RESOURCES
- * DAT_INTERNAL_ERROR
- * DAT_CONN_QUAL_UNAVAILBLE
- * DAT_CONN_QUAL_IN_USE
- *
- */
-DAT_RETURN
-dapls_ib_setup_conn_listener(IN DAPL_IA * ia_ptr,
- IN DAT_UINT64 ServiceID, IN DAPL_SP * sp_ptr)
-{
- DAT_RETURN dat_status = DAT_SUCCESS;
- ib_cm_srvc_handle_t conn;
- DAT_SOCK_ADDR6 addr; /* local binding address */
-
- /* Allocate CM and initialize lock */
- if ((conn = dapl_os_alloc(sizeof(*conn))) == NULL)
- return DAT_INSUFFICIENT_RESOURCES;
-
- dapl_os_memzero(conn, sizeof(*conn));
- dapl_os_lock_init(&conn->lock);
- conn->refs++;
-
- /* create CM_ID, bind to local device, create QP */
- if (rdma_create_id
- (g_cm_events, &conn->cm_id, (void *)conn, RDMA_PS_TCP)) {
- dapl_os_free(conn, sizeof(*conn));
- return (dapl_convert_errno(errno, "setup_listener"));
- }
-
- /* open identifies the local device; per DAT specification */
- /* Get family and address then set port to consumer's ServiceID */
- dapl_os_memcpy(&addr, &ia_ptr->hca_ptr->hca_address, sizeof(addr));
- ((struct sockaddr_in *)&addr)->sin_port = SID_TO_PORT(ServiceID);
-
- if (rdma_bind_addr(conn->cm_id, (struct sockaddr *)&addr)) {
- if ((errno == EBUSY) || (errno == EADDRINUSE))
- dat_status = DAT_CONN_QUAL_IN_USE;
- else
- dat_status =
- dapl_convert_errno(errno, "setup_listener");
- goto bail;
- }
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " listen(ia_ptr %p SID 0x%llx Port %d sp %p conn %p id %d)\n",
- ia_ptr, ServiceID, ntohs(SID_TO_PORT(ServiceID)),
- sp_ptr, conn, conn->cm_id);
-
- sp_ptr->cm_srvc_handle = conn;
- conn->sp = sp_ptr;
- conn->hca = ia_ptr->hca_ptr;
-
- dapl_dbg_log(DAPL_DBG_TYPE_EP,
- " listen(conn=%p cm_id=%d)\n",
- sp_ptr->cm_srvc_handle, conn->cm_id);
-
- if (rdma_listen(conn->cm_id, 0)) { /* max cma backlog */
-
- if ((errno == EBUSY) || (errno == EADDRINUSE))
- dat_status = DAT_CONN_QUAL_IN_USE;
- else
- dat_status =
- dapl_convert_errno(errno, "setup_listener");
- goto bail;
- }
-
- /* success */
- return DAT_SUCCESS;
-
- bail:
- rdma_destroy_id(conn->cm_id);
- dapl_os_free(conn, sizeof(*conn));
- return dat_status;
-}
-
-/*
- * dapl_ib_remove_conn_listener
- *
- * Have the CM remove a connection listener.
- *
- * Input:
- * ia_handle IA handle
- * ServiceID IB Channel Service ID
- *
- * Output:
- * none
- *
- * Returns:
- * DAT_SUCCESS
- * DAT_INVALID_STATE
- *
- */
-DAT_RETURN
-dapls_ib_remove_conn_listener(IN DAPL_IA * ia_ptr, IN DAPL_SP * sp_ptr)
-{
- ib_cm_srvc_handle_t conn = sp_ptr->cm_srvc_handle;
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " remove_listen(ia_ptr %p sp_ptr %p cm_ptr %p)\n",
- ia_ptr, sp_ptr, conn);
-
- if (conn != IB_INVALID_HANDLE) {
- sp_ptr->cm_srvc_handle = NULL;
- dapls_ib_cm_free(conn, NULL);
- }
- return DAT_SUCCESS;
-}
-
-/*
- * dapls_ib_accept_connection
- *
- * Perform necessary steps to accept a connection
- *
- * Input:
- * cr_handle
- * ep_handle
- * private_data_size
- * private_data
- *
- * Output:
- * none
- *
- * Returns:
- * DAT_SUCCESS
- * DAT_INSUFFICIENT_RESOURCES
- * DAT_INTERNAL_ERROR
- *
- */
-DAT_RETURN
-dapls_ib_accept_connection(IN DAT_CR_HANDLE cr_handle,
- IN DAT_EP_HANDLE ep_handle,
- IN DAT_COUNT p_size, IN const DAT_PVOID p_data)
-{
- DAPL_CR *cr_ptr = (DAPL_CR *) cr_handle;
- DAPL_EP *ep_ptr = (DAPL_EP *) ep_handle;
- DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;
- struct dapl_cm_id *cr_conn = cr_ptr->ib_cm_handle;
- int ret;
- DAT_RETURN dat_status;
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " accept(cr %p conn %p, id %p, p_data %p, p_sz=%d)\n",
- cr_ptr, cr_conn, cr_conn->cm_id, p_data, p_size);
-
- /* Obtain size of private data structure & contents */
- if (p_size > IB_MAX_REP_PDATA_SIZE) {
- dat_status = DAT_ERROR(DAT_LENGTH_ERROR, DAT_NO_SUBTYPE);
- goto bail;
- }
-
- if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {
- /*
- * If we are lazy attaching the QP then we may need to
- * hook it up here. Typically, we run this code only for
- * DAT_PSP_PROVIDER_FLAG
- */
- dat_status = dapls_ib_qp_alloc(ia_ptr, ep_ptr, NULL);
- if (dat_status != DAT_SUCCESS) {
- dapl_log(DAPL_DBG_TYPE_ERR,
- " dapl_cma_accept: qp_alloc ERR %d\n",
- dat_status);
- goto bail;
- }
- }
-
- /*
- * Validate device and port in EP cm_id against inbound
- * CR cm_id. The pre-allocated EP cm_id is already bound to
- * a local device (cm_id and QP) when created. Move the QP
- * to the new cm_id only if device and port numbers match.
- */
- if (ep_ptr->cm_handle->cm_id->verbs == cr_conn->cm_id->verbs &&
- ep_ptr->cm_handle->cm_id->port_num == cr_conn->cm_id->port_num) {
- /* move QP to new cr_conn, remove QP ref in EP cm_id */
- cr_conn->cm_id->qp = ep_ptr->cm_handle->cm_id->qp;
- ep_ptr->cm_handle->cm_id->qp = NULL;
- dapls_ib_cm_free(ep_ptr->cm_handle, NULL);
- } else {
- dapl_log(DAPL_DBG_TYPE_ERR,
- " dapl_cma_accept: ERR dev(%p!=%p) or"
- " port mismatch(%d!=%d)\n",
- ep_ptr->cm_handle->cm_id->verbs, cr_conn->cm_id->verbs,
- ntohs(ep_ptr->cm_handle->cm_id->port_num),
- ntohs(cr_conn->cm_id->port_num));
- dat_status = DAT_INTERNAL_ERROR;
- goto bail;
- }
-
- cr_ptr->param.local_ep_handle = ep_handle;
- cr_conn->params.private_data = p_data;
- cr_conn->params.private_data_len = p_size;
-
- ret = rdma_accept(cr_conn->cm_id, &cr_conn->params);
- if (ret) {
- dapl_log(DAPL_DBG_TYPE_ERR, " dapl_cma_accept: ERR %d %s\n",
- ret, strerror(errno));
- dat_status = dapl_convert_errno(ret, "accept");
- goto bail;
- }
-
- /* save accepted conn and EP reference, qp_handle unchanged */
- ep_ptr->cm_handle = cr_conn;
- cr_conn->ep = ep_ptr;
-
- /* setup local and remote ports for ep query */
- /* Note: port qual in network order */
- ep_ptr->param.remote_port_qual =
- PORT_TO_SID(rdma_get_dst_port(cr_conn->cm_id));
- ep_ptr->param.local_port_qual =
- PORT_TO_SID(rdma_get_src_port(cr_conn->cm_id));
-
- return DAT_SUCCESS;
- bail:
- rdma_reject(cr_conn->cm_id, NULL, 0);
- dapls_ib_cm_free(cr_conn, NULL);
- return dat_status;
-}
-
-/*
- * dapls_ib_reject_connection
- *
- * Reject a connection
- *
- * Input:
- * cr_handle
- *
- * Output:
- * none
- *
- * Returns:
- * DAT_SUCCESS
- * DAT_INTERNAL_ERROR
- *
- */
-DAT_RETURN
-dapls_ib_reject_connection(IN dp_ib_cm_handle_t cm_handle,
- IN int reason,
- IN DAT_COUNT private_data_size,
- IN const DAT_PVOID private_data)
-{
- int ret;
- int offset = sizeof(struct dapl_pdata_hdr);
- struct dapl_pdata_hdr pdata_hdr;
-
- memset(&pdata_hdr, 0, sizeof pdata_hdr);
- pdata_hdr.version = htonl((DAT_VERSION_MAJOR << 24) |
- (DAT_VERSION_MINOR << 16) |
- (VN_PROVIDER_MAJOR << 8) |
- (VN_PROVIDER_MINOR));
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " reject: handle %p reason %x, ver=%x, data %p, sz=%d\n",
- cm_handle, reason, ntohl(pdata_hdr.version),
- private_data, private_data_size);
-
- if (cm_handle == IB_INVALID_HANDLE) {
- dapl_dbg_log(DAPL_DBG_TYPE_ERR,
- " reject: invalid handle: reason %d\n", reason);
- return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR);
- }
-
- if (private_data_size >
- dapls_ib_private_data_size(NULL, DAPL_PDATA_CONN_REJ,
- cm_handle->hca))
- return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
-
- /* setup pdata_hdr and users data, in CR pdata buffer */
- dapl_os_memcpy(cm_handle->p_data, &pdata_hdr, offset);
- if (private_data_size)
- dapl_os_memcpy(cm_handle->p_data + offset,
- private_data, private_data_size);
-
- /*
- * Always some private data with reject so active peer can
- * determine real application reject from an abnormal
- * application termination
- */
- ret = rdma_reject(cm_handle->cm_id,
- cm_handle->p_data, offset + private_data_size);
-
- dapls_ib_cm_free(cm_handle, NULL);
- return dapl_convert_errno(ret, "reject");
-}
-
-/*
- * dapls_ib_cm_remote_addr
- *
- * Obtain the remote IP address given a connection
- *
- * Input:
- * cr_handle
- *
- * Output:
- * remote_ia_address: where to place the remote address
- *
- * Returns:
- * DAT_SUCCESS
- * DAT_INVALID_HANDLE
- *
- */
-DAT_RETURN
-dapls_ib_cm_remote_addr(IN DAT_HANDLE dat_handle, OUT DAT_SOCK_ADDR6 * raddr)
-{
- DAPL_HEADER *header;
- dp_ib_cm_handle_t ib_cm_handle;
- struct rdma_addr *ipaddr;
-
- dapl_dbg_log(DAPL_DBG_TYPE_EP,
- " remote_addr(cm_handle=%p, r_addr=%p)\n",
- dat_handle, raddr);
-
- header = (DAPL_HEADER *) dat_handle;
-
- if (header->magic == DAPL_MAGIC_EP)
- ib_cm_handle = ((DAPL_EP *) dat_handle)->cm_handle;
- else if (header->magic == DAPL_MAGIC_CR)
- ib_cm_handle = ((DAPL_CR *) dat_handle)->ib_cm_handle;
- else
- return DAT_INVALID_HANDLE;
-
- /* get remote IP address from cm_id route */
- ipaddr = &ib_cm_handle->cm_id->route.addr;
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " remote_addr: conn %p id %p SRC %x DST %x PORT %d\n",
- ib_cm_handle, ib_cm_handle->cm_id,
- ntohl(((struct sockaddr_in *)
- &ipaddr->src_addr)->sin_addr.s_addr),
- ntohl(((struct sockaddr_in *)
- &ipaddr->dst_addr)->sin_addr.s_addr),
- ntohs(((struct sockaddr_in *)
- &ipaddr->dst_addr)->sin_port));
-
- dapl_os_memcpy(raddr, &ipaddr->dst_addr, sizeof(DAT_SOCK_ADDR));
- return DAT_SUCCESS;
-}
-
-/*
- * dapls_ib_private_data_size
- *
- * Return the size of private data given a connection op type
- *
- * Input:
- * prd_ptr private data pointer
- * conn_op connection operation type
- * hca_ptr hca pointer, needed for transport type
- *
- * If prd_ptr is NULL, this is a query for the max size supported by
- * the provider, otherwise it is the actual size of the private data
- * contained in prd_ptr.
- *
- *
- * Output:
- * None
- *
- * Returns:
- * length of private data
- *
- */
-int dapls_ib_private_data_size(IN DAPL_PRIVATE * prd_ptr,
- IN DAPL_PDATA_OP conn_op, IN DAPL_HCA * hca_ptr)
-{
- int size;
-
- if (hca_ptr->ib_hca_handle->device->transport_type
- == IBV_TRANSPORT_IWARP)
- return (IWARP_MAX_PDATA_SIZE - sizeof(struct dapl_pdata_hdr));
-
- switch (conn_op) {
-
- case DAPL_PDATA_CONN_REQ:
- size = IB_MAX_REQ_PDATA_SIZE;
- break;
- case DAPL_PDATA_CONN_REP:
- size = IB_MAX_REP_PDATA_SIZE;
- break;
- case DAPL_PDATA_CONN_REJ:
- size = IB_MAX_REJ_PDATA_SIZE - sizeof(struct dapl_pdata_hdr);
- break;
- case DAPL_PDATA_CONN_DREQ:
- size = IB_MAX_DREQ_PDATA_SIZE;
- break;
- case DAPL_PDATA_CONN_DREP:
- size = IB_MAX_DREP_PDATA_SIZE;
- break;
- default:
- size = 0;
-
- } /* end case */
-
- return size;
-}
-
-/*
- * Map all CMA event codes to the DAT equivelent.
- */
-#define DAPL_IB_EVENT_CNT 13
-
-static struct ib_cm_event_map {
- const ib_cm_events_t ib_cm_event;
- DAT_EVENT_NUMBER dat_event_num;
-} ib_cm_event_map[DAPL_IB_EVENT_CNT] = {
- /* 00 */ {
- IB_CME_CONNECTED, DAT_CONNECTION_EVENT_ESTABLISHED},
- /* 01 */ {
- IB_CME_DISCONNECTED, DAT_CONNECTION_EVENT_DISCONNECTED},
- /* 02 */ {
- IB_CME_DISCONNECTED_ON_LINK_DOWN,
- DAT_CONNECTION_EVENT_DISCONNECTED},
- /* 03 */ {
- IB_CME_CONNECTION_REQUEST_PENDING, DAT_CONNECTION_REQUEST_EVENT},
- /* 04 */ {
- IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA,
- DAT_CONNECTION_REQUEST_EVENT},
- /* 05 */ {
- IB_CME_CONNECTION_REQUEST_ACKED, DAT_CONNECTION_REQUEST_EVENT},
- /* 06 */ {
- IB_CME_DESTINATION_REJECT,
- DAT_CONNECTION_EVENT_NON_PEER_REJECTED},
- /* 07 */ {
- IB_CME_DESTINATION_REJECT_PRIVATE_DATA,
- DAT_CONNECTION_EVENT_PEER_REJECTED},
- /* 08 */ {
- IB_CME_DESTINATION_UNREACHABLE, DAT_CONNECTION_EVENT_UNREACHABLE},
- /* 09 */ {
- IB_CME_TOO_MANY_CONNECTION_REQUESTS,
- DAT_CONNECTION_EVENT_NON_PEER_REJECTED},
- /* 10 */ {
- IB_CME_LOCAL_FAILURE, DAT_CONNECTION_EVENT_BROKEN},
- /* 11 */ {
- IB_CME_BROKEN, DAT_CONNECTION_EVENT_BROKEN},
- /* 12 */ {
-IB_CME_TIMEOUT, DAT_CONNECTION_EVENT_TIMED_OUT},};
-
-/*
- * dapls_ib_get_cm_event
- *
- * Return a DAT connection event given a provider CM event.
- *
- * Input:
- * dat_event_num DAT event we need an equivelent CM event for
- *
- * Output:
- * none
- *
- * Returns:
- * ib_cm_event of translated DAPL value
- */
-DAT_EVENT_NUMBER
-dapls_ib_get_dat_event(IN const ib_cm_events_t ib_cm_event,
- IN DAT_BOOLEAN active)
-{
- DAT_EVENT_NUMBER dat_event_num;
- int i;
-
- active = active;
-
- dat_event_num = 0;
- for (i = 0; i < DAPL_IB_EVENT_CNT; i++) {
- if (ib_cm_event == ib_cm_event_map[i].ib_cm_event) {
- dat_event_num = ib_cm_event_map[i].dat_event_num;
- break;
- }
- }
- dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,
- "dapls_ib_get_dat_event: event(%s) ib=0x%x dat=0x%x\n",
- active ? "active" : "passive", ib_cm_event, dat_event_num);
-
- return dat_event_num;
-}
-
-/*
- * dapls_ib_get_dat_event
- *
- * Return a DAT connection event given a provider CM event.
- *
- * Input:
- * ib_cm_event event provided to the dapl callback routine
- * active switch indicating active or passive connection
- *
- * Output:
- * none
- *
- * Returns:
- * DAT_EVENT_NUMBER of translated provider value
- */
-ib_cm_events_t dapls_ib_get_cm_event(IN DAT_EVENT_NUMBER dat_event_num)
-{
- ib_cm_events_t ib_cm_event;
- int i;
-
- ib_cm_event = 0;
- for (i = 0; i < DAPL_IB_EVENT_CNT; i++) {
- if (dat_event_num == ib_cm_event_map[i].dat_event_num) {
- ib_cm_event = ib_cm_event_map[i].ib_cm_event;
- break;
- }
- }
- return ib_cm_event;
-}
-
-void dapli_cma_event_cb(void)
-{
- struct rdma_cm_event *event;
-
- /* process one CM event, fairness, non-blocking */
- if (!rdma_get_cm_event(g_cm_events, &event)) {
- struct dapl_cm_id *conn;
-
- /* set proper conn from cm_id context */
- if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST)
- conn = (struct dapl_cm_id *)event->listen_id->context;
- else
- conn = (struct dapl_cm_id *)event->id->context;
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " cm_event: EVENT=%d ID=%p LID=%p CTX=%p\n",
- event->event, event->id, event->listen_id, conn);
-
- /* cm_free is blocked waiting for ack */
- dapl_os_lock(&conn->lock);
- if (!conn->refs) {
- dapl_os_unlock(&conn->lock);
- rdma_ack_cm_event(event);
- return;
- }
- conn->refs++;
- dapl_os_unlock(&conn->lock);
-
- switch (event->event) {
- case RDMA_CM_EVENT_ADDR_RESOLVED:
- dapli_addr_resolve(conn);
- break;
-
- case RDMA_CM_EVENT_ROUTE_RESOLVED:
- dapli_route_resolve(conn);
- break;
-
- case RDMA_CM_EVENT_ADDR_ERROR:
- dapl_log(DAPL_DBG_TYPE_WARN,
- "dapl_cma_active: CM ADDR ERROR: ->"
- " DST %s retry (%d)..\n",
- inet_ntoa(((struct sockaddr_in *)
- &conn->r_addr)->sin_addr),
- conn->arp_retries);
-
- /* retry address resolution */
- if ((--conn->arp_retries) &&
- (event->status == -ETIMEDOUT)) {
- int ret;
- ret = rdma_resolve_addr(conn->cm_id, NULL,
- (struct sockaddr *)
- &conn->r_addr,
- conn->arp_timeout);
- if (!ret)
- break;
- else {
- dapl_dbg_log(DAPL_DBG_TYPE_WARN,
- " ERROR: rdma_resolve_addr = "
- "%d %s\n",
- ret, strerror(errno));
- }
- }
- /* retries exhausted or resolve_addr failed */
- dapl_log(DAPL_DBG_TYPE_ERR,
- "dapl_cma_active: ARP_ERR, retries(%d)"
- " exhausted -> DST %s,%d\n",
- IB_ARP_RETRY_COUNT,
- inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_addr),
- ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_port));
-
- dapl_evd_connection_callback(conn,
- IB_CME_DESTINATION_UNREACHABLE,
- NULL, conn->ep);
- break;
-
- case RDMA_CM_EVENT_ROUTE_ERROR:
- dapl_log(DAPL_DBG_TYPE_WARN,
- "dapl_cma_active: CM ROUTE ERROR: ->"
- " DST %s retry (%d)..\n",
- inet_ntoa(((struct sockaddr_in *)
- &conn->r_addr)->sin_addr),
- conn->route_retries);
-
- /* retry route resolution */
- if ((--conn->route_retries) &&
- (event->status == -ETIMEDOUT))
- dapli_addr_resolve(conn);
- else {
- dapl_log(DAPL_DBG_TYPE_ERR,
- "dapl_cma_active: PATH_RECORD_ERR,"
- " retries(%d) exhausted, DST %s,%d\n",
- IB_ROUTE_RETRY_COUNT,
- inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.
- dst_addr)->sin_addr),
- ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.
- dst_addr)->sin_port));
-
- dapl_evd_connection_callback(conn,
- IB_CME_DESTINATION_UNREACHABLE,
- NULL, conn->ep);
- }
- break;
-
- case RDMA_CM_EVENT_DEVICE_REMOVAL:
- dapl_evd_connection_callback(conn,
- IB_CME_LOCAL_FAILURE,
- NULL, conn->ep);
- break;
- case RDMA_CM_EVENT_CONNECT_REQUEST:
- case RDMA_CM_EVENT_CONNECT_ERROR:
- case RDMA_CM_EVENT_UNREACHABLE:
- case RDMA_CM_EVENT_REJECTED:
- case RDMA_CM_EVENT_ESTABLISHED:
- case RDMA_CM_EVENT_DISCONNECTED:
- /* passive or active */
- if (conn->sp)
- dapli_cm_passive_cb(conn, event);
- else
- dapli_cm_active_cb(conn, event);
- break;
- case RDMA_CM_EVENT_CONNECT_RESPONSE:
-#ifdef RDMA_CM_EVENT_TIMEWAIT_EXIT
- case RDMA_CM_EVENT_TIMEWAIT_EXIT:
-#endif
- break;
- default:
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " cm_event: UNEXPECTED EVENT=%p ID=%p CTX=%p\n",
- event->event, event->id,
- event->id->context);
- break;
- }
-
- /* ack event, unblocks destroy_cm_id in consumer threads */
- rdma_ack_cm_event(event);
-
- dapl_os_lock(&conn->lock);
- conn->refs--;
- dapl_os_unlock(&conn->lock);
- }
-}
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * End:
- */
+/*\r
+ * Copyright (c) 2005 Voltaire Inc. All rights reserved.\r
+ * Copyright (c) 2005-2007 Intel Corporation. All rights reserved.\r
+ * Copyright (c) 2004-2005, Mellanox Technologies, Inc. All rights reserved. \r
+ * Copyright (c) 2003 Topspin Corporation. All rights reserved. \r
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.\r
+ *\r
+ * This Software is licensed under one of the following licenses:\r
+ *\r
+ * 1) under the terms of the "Common Public License 1.0" a copy of which is\r
+ * available from the Open Source Initiative, see\r
+ * http://www.opensource.org/licenses/cpl.php.\r
+ *\r
+ * 2) under the terms of the "The BSD License" a copy of which is\r
+ * available from the Open Source Initiative, see\r
+ * http://www.opensource.org/licenses/bsd-license.php.\r
+ *\r
+ * 3) under the terms of the "GNU General Public License (GPL) Version 2" a\r
+ * copy of which is available from the Open Source Initiative, see\r
+ * http://www.opensource.org/licenses/gpl-license.php.\r
+ *\r
+ * Licensee has the right to choose one of the above licenses.\r
+ *\r
+ * Redistributions of source code must retain the above copyright\r
+ * notice and one of the license notices.\r
+ *\r
+ * Redistributions in binary form must reproduce both the above copyright\r
+ * notice, one of the license notices in the documentation\r
+ * and/or other materials provided with the distribution.\r
+ */\r
+\r
+/**********************************************************************\r
+ *\r
+ * MODULE: dapl_ib_cm.c\r
+ *\r
+ * PURPOSE: The OFED provider - uCMA, name and route resolution\r
+ *\r
+ * $Id: $\r
+ *\r
+ **********************************************************************/\r
+\r
+#include "dapl.h"\r
+#include "dapl_adapter_util.h"\r
+#include "dapl_evd_util.h"\r
+#include "dapl_cr_util.h"\r
+#include "dapl_name_service.h"\r
+#include "dapl_ib_util.h"\r
+#include "dapl_vendor.h"\r
+#include "dapl_osd.h"\r
+\r
+extern struct rdma_event_channel *g_cm_events;\r
+\r
+/* local prototypes */\r
+static struct dapl_cm_id *dapli_req_recv(struct dapl_cm_id *conn,\r
+ struct rdma_cm_event *event);\r
+static void dapli_cm_active_cb(struct dapl_cm_id *conn,\r
+ struct rdma_cm_event *event);\r
+static void dapli_cm_passive_cb(struct dapl_cm_id *conn,\r
+ struct rdma_cm_event *event);\r
+static void dapli_addr_resolve(struct dapl_cm_id *conn);\r
+static void dapli_route_resolve(struct dapl_cm_id *conn);\r
+\r
+/* cma requires 16 bit SID, in network order */\r
+#define IB_PORT_MOD 32001\r
+#define IB_PORT_BASE (65535 - IB_PORT_MOD)\r
+#define SID_TO_PORT(SID) \\r
+ (SID > 0xffff ? \\r
+ htons((unsigned short)((SID % IB_PORT_MOD) + IB_PORT_BASE)) :\\r
+ htons((unsigned short)SID))\r
+\r
+#define PORT_TO_SID(p) ntohs(p)\r
+\r
+/* private data header to validate consumer rejects versus abnormal events */\r
+struct dapl_pdata_hdr {\r
+ DAT_UINT32 version;\r
+};\r
+\r
+static void dapli_addr_resolve(struct dapl_cm_id *conn)\r
+{\r
+ int ret;\r
+#ifdef DAPL_DBG\r
+ struct rdma_addr *ipaddr = &conn->cm_id->route.addr;\r
+#endif\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " addr_resolve: cm_id %p SRC %x DST %x\n",\r
+ conn->cm_id, ntohl(((struct sockaddr_in *)\r
+ &ipaddr->src_addr)->sin_addr.s_addr),\r
+ ntohl(((struct sockaddr_in *)\r
+ &ipaddr->dst_addr)->sin_addr.s_addr));\r
+\r
+ ret = rdma_resolve_route(conn->cm_id, conn->route_timeout);\r
+ if (ret) {\r
+ dapl_log(DAPL_DBG_TYPE_ERR,\r
+ " dapl_cma_connect: rdma_resolve_route ERR 0x%x %s\n",\r
+ ret, strerror(errno));\r
+ dapl_evd_connection_callback(conn,\r
+ IB_CME_LOCAL_FAILURE,\r
+ NULL, conn->ep);\r
+ }\r
+}\r
+\r
+static void dapli_route_resolve(struct dapl_cm_id *conn)\r
+{\r
+ int ret;\r
+#ifdef DAPL_DBG\r
+ struct rdma_addr *ipaddr = &conn->cm_id->route.addr;\r
+ struct ib_addr *ibaddr = &conn->cm_id->route.addr.addr.ibaddr;\r
+#endif\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " route_resolve: cm_id %p SRC %x DST %x PORT %d\n",\r
+ conn->cm_id, ntohl(((struct sockaddr_in *)\r
+ &ipaddr->src_addr)->sin_addr.s_addr),\r
+ ntohl(((struct sockaddr_in *)\r
+ &ipaddr->dst_addr)->sin_addr.s_addr),\r
+ ntohs(((struct sockaddr_in *)\r
+ &ipaddr->dst_addr)->sin_port));\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " route_resolve: SRC GID subnet %016llx id %016llx\n",\r
+ (unsigned long long)\r
+ ntohll(ibaddr->sgid.global.subnet_prefix),\r
+ (unsigned long long)\r
+ ntohll(ibaddr->sgid.global.interface_id));\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " route_resolve: DST GID subnet %016llx id %016llx\n",\r
+ (unsigned long long)\r
+ ntohll(ibaddr->dgid.global.subnet_prefix),\r
+ (unsigned long long)\r
+ ntohll(ibaddr->dgid.global.interface_id));\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " route_resolve: cm_id %p pdata %p plen %d rr %d ind %d\n",\r
+ conn->cm_id,\r
+ conn->params.private_data,\r
+ conn->params.private_data_len,\r
+ conn->params.responder_resources,\r
+ conn->params.initiator_depth);\r
+\r
+ ret = rdma_connect(conn->cm_id, &conn->params);\r
+ if (ret) {\r
+ dapl_log(DAPL_DBG_TYPE_ERR,\r
+ " dapl_cma_connect: rdma_connect ERR %d %s\n",\r
+ ret, strerror(errno));\r
+ goto bail;\r
+ }\r
+ return;\r
+\r
+ bail:\r
+ dapl_evd_connection_callback(conn,\r
+ IB_CME_LOCAL_FAILURE, NULL, conn->ep);\r
+}\r
+\r
+dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep)\r
+{\r
+ dp_ib_cm_handle_t conn;\r
+ struct rdma_cm_id *cm_id;\r
+\r
+ /* Allocate CM and initialize lock */\r
+ if ((conn = dapl_os_alloc(sizeof(*conn))) == NULL)\r
+ return NULL;\r
+\r
+ dapl_os_memzero(conn, sizeof(*conn));\r
+ dapl_os_lock_init(&conn->lock);\r
+ conn->refs++;\r
+\r
+ /* create CM_ID, bind to local device, create QP */\r
+ if (rdma_create_id(g_cm_events, &cm_id, (void *)conn, RDMA_PS_TCP)) {\r
+ dapl_os_free(conn, sizeof(*conn));\r
+ return NULL;\r
+ }\r
+ conn->cm_id = cm_id;\r
+\r
+ /* setup timers for address and route resolution */\r
+ conn->arp_timeout = dapl_os_get_env_val("DAPL_CM_ARP_TIMEOUT_MS",\r
+ IB_ARP_TIMEOUT);\r
+ conn->arp_retries = dapl_os_get_env_val("DAPL_CM_ARP_RETRY_COUNT",\r
+ IB_ARP_RETRY_COUNT);\r
+ conn->route_timeout = dapl_os_get_env_val("DAPL_CM_ROUTE_TIMEOUT_MS",\r
+ IB_ROUTE_TIMEOUT);\r
+ conn->route_retries = dapl_os_get_env_val("DAPL_CM_ROUTE_RETRY_COUNT",\r
+ IB_ROUTE_RETRY_COUNT);\r
+ if (ep != NULL) {\r
+ conn->ep = ep;\r
+ conn->hca = ((DAPL_IA *)ep->param.ia_handle)->hca_ptr;\r
+ }\r
+\r
+ return conn;\r
+}\r
+\r
+/* \r
+ * Only called from consumer thread via dat_ep_free()\r
+ * accept, reject, or connect.\r
+ * Cannot be called from callback thread.\r
+ * rdma_destroy_id will block until rdma_get_cm_event is acked.\r
+ */\r
+void dapls_ib_cm_free(dp_ib_cm_handle_t conn, DAPL_EP *ep)\r
+{\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " destroy_conn: conn %p id %d\n", \r
+ conn, conn->cm_id);\r
+\r
+ dapl_os_lock(&conn->lock);\r
+ conn->refs--;\r
+ dapl_os_unlock(&conn->lock);\r
+\r
+ /* block until event thread complete */\r
+ while (conn->refs) \r
+ dapl_os_sleep_usec(10000);\r
+ \r
+ if (ep) {\r
+ ep->cm_handle = NULL;\r
+ ep->qp_handle = NULL;\r
+ ep->qp_state = IB_QP_STATE_ERROR;\r
+ }\r
+\r
+ if (conn->cm_id) {\r
+ if (conn->cm_id->qp)\r
+ rdma_destroy_qp(conn->cm_id);\r
+ rdma_destroy_id(conn->cm_id);\r
+ }\r
+\r
+ dapl_os_free(conn, sizeof(*conn));\r
+}\r
+\r
+static struct dapl_cm_id *dapli_req_recv(struct dapl_cm_id *conn,\r
+ struct rdma_cm_event *event)\r
+{\r
+ struct dapl_cm_id *new_conn;\r
+#ifdef DAPL_DBG\r
+ struct rdma_addr *ipaddr = &event->id->route.addr;\r
+#endif\r
+\r
+ if (conn->sp == NULL) {\r
+ dapl_dbg_log(DAPL_DBG_TYPE_ERR,\r
+ " dapli_rep_recv: on invalid listen " "handle\n");\r
+ return NULL;\r
+ }\r
+\r
+ /* allocate new cm_id and merge listen parameters */\r
+ new_conn = dapl_os_alloc(sizeof(*new_conn));\r
+ if (new_conn) {\r
+ (void)dapl_os_memzero(new_conn, sizeof(*new_conn));\r
+ dapl_os_lock_init(&new_conn->lock);\r
+ new_conn->cm_id = event->id; /* provided by uCMA */\r
+ event->id->context = new_conn; /* update CM_ID context */\r
+ new_conn->sp = conn->sp;\r
+ new_conn->hca = conn->hca;\r
+ new_conn->refs++;\r
+\r
+ /* Get requesters connect data, setup for accept */\r
+ new_conn->params.responder_resources =\r
+ DAPL_MIN(event->param.conn.responder_resources,\r
+ conn->hca->ib_trans.rd_atom_in);\r
+ new_conn->params.initiator_depth =\r
+ DAPL_MIN(event->param.conn.initiator_depth,\r
+ conn->hca->ib_trans.rd_atom_out);\r
+\r
+ new_conn->params.flow_control = event->param.conn.flow_control;\r
+ new_conn->params.rnr_retry_count =\r
+ event->param.conn.rnr_retry_count;\r
+ new_conn->params.retry_count = event->param.conn.retry_count;\r
+\r
+ /* save private data */\r
+ if (event->param.conn.private_data_len) {\r
+ dapl_os_memcpy(new_conn->p_data,\r
+ event->param.conn.private_data,\r
+ event->param.conn.private_data_len);\r
+ new_conn->params.private_data = new_conn->p_data;\r
+ new_conn->params.private_data_len =\r
+ event->param.conn.private_data_len;\r
+ }\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM, " passive_cb: "\r
+ "REQ: SP %p PORT %d LID %d "\r
+ "NEW CONN %p ID %p pdata %p,%d\n",\r
+ new_conn->sp, ntohs(((struct sockaddr_in *)\r
+ &ipaddr->src_addr)->sin_port),\r
+ event->listen_id, new_conn, event->id,\r
+ event->param.conn.private_data,\r
+ event->param.conn.private_data_len);\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM, " passive_cb: "\r
+ "REQ: IP SRC %x PORT %d DST %x PORT %d "\r
+ "rr %d init %d\n", ntohl(((struct sockaddr_in *)\r
+ &ipaddr->src_addr)->\r
+ sin_addr.s_addr),\r
+ ntohs(((struct sockaddr_in *)\r
+ &ipaddr->src_addr)->sin_port),\r
+ ntohl(((struct sockaddr_in *)\r
+ &ipaddr->dst_addr)->sin_addr.s_addr),\r
+ ntohs(((struct sockaddr_in *)\r
+ &ipaddr->dst_addr)->sin_port),\r
+ new_conn->params.responder_resources,\r
+ new_conn->params.initiator_depth);\r
+ }\r
+ return new_conn;\r
+}\r
+\r
+static void dapli_cm_active_cb(struct dapl_cm_id *conn,\r
+ struct rdma_cm_event *event)\r
+{\r
+ DAPL_OS_LOCK *lock = &conn->lock;\r
+ ib_cm_events_t ib_cm_event;\r
+ const void *pdata = NULL;\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " active_cb: conn %p id %d event %d\n",\r
+ conn, conn->cm_id, event->event);\r
+\r
+ /* There is a chance that we can get events after\r
+ * the consumer calls disconnect in a pending state\r
+ * since the IB CM and uDAPL states are not shared.\r
+ * In some cases, IB CM could generate either a DCONN\r
+ * or CONN_ERR after the consumer returned from\r
+ * dapl_ep_disconnect with a DISCONNECTED event\r
+ * already queued. Check state here and bail to\r
+ * avoid any events after a disconnect.\r
+ */\r
+ if (DAPL_BAD_HANDLE(conn->ep, DAPL_MAGIC_EP))\r
+ return;\r
+\r
+ dapl_os_lock(&conn->ep->header.lock);\r
+ if (conn->ep->param.ep_state == DAT_EP_STATE_DISCONNECTED) {\r
+ dapl_os_unlock(&conn->ep->header.lock);\r
+ return;\r
+ }\r
+ if (event->event == RDMA_CM_EVENT_DISCONNECTED)\r
+ conn->ep->param.ep_state = DAT_EP_STATE_DISCONNECTED;\r
+\r
+ dapl_os_unlock(&conn->ep->header.lock);\r
+ dapl_os_lock(lock);\r
+\r
+ switch (event->event) {\r
+ case RDMA_CM_EVENT_UNREACHABLE:\r
+ case RDMA_CM_EVENT_CONNECT_ERROR:\r
+ dapl_log(DAPL_DBG_TYPE_WARN,\r
+ "dapl_cma_active: CONN_ERR event=0x%x"\r
+ " status=%d %s DST %s, %d\n",\r
+ event->event, event->status,\r
+ (event->status == -ETIMEDOUT) ? "TIMEOUT" : "",\r
+ inet_ntoa(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.dst_addr)->\r
+ sin_addr),\r
+ ntohs(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.dst_addr)->\r
+ sin_port));\r
+\r
+ /* per DAT SPEC provider always returns UNREACHABLE */\r
+ ib_cm_event = IB_CME_DESTINATION_UNREACHABLE;\r
+ break;\r
+ case RDMA_CM_EVENT_REJECTED:\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " dapli_cm_active_handler: REJECTED reason=%d\n",\r
+ event->status);\r
+\r
+ /* valid REJ from consumer will always contain private data */\r
+ if (event->status == 28 &&\r
+ event->param.conn.private_data_len) {\r
+ ib_cm_event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA;\r
+ pdata =\r
+ (unsigned char *)event->param.conn.\r
+ private_data +\r
+ sizeof(struct dapl_pdata_hdr);\r
+ } else {\r
+ ib_cm_event = IB_CME_DESTINATION_REJECT;\r
+ dapl_log(DAPL_DBG_TYPE_WARN,\r
+ "dapl_cma_active: non-consumer REJ,"\r
+ " reason=%d, DST %s, %d\n",\r
+ event->status,\r
+ inet_ntoa(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.\r
+ dst_addr)->sin_addr),\r
+ ntohs(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.\r
+ dst_addr)->sin_port));\r
+ }\r
+ break;\r
+ case RDMA_CM_EVENT_ESTABLISHED:\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " active_cb: cm_id %d PORT %d CONNECTED to %s!\n",\r
+ conn->cm_id, ntohs(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.\r
+ dst_addr)->sin_port),\r
+ inet_ntoa(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.dst_addr)->\r
+ sin_addr));\r
+\r
+ /* setup local and remote ports for ep query */\r
+ conn->ep->param.remote_port_qual =\r
+ PORT_TO_SID(rdma_get_dst_port(conn->cm_id));\r
+ conn->ep->param.local_port_qual =\r
+ PORT_TO_SID(rdma_get_src_port(conn->cm_id));\r
+\r
+ ib_cm_event = IB_CME_CONNECTED;\r
+ pdata = event->param.conn.private_data;\r
+ break;\r
+ case RDMA_CM_EVENT_DISCONNECTED:\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " active_cb: DISC EVENT - EP %p\n",conn->ep);\r
+ rdma_disconnect(conn->cm_id); /* required for DREP */\r
+ ib_cm_event = IB_CME_DISCONNECTED;\r
+ /* validate EP handle */\r
+ if (DAPL_BAD_HANDLE(conn->ep, DAPL_MAGIC_EP))\r
+ conn = NULL;\r
+ break;\r
+ default:\r
+ dapl_dbg_log(DAPL_DBG_TYPE_ERR,\r
+ " dapli_cm_active_cb_handler: Unexpected CM "\r
+ "event %d on ID 0x%p\n", event->event,\r
+ conn->cm_id);\r
+ conn = NULL;\r
+ break;\r
+ }\r
+\r
+ dapl_os_unlock(lock);\r
+ if (conn)\r
+ dapl_evd_connection_callback(conn, ib_cm_event, pdata, conn->ep);\r
+}\r
+\r
+static void dapli_cm_passive_cb(struct dapl_cm_id *conn,\r
+ struct rdma_cm_event *event)\r
+{\r
+ ib_cm_events_t ib_cm_event;\r
+ struct dapl_cm_id *conn_recv = conn;\r
+ const void *pdata = NULL;\r
+ \r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " passive_cb: conn %p id %d event %d\n",\r
+ conn, event->id, event->event);\r
+\r
+ dapl_os_lock(&conn->lock);\r
+\r
+ switch (event->event) {\r
+ case RDMA_CM_EVENT_CONNECT_REQUEST:\r
+ /* create new conn object with new conn_id from event */\r
+ conn_recv = dapli_req_recv(conn, event);\r
+ ib_cm_event = IB_CME_CONNECTION_REQUEST_PENDING;\r
+ pdata = event->param.conn.private_data;\r
+ break;\r
+ case RDMA_CM_EVENT_UNREACHABLE:\r
+ case RDMA_CM_EVENT_CONNECT_ERROR:\r
+ dapl_log(DAPL_DBG_TYPE_WARN,\r
+ "dapl_cm_passive: CONN_ERR event=0x%x status=%d %s,"\r
+ " DST %s,%d\n",\r
+ event->event, event->status,\r
+ (event->status == -ETIMEDOUT) ? "TIMEOUT" : "",\r
+ inet_ntoa(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.dst_addr)->\r
+ sin_addr), ntohs(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.\r
+ dst_addr)->sin_port));\r
+ ib_cm_event = IB_CME_DESTINATION_UNREACHABLE;\r
+ break;\r
+ case RDMA_CM_EVENT_REJECTED:\r
+ /* will alwasys be abnormal NON-consumer from active side */\r
+ dapl_log(DAPL_DBG_TYPE_WARN,\r
+ "dapl_cm_passive: non-consumer REJ, reason=%d,"\r
+ " DST %s, %d\n",\r
+ event->status,\r
+ inet_ntoa(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.dst_addr)->\r
+ sin_addr),\r
+ ntohs(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.dst_addr)->\r
+ sin_port));\r
+ ib_cm_event = IB_CME_DESTINATION_REJECT;\r
+ break;\r
+ case RDMA_CM_EVENT_ESTABLISHED:\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " passive_cb: cm_id %p PORT %d CONNECTED from 0x%x!\n",\r
+ conn->cm_id, ntohs(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.\r
+ src_addr)->sin_port),\r
+ ntohl(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.dst_addr)->\r
+ sin_addr.s_addr));\r
+ ib_cm_event = IB_CME_CONNECTED;\r
+ break;\r
+ case RDMA_CM_EVENT_DISCONNECTED:\r
+ rdma_disconnect(conn->cm_id); /* required for DREP */\r
+ ib_cm_event = IB_CME_DISCONNECTED;\r
+ /* validate SP handle context */\r
+ if (DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_PSP) &&\r
+ DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_RSP))\r
+ conn_recv = NULL;\r
+ break;\r
+ default:\r
+ dapl_dbg_log(DAPL_DBG_TYPE_ERR, " passive_cb: "\r
+ "Unexpected CM event %d on ID 0x%p\n",\r
+ event->event, conn->cm_id);\r
+ conn_recv = NULL;\r
+ break;\r
+ }\r
+\r
+ dapl_os_unlock(&conn->lock);\r
+ if (conn_recv)\r
+ dapls_cr_callback(conn_recv, ib_cm_event, pdata, conn_recv->sp);\r
+}\r
+\r
+/************************ DAPL provider entry points **********************/\r
+\r
+/*\r
+ * dapls_ib_connect\r
+ *\r
+ * Initiate a connection with the passive listener on another node\r
+ *\r
+ * Input:\r
+ * ep_handle,\r
+ * remote_ia_address,\r
+ * remote_conn_qual,\r
+ * prd_size size of private data and structure\r
+ * prd_prt pointer to private data structure\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * DAT_SUCCESS\r
+ * DAT_INSUFFICIENT_RESOURCES\r
+ * DAT_INVALID_PARAMETER\r
+ *\r
+ */\r
+DAT_RETURN dapls_ib_connect(IN DAT_EP_HANDLE ep_handle,\r
+ IN DAT_IA_ADDRESS_PTR r_addr,\r
+ IN DAT_CONN_QUAL r_qual,\r
+ IN DAT_COUNT p_size, IN void *p_data)\r
+{\r
+ struct dapl_ep *ep_ptr = ep_handle;\r
+ struct dapl_cm_id *conn = ep_ptr->cm_handle;\r
+ int ret;\r
+\r
+ /* Sanity check */\r
+ if (NULL == ep_ptr)\r
+ return DAT_SUCCESS;\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " connect: rSID 0x%llx rPort %d, pdata %p, ln %d\n",\r
+ r_qual, ntohs(SID_TO_PORT(r_qual)), p_data, p_size);\r
+\r
+ /* rdma conn and cm_id pre-bound; reference via ep_ptr->cm_handle */\r
+\r
+ /* Setup QP/CM parameters and private data in cm_id */\r
+ (void)dapl_os_memzero(&conn->params, sizeof(conn->params));\r
+ conn->params.responder_resources =\r
+ ep_ptr->param.ep_attr.max_rdma_read_in;\r
+ conn->params.initiator_depth = ep_ptr->param.ep_attr.max_rdma_read_out;\r
+ conn->params.flow_control = 1;\r
+ conn->params.rnr_retry_count = IB_RNR_RETRY_COUNT;\r
+ conn->params.retry_count = IB_RC_RETRY_COUNT;\r
+ if (p_size) {\r
+ dapl_os_memcpy(conn->p_data, p_data, p_size);\r
+ conn->params.private_data = conn->p_data;\r
+ conn->params.private_data_len = p_size;\r
+ }\r
+\r
+ /* copy in remote address, need a copy for retry attempts */\r
+ dapl_os_memcpy(&conn->r_addr, r_addr, sizeof(*r_addr));\r
+\r
+ /* Resolve remote address, src already bound during QP create */\r
+ ((struct sockaddr_in *)&conn->r_addr)->sin_port = SID_TO_PORT(r_qual);\r
+ ((struct sockaddr_in *)&conn->r_addr)->sin_family = AF_INET;\r
+\r
+ ret = rdma_resolve_addr(conn->cm_id, NULL,\r
+ (struct sockaddr *)&conn->r_addr,\r
+ conn->arp_timeout);\r
+ if (ret) {\r
+ dapl_log(DAPL_DBG_TYPE_ERR,\r
+ " dapl_cma_connect: rdma_resolve_addr ERR 0x%x %s\n",\r
+ ret, strerror(errno));\r
+ return dapl_convert_errno(errno, "ib_connect");\r
+ }\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " connect: resolve_addr: cm_id %p -> %s port %d\n",\r
+ conn->cm_id,\r
+ inet_ntoa(((struct sockaddr_in *)&conn->r_addr)->sin_addr),\r
+ ((struct sockaddr_in *)&conn->r_addr)->sin_port);\r
+\r
+ return DAT_SUCCESS;\r
+}\r
+\r
+/*\r
+ * dapls_ib_disconnect\r
+ *\r
+ * Disconnect an EP\r
+ *\r
+ * Input:\r
+ * ep_handle,\r
+ * disconnect_flags\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * DAT_SUCCESS\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_disconnect(IN DAPL_EP * ep_ptr, IN DAT_CLOSE_FLAGS close_flags)\r
+{\r
+ dp_ib_cm_handle_t conn = ep_ptr->cm_handle;\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " disconnect(ep %p, conn %p, id %d flags %x)\n",\r
+ ep_ptr, conn, (conn ? conn->cm_id : 0), close_flags);\r
+\r
+ if ((conn == IB_INVALID_HANDLE) || (conn->cm_id == NULL))\r
+ return DAT_SUCCESS;\r
+\r
+ /* no graceful half-pipe disconnect option */\r
+ rdma_disconnect(conn->cm_id);\r
+\r
+ /* \r
+ * DAT event notification occurs from the callback\r
+ * Note: will fire even if DREQ goes unanswered on timeout \r
+ */\r
+ return DAT_SUCCESS;\r
+}\r
+\r
+/*\r
+ * dapls_ib_disconnect_clean\r
+ *\r
+ * Clean up outstanding connection data. This routine is invoked\r
+ * after the final disconnect callback has occurred. Only on the\r
+ * ACTIVE side of a connection.\r
+ *\r
+ * Input:\r
+ * ep_ptr DAPL_EP\r
+ * active Indicates active side of connection\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * void\r
+ *\r
+ */\r
+void\r
+dapls_ib_disconnect_clean(IN DAPL_EP * ep_ptr,\r
+ IN DAT_BOOLEAN active,\r
+ IN const ib_cm_events_t ib_cm_event)\r
+{\r
+ /* nothing to do */\r
+ return;\r
+}\r
+\r
+/*\r
+ * dapl_ib_setup_conn_listener\r
+ *\r
+ * Have the CM set up a connection listener.\r
+ *\r
+ * Input:\r
+ * ibm_hca_handle HCA handle\r
+ * qp_handle QP handle\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * DAT_SUCCESS\r
+ * DAT_INSUFFICIENT_RESOURCES\r
+ * DAT_INTERNAL_ERROR\r
+ * DAT_CONN_QUAL_UNAVAILBLE\r
+ * DAT_CONN_QUAL_IN_USE\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_setup_conn_listener(IN DAPL_IA * ia_ptr,\r
+ IN DAT_UINT64 ServiceID, IN DAPL_SP * sp_ptr)\r
+{\r
+ DAT_RETURN dat_status = DAT_SUCCESS;\r
+ ib_cm_srvc_handle_t conn;\r
+ DAT_SOCK_ADDR6 addr; /* local binding address */\r
+\r
+ /* Allocate CM and initialize lock */\r
+ if ((conn = dapl_os_alloc(sizeof(*conn))) == NULL)\r
+ return DAT_INSUFFICIENT_RESOURCES;\r
+\r
+ dapl_os_memzero(conn, sizeof(*conn));\r
+ dapl_os_lock_init(&conn->lock);\r
+ conn->refs++;\r
+\r
+ /* create CM_ID, bind to local device, create QP */\r
+ if (rdma_create_id\r
+ (g_cm_events, &conn->cm_id, (void *)conn, RDMA_PS_TCP)) {\r
+ dapl_os_free(conn, sizeof(*conn));\r
+ return (dapl_convert_errno(errno, "setup_listener"));\r
+ }\r
+\r
+ /* open identifies the local device; per DAT specification */\r
+ /* Get family and address then set port to consumer's ServiceID */\r
+ dapl_os_memcpy(&addr, &ia_ptr->hca_ptr->hca_address, sizeof(addr));\r
+ ((struct sockaddr_in *)&addr)->sin_port = SID_TO_PORT(ServiceID);\r
+\r
+ if (rdma_bind_addr(conn->cm_id, (struct sockaddr *)&addr)) {\r
+ if ((errno == EBUSY) || (errno == EADDRINUSE) || \r
+ (errno == EADDRNOTAVAIL))\r
+ dat_status = DAT_CONN_QUAL_IN_USE;\r
+ else\r
+ dat_status =\r
+ dapl_convert_errno(errno, "setup_listener");\r
+ goto bail;\r
+ }\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " listen(ia_ptr %p SID 0x%llx Port %d sp %p conn %p id %d)\n",\r
+ ia_ptr, ServiceID, ntohs(SID_TO_PORT(ServiceID)),\r
+ sp_ptr, conn, conn->cm_id);\r
+\r
+ sp_ptr->cm_srvc_handle = conn;\r
+ conn->sp = sp_ptr;\r
+ conn->hca = ia_ptr->hca_ptr;\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
+ " listen(conn=%p cm_id=%d)\n",\r
+ sp_ptr->cm_srvc_handle, conn->cm_id);\r
+\r
+ if (rdma_listen(conn->cm_id, 0)) { /* max cma backlog */\r
+\r
+ if ((errno == EBUSY) || (errno == EADDRINUSE) ||\r
+ (errno == EADDRNOTAVAIL))\r
+ dat_status = DAT_CONN_QUAL_IN_USE;\r
+ else\r
+ dat_status =\r
+ dapl_convert_errno(errno, "setup_listener");\r
+ goto bail;\r
+ }\r
+\r
+ /* success */\r
+ return DAT_SUCCESS;\r
+\r
+ bail:\r
+ rdma_destroy_id(conn->cm_id);\r
+ dapl_os_free(conn, sizeof(*conn));\r
+ return dat_status;\r
+}\r
+\r
+/*\r
+ * dapl_ib_remove_conn_listener\r
+ *\r
+ * Have the CM remove a connection listener.\r
+ *\r
+ * Input:\r
+ * ia_handle IA handle\r
+ * ServiceID IB Channel Service ID\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * DAT_SUCCESS\r
+ * DAT_INVALID_STATE\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_remove_conn_listener(IN DAPL_IA * ia_ptr, IN DAPL_SP * sp_ptr)\r
+{\r
+ ib_cm_srvc_handle_t conn = sp_ptr->cm_srvc_handle;\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " remove_listen(ia_ptr %p sp_ptr %p cm_ptr %p)\n",\r
+ ia_ptr, sp_ptr, conn);\r
+\r
+ if (conn != IB_INVALID_HANDLE) {\r
+ sp_ptr->cm_srvc_handle = NULL;\r
+ dapls_ib_cm_free(conn, NULL);\r
+ }\r
+ return DAT_SUCCESS;\r
+}\r
+\r
+/*\r
+ * dapls_ib_accept_connection\r
+ *\r
+ * Perform necessary steps to accept a connection\r
+ *\r
+ * Input:\r
+ * cr_handle\r
+ * ep_handle\r
+ * private_data_size\r
+ * private_data\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * DAT_SUCCESS\r
+ * DAT_INSUFFICIENT_RESOURCES\r
+ * DAT_INTERNAL_ERROR\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_accept_connection(IN DAT_CR_HANDLE cr_handle,\r
+ IN DAT_EP_HANDLE ep_handle,\r
+ IN DAT_COUNT p_size, IN const DAT_PVOID p_data)\r
+{\r
+ DAPL_CR *cr_ptr = (DAPL_CR *) cr_handle;\r
+ DAPL_EP *ep_ptr = (DAPL_EP *) ep_handle;\r
+ DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;\r
+ struct dapl_cm_id *cr_conn = cr_ptr->ib_cm_handle;\r
+ int ret;\r
+ DAT_RETURN dat_status;\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " accept(cr %p conn %p, id %p, p_data %p, p_sz=%d)\n",\r
+ cr_ptr, cr_conn, cr_conn->cm_id, p_data, p_size);\r
+\r
+ /* Obtain size of private data structure & contents */\r
+ if (p_size > IB_MAX_REP_PDATA_SIZE) {\r
+ dat_status = DAT_ERROR(DAT_LENGTH_ERROR, DAT_NO_SUBTYPE);\r
+ goto bail;\r
+ }\r
+\r
+ if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {\r
+ /* \r
+ * If we are lazy attaching the QP then we may need to\r
+ * hook it up here. Typically, we run this code only for\r
+ * DAT_PSP_PROVIDER_FLAG\r
+ */\r
+ dat_status = dapls_ib_qp_alloc(ia_ptr, ep_ptr, NULL);\r
+ if (dat_status != DAT_SUCCESS) {\r
+ dapl_log(DAPL_DBG_TYPE_ERR,\r
+ " dapl_cma_accept: qp_alloc ERR %d\n",\r
+ dat_status);\r
+ goto bail;\r
+ }\r
+ }\r
+\r
+ /* \r
+ * Validate device and port in EP cm_id against inbound \r
+ * CR cm_id. The pre-allocated EP cm_id is already bound to \r
+ * a local device (cm_id and QP) when created. Move the QP\r
+ * to the new cm_id only if device and port numbers match.\r
+ */\r
+ if (ep_ptr->cm_handle->cm_id->verbs == cr_conn->cm_id->verbs &&\r
+ ep_ptr->cm_handle->cm_id->port_num == cr_conn->cm_id->port_num) {\r
+ /* move QP to new cr_conn, remove QP ref in EP cm_id */\r
+ cr_conn->cm_id->qp = ep_ptr->cm_handle->cm_id->qp;\r
+ ep_ptr->cm_handle->cm_id->qp = NULL;\r
+ dapls_ib_cm_free(ep_ptr->cm_handle, NULL);\r
+ } else {\r
+ dapl_log(DAPL_DBG_TYPE_ERR,\r
+ " dapl_cma_accept: ERR dev(%p!=%p) or"\r
+ " port mismatch(%d!=%d)\n",\r
+ ep_ptr->cm_handle->cm_id->verbs, cr_conn->cm_id->verbs,\r
+ ntohs(ep_ptr->cm_handle->cm_id->port_num),\r
+ ntohs(cr_conn->cm_id->port_num));\r
+ dat_status = DAT_INTERNAL_ERROR;\r
+ goto bail;\r
+ }\r
+\r
+ cr_ptr->param.local_ep_handle = ep_handle;\r
+ cr_conn->params.private_data = p_data;\r
+ cr_conn->params.private_data_len = p_size;\r
+\r
+ ret = rdma_accept(cr_conn->cm_id, &cr_conn->params);\r
+ if (ret) {\r
+ dapl_log(DAPL_DBG_TYPE_ERR, " dapl_cma_accept: ERR %d %s\n",\r
+ ret, strerror(errno));\r
+ dat_status = dapl_convert_errno(ret, "accept");\r
+ goto bail;\r
+ }\r
+\r
+ /* save accepted conn and EP reference, qp_handle unchanged */\r
+ ep_ptr->cm_handle = cr_conn;\r
+ cr_conn->ep = ep_ptr;\r
+\r
+ /* setup local and remote ports for ep query */\r
+ /* Note: port qual in network order */\r
+ ep_ptr->param.remote_port_qual =\r
+ PORT_TO_SID(rdma_get_dst_port(cr_conn->cm_id));\r
+ ep_ptr->param.local_port_qual =\r
+ PORT_TO_SID(rdma_get_src_port(cr_conn->cm_id));\r
+\r
+ return DAT_SUCCESS;\r
+ bail:\r
+ rdma_reject(cr_conn->cm_id, NULL, 0);\r
+ dapls_ib_cm_free(cr_conn, NULL);\r
+ return dat_status;\r
+}\r
+\r
+/*\r
+ * dapls_ib_reject_connection\r
+ *\r
+ * Reject a connection\r
+ *\r
+ * Input:\r
+ * cr_handle\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * DAT_SUCCESS\r
+ * DAT_INTERNAL_ERROR\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_reject_connection(IN dp_ib_cm_handle_t cm_handle,\r
+ IN int reason,\r
+ IN DAT_COUNT private_data_size,\r
+ IN const DAT_PVOID private_data)\r
+{\r
+ int ret;\r
+ int offset = sizeof(struct dapl_pdata_hdr);\r
+ struct dapl_pdata_hdr pdata_hdr;\r
+\r
+ memset(&pdata_hdr, 0, sizeof pdata_hdr);\r
+ pdata_hdr.version = htonl((DAT_VERSION_MAJOR << 24) |\r
+ (DAT_VERSION_MINOR << 16) |\r
+ (VN_PROVIDER_MAJOR << 8) |\r
+ (VN_PROVIDER_MINOR));\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " reject: handle %p reason %x, ver=%x, data %p, sz=%d\n",\r
+ cm_handle, reason, ntohl(pdata_hdr.version),\r
+ private_data, private_data_size);\r
+\r
+ if (cm_handle == IB_INVALID_HANDLE) {\r
+ dapl_dbg_log(DAPL_DBG_TYPE_ERR,\r
+ " reject: invalid handle: reason %d\n", reason);\r
+ return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR);\r
+ }\r
+\r
+ if (private_data_size >\r
+ dapls_ib_private_data_size(NULL, DAPL_PDATA_CONN_REJ,\r
+ cm_handle->hca))\r
+ return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);\r
+\r
+ /* setup pdata_hdr and users data, in CR pdata buffer */\r
+ dapl_os_memcpy(cm_handle->p_data, &pdata_hdr, offset);\r
+ if (private_data_size)\r
+ dapl_os_memcpy(cm_handle->p_data + offset,\r
+ private_data, private_data_size);\r
+\r
+ /*\r
+ * Always some private data with reject so active peer can\r
+ * determine real application reject from an abnormal \r
+ * application termination\r
+ */\r
+ ret = rdma_reject(cm_handle->cm_id,\r
+ cm_handle->p_data, offset + private_data_size);\r
+\r
+ dapls_ib_cm_free(cm_handle, NULL);\r
+ return dapl_convert_errno(ret, "reject");\r
+}\r
+\r
+/*\r
+ * dapls_ib_cm_remote_addr\r
+ *\r
+ * Obtain the remote IP address given a connection\r
+ *\r
+ * Input:\r
+ * cr_handle\r
+ *\r
+ * Output:\r
+ * remote_ia_address: where to place the remote address\r
+ *\r
+ * Returns:\r
+ * DAT_SUCCESS\r
+ * DAT_INVALID_HANDLE\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_cm_remote_addr(IN DAT_HANDLE dat_handle, OUT DAT_SOCK_ADDR6 * raddr)\r
+{\r
+ DAPL_HEADER *header;\r
+ dp_ib_cm_handle_t ib_cm_handle;\r
+ struct rdma_addr *ipaddr;\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
+ " remote_addr(cm_handle=%p, r_addr=%p)\n",\r
+ dat_handle, raddr);\r
+\r
+ header = (DAPL_HEADER *) dat_handle;\r
+\r
+ if (header->magic == DAPL_MAGIC_EP)\r
+ ib_cm_handle = ((DAPL_EP *) dat_handle)->cm_handle;\r
+ else if (header->magic == DAPL_MAGIC_CR)\r
+ ib_cm_handle = ((DAPL_CR *) dat_handle)->ib_cm_handle;\r
+ else\r
+ return DAT_INVALID_HANDLE;\r
+\r
+ /* get remote IP address from cm_id route */\r
+ ipaddr = &ib_cm_handle->cm_id->route.addr;\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " remote_addr: conn %p id %p SRC %x DST %x PORT %d\n",\r
+ ib_cm_handle, ib_cm_handle->cm_id,\r
+ ntohl(((struct sockaddr_in *)\r
+ &ipaddr->src_addr)->sin_addr.s_addr),\r
+ ntohl(((struct sockaddr_in *)\r
+ &ipaddr->dst_addr)->sin_addr.s_addr),\r
+ ntohs(((struct sockaddr_in *)\r
+ &ipaddr->dst_addr)->sin_port));\r
+\r
+ dapl_os_memcpy(raddr, &ipaddr->dst_addr, sizeof(DAT_SOCK_ADDR));\r
+ return DAT_SUCCESS;\r
+}\r
+\r
+/*\r
+ * dapls_ib_private_data_size\r
+ *\r
+ * Return the size of private data given a connection op type\r
+ *\r
+ * Input:\r
+ * prd_ptr private data pointer\r
+ * conn_op connection operation type\r
+ * hca_ptr hca pointer, needed for transport type\r
+ *\r
+ * If prd_ptr is NULL, this is a query for the max size supported by\r
+ * the provider, otherwise it is the actual size of the private data\r
+ * contained in prd_ptr.\r
+ *\r
+ *\r
+ * Output:\r
+ * None\r
+ *\r
+ * Returns:\r
+ * length of private data\r
+ *\r
+ */\r
+int dapls_ib_private_data_size(IN DAPL_PRIVATE * prd_ptr,\r
+ IN DAPL_PDATA_OP conn_op, IN DAPL_HCA * hca_ptr)\r
+{\r
+ int size;\r
+\r
+ if (hca_ptr->ib_hca_handle->device->transport_type\r
+ == IBV_TRANSPORT_IWARP)\r
+ return (IWARP_MAX_PDATA_SIZE - sizeof(struct dapl_pdata_hdr));\r
+\r
+ switch (conn_op) {\r
+\r
+ case DAPL_PDATA_CONN_REQ:\r
+ size = IB_MAX_REQ_PDATA_SIZE;\r
+ break;\r
+ case DAPL_PDATA_CONN_REP:\r
+ size = IB_MAX_REP_PDATA_SIZE;\r
+ break;\r
+ case DAPL_PDATA_CONN_REJ:\r
+ size = IB_MAX_REJ_PDATA_SIZE - sizeof(struct dapl_pdata_hdr);\r
+ break;\r
+ case DAPL_PDATA_CONN_DREQ:\r
+ size = IB_MAX_DREQ_PDATA_SIZE;\r
+ break;\r
+ case DAPL_PDATA_CONN_DREP:\r
+ size = IB_MAX_DREP_PDATA_SIZE;\r
+ break;\r
+ default:\r
+ size = 0;\r
+\r
+ } /* end case */\r
+\r
+ return size;\r
+}\r
+\r
+/*\r
+ * Map all CMA event codes to the DAT equivelent.\r
+ */\r
+#define DAPL_IB_EVENT_CNT 13\r
+\r
+static struct ib_cm_event_map {\r
+ const ib_cm_events_t ib_cm_event;\r
+ DAT_EVENT_NUMBER dat_event_num;\r
+} ib_cm_event_map[DAPL_IB_EVENT_CNT] = {\r
+ /* 00 */ {\r
+ IB_CME_CONNECTED, DAT_CONNECTION_EVENT_ESTABLISHED},\r
+ /* 01 */ {\r
+ IB_CME_DISCONNECTED, DAT_CONNECTION_EVENT_DISCONNECTED},\r
+ /* 02 */ {\r
+ IB_CME_DISCONNECTED_ON_LINK_DOWN,\r
+ DAT_CONNECTION_EVENT_DISCONNECTED},\r
+ /* 03 */ {\r
+ IB_CME_CONNECTION_REQUEST_PENDING, DAT_CONNECTION_REQUEST_EVENT},\r
+ /* 04 */ {\r
+ IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA,\r
+ DAT_CONNECTION_REQUEST_EVENT},\r
+ /* 05 */ {\r
+ IB_CME_CONNECTION_REQUEST_ACKED, DAT_CONNECTION_REQUEST_EVENT},\r
+ /* 06 */ {\r
+ IB_CME_DESTINATION_REJECT,\r
+ DAT_CONNECTION_EVENT_NON_PEER_REJECTED},\r
+ /* 07 */ {\r
+ IB_CME_DESTINATION_REJECT_PRIVATE_DATA,\r
+ DAT_CONNECTION_EVENT_PEER_REJECTED},\r
+ /* 08 */ {\r
+ IB_CME_DESTINATION_UNREACHABLE, DAT_CONNECTION_EVENT_UNREACHABLE},\r
+ /* 09 */ {\r
+ IB_CME_TOO_MANY_CONNECTION_REQUESTS,\r
+ DAT_CONNECTION_EVENT_NON_PEER_REJECTED},\r
+ /* 10 */ {\r
+ IB_CME_LOCAL_FAILURE, DAT_CONNECTION_EVENT_BROKEN},\r
+ /* 11 */ {\r
+ IB_CME_BROKEN, DAT_CONNECTION_EVENT_BROKEN},\r
+ /* 12 */ {\r
+IB_CME_TIMEOUT, DAT_CONNECTION_EVENT_TIMED_OUT},};\r
+\r
+/*\r
+ * dapls_ib_get_cm_event\r
+ *\r
+ * Return a DAT connection event given a provider CM event.\r
+ *\r
+ * Input:\r
+ * dat_event_num DAT event we need an equivelent CM event for\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * ib_cm_event of translated DAPL value\r
+ */\r
+DAT_EVENT_NUMBER\r
+dapls_ib_get_dat_event(IN const ib_cm_events_t ib_cm_event,\r
+ IN DAT_BOOLEAN active)\r
+{\r
+ DAT_EVENT_NUMBER dat_event_num;\r
+ int i;\r
+\r
+ active = active;\r
+\r
+ dat_event_num = 0;\r
+ for (i = 0; i < DAPL_IB_EVENT_CNT; i++) {\r
+ if (ib_cm_event == ib_cm_event_map[i].ib_cm_event) {\r
+ dat_event_num = ib_cm_event_map[i].dat_event_num;\r
+ break;\r
+ }\r
+ }\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,\r
+ "dapls_ib_get_dat_event: event(%s) ib=0x%x dat=0x%x\n",\r
+ active ? "active" : "passive", ib_cm_event, dat_event_num);\r
+\r
+ return dat_event_num;\r
+}\r
+\r
+/*\r
+ * dapls_ib_get_dat_event\r
+ *\r
+ * Return a DAT connection event given a provider CM event.\r
+ * \r
+ * Input:\r
+ * ib_cm_event event provided to the dapl callback routine\r
+ * active switch indicating active or passive connection\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * DAT_EVENT_NUMBER of translated provider value\r
+ */\r
+ib_cm_events_t dapls_ib_get_cm_event(IN DAT_EVENT_NUMBER dat_event_num)\r
+{\r
+ ib_cm_events_t ib_cm_event;\r
+ int i;\r
+\r
+ ib_cm_event = 0;\r
+ for (i = 0; i < DAPL_IB_EVENT_CNT; i++) {\r
+ if (dat_event_num == ib_cm_event_map[i].dat_event_num) {\r
+ ib_cm_event = ib_cm_event_map[i].ib_cm_event;\r
+ break;\r
+ }\r
+ }\r
+ return ib_cm_event;\r
+}\r
+\r
+void dapli_cma_event_cb(void)\r
+{\r
+ struct rdma_cm_event *event;\r
+ \r
+ /* process one CM event, fairness, non-blocking */\r
+ if (!rdma_get_cm_event(g_cm_events, &event)) {\r
+ struct dapl_cm_id *conn;\r
+\r
+ /* set proper conn from cm_id context */\r
+ if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST)\r
+ conn = (struct dapl_cm_id *)event->listen_id->context;\r
+ else\r
+ conn = (struct dapl_cm_id *)event->id->context;\r
+\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " cm_event: EVENT=%d ID=%p LID=%p CTX=%p\n",\r
+ event->event, event->id, event->listen_id, conn);\r
+ \r
+ /* cm_free is blocked waiting for ack */\r
+ dapl_os_lock(&conn->lock);\r
+ if (!conn->refs) {\r
+ dapl_os_unlock(&conn->lock);\r
+ rdma_ack_cm_event(event);\r
+ return;\r
+ }\r
+ conn->refs++;\r
+ dapl_os_unlock(&conn->lock);\r
+\r
+ switch (event->event) {\r
+ case RDMA_CM_EVENT_ADDR_RESOLVED:\r
+ dapli_addr_resolve(conn);\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:\r
+ dapli_route_resolve(conn);\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_ADDR_ERROR:\r
+ dapl_log(DAPL_DBG_TYPE_WARN,\r
+ "dapl_cma_active: CM ADDR ERROR: ->"\r
+ " DST %s retry (%d)..\n",\r
+ inet_ntoa(((struct sockaddr_in *)\r
+ &conn->r_addr)->sin_addr),\r
+ conn->arp_retries);\r
+\r
+ /* retry address resolution */\r
+ if ((--conn->arp_retries) &&\r
+ (event->status == -ETIMEDOUT)) {\r
+ int ret;\r
+ ret = rdma_resolve_addr(conn->cm_id, NULL,\r
+ (struct sockaddr *)\r
+ &conn->r_addr,\r
+ conn->arp_timeout);\r
+ if (!ret)\r
+ break;\r
+ else {\r
+ dapl_dbg_log(DAPL_DBG_TYPE_WARN,\r
+ " ERROR: rdma_resolve_addr = "\r
+ "%d %s\n",\r
+ ret, strerror(errno));\r
+ }\r
+ }\r
+ /* retries exhausted or resolve_addr failed */\r
+ dapl_log(DAPL_DBG_TYPE_ERR,\r
+ "dapl_cma_active: ARP_ERR, retries(%d)"\r
+ " exhausted -> DST %s,%d\n",\r
+ IB_ARP_RETRY_COUNT,\r
+ inet_ntoa(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.dst_addr)->\r
+ sin_addr),\r
+ ntohs(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.dst_addr)->\r
+ sin_port));\r
+\r
+ dapl_evd_connection_callback(conn,\r
+ IB_CME_DESTINATION_UNREACHABLE,\r
+ NULL, conn->ep);\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_ROUTE_ERROR:\r
+ dapl_log(DAPL_DBG_TYPE_WARN,\r
+ "dapl_cma_active: CM ROUTE ERROR: ->"\r
+ " DST %s retry (%d)..\n",\r
+ inet_ntoa(((struct sockaddr_in *)\r
+ &conn->r_addr)->sin_addr),\r
+ conn->route_retries);\r
+\r
+ /* retry route resolution */\r
+ if ((--conn->route_retries) &&\r
+ (event->status == -ETIMEDOUT))\r
+ dapli_addr_resolve(conn);\r
+ else {\r
+ dapl_log(DAPL_DBG_TYPE_ERR,\r
+ "dapl_cma_active: PATH_RECORD_ERR,"\r
+ " retries(%d) exhausted, DST %s,%d\n",\r
+ IB_ROUTE_RETRY_COUNT,\r
+ inet_ntoa(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.\r
+ dst_addr)->sin_addr),\r
+ ntohs(((struct sockaddr_in *)\r
+ &conn->cm_id->route.addr.\r
+ dst_addr)->sin_port));\r
+\r
+ dapl_evd_connection_callback(conn,\r
+ IB_CME_DESTINATION_UNREACHABLE,\r
+ NULL, conn->ep);\r
+ }\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:\r
+ dapl_evd_connection_callback(conn,\r
+ IB_CME_LOCAL_FAILURE,\r
+ NULL, conn->ep);\r
+ break;\r
+ case RDMA_CM_EVENT_CONNECT_REQUEST:\r
+ case RDMA_CM_EVENT_CONNECT_ERROR:\r
+ case RDMA_CM_EVENT_UNREACHABLE:\r
+ case RDMA_CM_EVENT_REJECTED:\r
+ case RDMA_CM_EVENT_ESTABLISHED:\r
+ case RDMA_CM_EVENT_DISCONNECTED:\r
+ /* passive or active */\r
+ if (conn->sp)\r
+ dapli_cm_passive_cb(conn, event);\r
+ else\r
+ dapli_cm_active_cb(conn, event);\r
+ break;\r
+ case RDMA_CM_EVENT_CONNECT_RESPONSE:\r
+#ifdef RDMA_CM_EVENT_TIMEWAIT_EXIT\r
+ case RDMA_CM_EVENT_TIMEWAIT_EXIT:\r
+#endif\r
+ break;\r
+ default:\r
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
+ " cm_event: UNEXPECTED EVENT=%p ID=%p CTX=%p\n",\r
+ event->event, event->id,\r
+ event->id->context);\r
+ break;\r
+ }\r
+ \r
+ /* ack event, unblocks destroy_cm_id in consumer threads */\r
+ rdma_ack_cm_event(event);\r
+\r
+ dapl_os_lock(&conn->lock);\r
+ conn->refs--;\r
+ dapl_os_unlock(&conn->lock);\r
+ } \r
+}\r
+\r
+/*\r
+ * Local variables:\r
+ * c-indent-level: 4\r
+ * c-basic-offset: 4\r
+ * tab-width: 8\r
+ * End:\r
+ */\r