#
# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved.
# Copyright (c) 2005 Voltaire Inc. All rights reserved.
-# Copyright (c) 2005 Intel Corporation. All rights reserved.
+# Copyright (c) 2005-2010 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
-# in the file LICENSE.txt in the root directory. The license is also
-# available from the Open Source Initiative, see
-# http://www.opensource.org/licenses/cpl.php.
+# in the file LICENSE.txt in the root directory.
#
# 2) under the terms of the "The BSD License" a copy of which is in the file
-# LICENSE2.txt in the root directory. The license is also available from
-# the Open Source Initiative, see
-# http://www.opensource.org/licenses/bsd-license.php.
+# LICENSE2.txt in the root directory.
#
# 3) under the terms of the "GNU General Public License (GPL) Version 2" a
-# copy of which is in the file LICENSE3.txt in the root directory. The
-# license is also available from the Open Source Initiative, see
-# http://www.opensource.org/licenses/gpl-license.php.
+# copy of which is in the file LICENSE3.txt in the root directory.
#
# Licensee has the right to choose one of the above licenses.
#
# notice, one of the license notices in the documentation
# and/or other materials provided with the distribution.
#
-
-
+commit 454c27b1f357c7c3070e459b25d12929f86304ca
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Mon Feb 22 09:42:17 2010 -0800
+
+ windows: add scm makefile
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 66ac48d5280bcf0453760c6e22909de6b8519b6d
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Mon Feb 22 09:41:13 2010 -0800
+
+ Windows does not require rdma_cma_abi.h, move the include from common code and to OSD file.
+
+ Signed-off-by: stan smith <stan.smith@intel.com>
+
+commit c05c41c31f01e1ddef91e92998ca66d258fafe3d
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Fri Feb 19 14:52:01 2010 -0800
+
+ Windows patch to fix IB_INVALID_HANDLE name collision
+
+ signed-off-by: stan smith <stan.smith@intel.com>
+
+commit 712e7e5ba71f8a4344dfff481a9be870eefefe25
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Mon Feb 8 13:49:35 2010 -0800
+
+ scm: dat_ep_connect fails on 32bit servers
+
+ memcpy for remote IA address uses incorrect sizeof for a pointer type.
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 3040fa78d7d22c8f76c88dc77cedde09f016eb67
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Fri Feb 5 11:51:16 2010 -0800
+
+ undefined symbol: dapls_print_cm_list
+
+ call prototype should be dependent on DAPL_COUNTERS.
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit cbeebe422b952d679f49429be8ba045a62d7f4ac
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Fri Feb 5 11:39:21 2010 -0800
+
+ Cleanup CM object lock before freeing CM object memory
+
+ Running windows application verifiier for uDAPL validation
+ for all 3 providers. Cleanup memory lock leaks found
+ by verifier.
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 855a8e4aa83fa2e4f7847122415106f49286f4ca
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Wed Feb 3 16:21:30 2010 -0800
+
+ destroy verbs completion channels created via ia_open or ep_create.
+
+ Completion channels are created with ia_open for CNO events and
+ with ep_create in cases where DAT allows EP(qp) to be created with
+ no EVD(cq) and IB doesn't. These completion channels need to be
+ destroyed at close along with a CQ for the EP without CQ case.
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 4da540591148e47dd912851cc7314776f2f7622e
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Wed Feb 3 11:06:45 2010 -0800
+
+ Update Copyright file and include the 3 license files in distribution
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 9011abd4b1470c65bfe81eef5a2f3a81060cec81
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Tue Feb 2 14:43:03 2010 -0800
+
+ When copying private_data out of rdma_cm events, use the
+ reported private_data_len for the size, and not IB maximums.
+ This fixes a bug running over the librdmacm on windows, where
+ DAPL accessed invalid memory.
+
+ Signed-off-by: Sean Hefty <sean.hefty@intel.com>
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 5da33bb3b9c230c08492f85d13caa330ce65906e
+Author: Sean Hefty <sean.hefty@intel.com>
+Date: Thu Jan 28 10:19:20 2010 -0800
+
+ dapl/cma: fix referencing freed address
+
+ DAPL uses a pointer to reference the local and remote addresses
+ of an endpoint. It expects that those addresses are located
+ in memory that is always accessible. Typically, for the local
+ address, the pointer references the address stored with the DAPL
+ HCA device. However, for the cma provider, it changes this pointer
+ to reference the address stored with the rdma_cm_id.
+
+ This causes a problem when that endpoint is connected on the
+ passive side of a connection. When connect requests are given
+ to DAPL, a new rdma_cm_id is associated with the request. The
+ DAPL code replaces the current rdma_cm_id associated with a
+ user's endpoint with the new rdma_cm_id. The old rdma_cm_id is
+ then deleted. But the endpoint's local address pointer still
+ references the address stored with the old rdma_cm_id. The
+ result is that any reference to the address will access freed
+ memory.
+
+ Fix this by keeping the local address pointer always pointing
+ to the address associated with the DAPL HCA device. This is about
+ the best that can be done given the DAPL interface design.
+
+ Signed-off-by: Sean Hefty <sean.hefty@intel.com>
+
+commit 66dbb5f20bf494eb3f5041655b478059165c5f1b
+Author: Sean Hefty <sean.hefty@intel.com>
+Date: Tue Jan 26 15:13:03 2010 -0800
+
+ dapl: move close device after async thread is done
+
+ using it
+
+ Before calling ibv_close_device, wait for the asynchronous
+ processing thread to finish using the device. This prevents
+ a use after free error.
+
+ Signed-off-by: Sean Hefty <sean.hefty@intel.com>
+
+commit 560b235adc799fa710571ca63cbc3e4fa6374ff2
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Mon Jan 11 09:03:10 2010 -0800
+
+ Release 2.0.26-1
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 73dfb32ace6aff2fdb21e54689342fd551822286
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Tue Dec 22 14:00:33 2009 -0800
+
+ openib_common: add check for both gid and global routing in RTR
+
+ check for valid gid pointer along with global route setting
+ during transition to RTR. Add more GID information to
+ debug print statement in qp modify call.
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 7aab18fd8ff3f201b0a4b6c76896667b29f103c4
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Fri Dec 4 12:31:22 2009 -0800
+
+ openib_common: remote memory read privilege set multi times
+
+ duplicate setting of read privilege in dapls_convert_privileges
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 016e2c40b8ac2fe18993e9fb7122ecb9b439e5eb
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Fri Dec 4 12:25:30 2009 -0800
+
+ ucm, scm: DAPL_GLOBAL_ROUTING enabled causes segv
+
+ socket cm and ud cm providers support QP modify with is_global
+ set and GRH. New v2 providers didn't pass GID information
+ in modify_qp RTR call and incorrectly byte swapped the already
+ network order GID. Add debug print of GID during global modify.
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 7b0c596c7b4ad619f65da9f79dcbc4376e651dde
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Tue Nov 24 22:16:58 2009 -0800
+
+ Release 2.0.25-1
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 3197bffff478ad7ff5eff9220fa0528e42e6b56e
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Tue Nov 24 22:15:46 2009 -0800
+
+ winof scm: initialize opt for NODELAY setsockopt
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
+commit 8559ec069329249592f367b5b8f61427cbad0a46
+Author: Arlin Davis <arlin.r.davis@intel.com>
+Date: Tue Nov 24 11:29:46 2009 -0800
+
+ Release 2.0.25
+
+ Signed-off-by: Arlin Davis <arlin.r.davis@intel.com>
+
commit 0983c66cbd9511128c1fa221470c4c983903e420
Author: Arlin Davis <arlin.r.davis@intel.com>
Date: Tue Nov 24 08:58:44 2009 -0800
dapl/udapl/libdaplofa.map \
dapl/udapl/libdaploscm.map \
dapl/udapl/libdaploucm.map \
+ LICENSE.txt \
+ LICENSE2.txt \
+ LICENSE3.txt \
dapl.spec.in \
$(man_MANS) \
test/dapltest/include/dapl_bpool.h \
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.57)
-AC_INIT(dapl, 2.0.25, linux-rdma@vger.kernel.org)
+AC_INIT(dapl, 2.0.27, linux-rdma@vger.kernel.org)
AC_CONFIG_SRCDIR([dat/udat/udat.c])
AC_CONFIG_AUX_DIR(config)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(dapl, 2.0.25)
+AM_INIT_AUTOMAKE(dapl, 2.0.27)
AM_PROG_LIBTOOL
%files
%defattr(-,root,root,-)
%{_libdir}/libda*.so.*
-%doc AUTHORS README ChangeLog
+%doc AUTHORS README COPYING ChangeLog LICENSE.txt LICENSE2.txt LICENSE3.txt
%files devel
%defattr(-,root,root,-)
%{_mandir}/man5/*.5*
%changelog
+* Tue Feb 23 2010 Arlin Davis <ardavis@ichips.intel.com> - 2.0.27
+- DAT/DAPL Version 2.0.27 Release 1, OFED 1.5.1
+
+* Tue Jan 11 2010 Arlin Davis <ardavis@ichips.intel.com> - 2.0.26
+- DAT/DAPL Version 2.0.26 Release 1, OFED 1.5, OFED 1.5-RDMAoE
+
* Tue Nov 24 2009 Arlin Davis <ardavis@ichips.intel.com> - 2.0.25
- DAT/DAPL Version 2.0.25 Release 1, OFED 1.5 RC3
-/*\r
- * Copyright (c) 2002-2005, Network Appliance, 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
- * in the file LICENSE.txt in the root directory. The license is also\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 in the file\r
- * LICENSE2.txt in the root directory. The license is also available from\r
- * 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 in the file LICENSE3.txt in the root directory. The \r
- * license is also 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
- * HEADER: dapl_adapter_util.h\r
- *\r
- * PURPOSE: Utility defs & routines for the adapter data structure\r
- *\r
- * $Id: dapl_adapter_util.h 1317 2005-04-25 17:29:42Z jlentini $\r
- *\r
- **********************************************************************/\r
-\r
-#ifndef _DAPL_ADAPTER_UTIL_H_\r
-#define _DAPL_ADAPTER_UTIL_H_\r
-\r
-\r
-typedef enum async_handler_type\r
-{\r
- DAPL_ASYNC_UNAFILIATED,\r
- DAPL_ASYNC_CQ_ERROR,\r
- DAPL_ASYNC_CQ_COMPLETION,\r
- DAPL_ASYNC_QP_ERROR\r
-} DAPL_ASYNC_HANDLER_TYPE;\r
-\r
-\r
-int dapls_ib_init (void);\r
-\r
-int dapls_ib_release (void);\r
-\r
-DAT_RETURN dapls_ib_enum_hcas (\r
- IN const char *vendor, \r
- OUT DAPL_HCA_NAME **hca_names,\r
- OUT DAT_COUNT *total_hca_count);\r
-\r
-DAT_RETURN dapls_ib_get_instance_data(\r
- IN DAPL_HCA_NAME hca_name, \r
- OUT char *instance);\r
-\r
-DAT_RETURN dapls_ib_open_hca (\r
- IN char *namestr,\r
- IN DAPL_HCA *hca_ptr);\r
-\r
-DAT_RETURN dapls_ib_close_hca (\r
- IN DAPL_HCA *hca_ptr);\r
-\r
-DAT_RETURN dapls_ib_qp_alloc (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_EP *ep_ptr,\r
- IN DAPL_EP *ep_ctx_ptr);\r
-\r
-DAT_RETURN dapls_ib_qp_free (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_EP *ep_ptr);\r
-\r
-DAT_RETURN dapls_ib_qp_modify (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_EP *ep_ptr,\r
- IN DAT_EP_ATTR *ep_attr);\r
-\r
-DAT_RETURN dapls_ib_connect (\r
- IN DAT_EP_HANDLE ep_handle,\r
- IN DAT_IA_ADDRESS_PTR remote_ia_address,\r
- IN DAT_CONN_QUAL remote_conn_qual,\r
- IN DAT_COUNT private_data_size,\r
- IN DAT_PVOID private_data);\r
-\r
-DAT_RETURN dapls_ib_disconnect (\r
- IN DAPL_EP *ep_ptr,\r
- IN DAT_CLOSE_FLAGS close_flags);\r
-\r
-DAT_RETURN dapls_ib_setup_conn_listener (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAT_UINT64 ServiceID,\r
- IN DAPL_SP *sp_ptr);\r
-\r
-DAT_RETURN dapls_ib_remove_conn_listener (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_SP *sp_ptr);\r
-\r
-DAT_RETURN dapls_ib_accept_connection (\r
- IN DAT_CR_HANDLE cr_handle,\r
- IN DAT_EP_HANDLE ep_handle,\r
- IN DAT_COUNT private_data_size,\r
- IN const DAT_PVOID private_data);\r
-\r
-DAT_RETURN dapls_ib_reject_connection (\r
- IN dp_ib_cm_handle_t cm_handle,\r
- IN int reject_reason,\r
- IN DAT_COUNT private_data_size,\r
- IN const DAT_PVOID private_data);\r
-\r
-DAT_RETURN dapls_ib_setup_async_callback (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_ASYNC_HANDLER_TYPE handler_type,\r
- IN DAPL_EVD *evd_ptr,\r
- IN ib_async_handler_t callback,\r
- IN void *context);\r
-\r
-DAT_RETURN dapls_ib_cq_alloc (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_EVD *evd_ptr,\r
- IN DAT_COUNT *cqlen);\r
-\r
-DAT_RETURN dapls_ib_cq_free (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_EVD *evd_ptr);\r
-\r
-DAT_RETURN dapls_set_cq_notify (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_EVD *evd_ptr);\r
-\r
-DAT_RETURN dapls_ib_cq_resize (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_EVD *evd_ptr,\r
- IN DAT_COUNT *cqlen);\r
-\r
-DAT_RETURN dapls_ib_pd_alloc (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_PZ *pz);\r
-\r
-DAT_RETURN dapls_ib_pd_free (\r
- IN DAPL_PZ *pz);\r
-\r
-DAT_RETURN dapls_ib_mr_register (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_LMR *lmr,\r
- IN DAT_PVOID virt_addr,\r
- IN DAT_VLEN length,\r
- IN DAT_MEM_PRIV_FLAGS privileges,\r
- IN DAT_VA_TYPE va_type);\r
-\r
-#if defined(__KDAPL__)\r
-DAT_RETURN dapls_ib_mr_register_physical (\r
- IN DAPL_IA *ia_ptr,\r
- INOUT DAPL_LMR *lmr,\r
- IN DAT_PADDR phys_addr,\r
- IN DAT_VLEN length,\r
- IN DAT_MEM_PRIV_FLAGS privileges);\r
-#endif /* __KDAPL__ */\r
-\r
-DAT_RETURN dapls_ib_mr_deregister (\r
- IN DAPL_LMR *lmr);\r
-\r
-DAT_RETURN dapls_ib_mr_register_shared (\r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_LMR *lmr,\r
- IN DAT_MEM_PRIV_FLAGS privileges,\r
- IN DAT_VA_TYPE va_type);\r
-\r
-DAT_RETURN dapls_ib_mw_alloc (\r
- IN DAPL_RMR *rmr);\r
-\r
-DAT_RETURN dapls_ib_mw_free (\r
- IN DAPL_RMR *rmr);\r
-\r
-DAT_RETURN dapls_ib_mw_bind (\r
- IN DAPL_RMR *rmr,\r
- IN DAPL_LMR *lmr,\r
- IN DAPL_EP *ep,\r
- IN DAPL_COOKIE *cookie,\r
- IN DAT_VADDR virtual_address,\r
- IN DAT_VLEN length,\r
- IN DAT_MEM_PRIV_FLAGS mem_priv,\r
- IN DAT_BOOLEAN is_signaled);\r
-\r
-DAT_RETURN dapls_ib_mw_unbind (\r
- IN DAPL_RMR *rmr,\r
- IN DAPL_EP *ep,\r
- IN DAPL_COOKIE *cookie,\r
- IN DAT_BOOLEAN is_signaled);\r
-\r
-DAT_RETURN dapls_ib_query_hca (\r
- IN DAPL_HCA *hca_ptr,\r
- OUT DAT_IA_ATTR *ia_attr,\r
- OUT DAT_EP_ATTR *ep_attr,\r
- OUT DAT_SOCK_ADDR6 *ip_addr);\r
-\r
-DAT_RETURN dapls_ib_completion_poll (\r
- IN DAPL_HCA *hca_ptr,\r
- IN DAPL_EVD *evd_ptr,\r
- IN ib_work_completion_t *cqe_ptr);\r
-\r
-DAT_RETURN dapls_ib_completion_notify (\r
- IN ib_hca_handle_t hca_handle,\r
- IN DAPL_EVD *evd_ptr,\r
- IN ib_notification_type_t type);\r
-\r
-DAT_DTO_COMPLETION_STATUS dapls_ib_get_dto_status (\r
- IN ib_work_completion_t *cqe_ptr);\r
-\r
-void dapls_ib_reinit_ep (\r
- IN DAPL_EP *ep_ptr);\r
-\r
-void dapls_ib_disconnect_clean (\r
- IN DAPL_EP *ep_ptr,\r
- IN DAT_BOOLEAN passive,\r
- IN const ib_cm_events_t ib_cm_event);\r
-\r
-DAT_RETURN dapls_ib_get_async_event (\r
- IN ib_error_record_t *cause_ptr,\r
- OUT DAT_EVENT_NUMBER *async_event);\r
-\r
-DAT_EVENT_NUMBER dapls_ib_get_dat_event (\r
- IN const ib_cm_events_t ib_cm_event,\r
- IN DAT_BOOLEAN active);\r
-\r
-ib_cm_events_t dapls_ib_get_cm_event (\r
- IN DAT_EVENT_NUMBER dat_event_num);\r
-\r
-DAT_RETURN dapls_ib_cm_remote_addr (\r
- IN DAT_HANDLE dat_handle,\r
- OUT DAT_SOCK_ADDR6 *remote_ia_address);\r
-\r
-int dapls_ib_private_data_size(\r
- IN DAPL_HCA *hca_ptr);\r
-\r
-void \r
-dapls_query_provider_specific_attr(\r
- IN DAPL_IA *ia_ptr,\r
- IN DAT_PROVIDER_ATTR *attr_ptr );\r
-\r
-DAT_RETURN\r
-dapls_evd_dto_wakeup (\r
- IN DAPL_EVD *evd_ptr);\r
-\r
-DAT_RETURN\r
-dapls_evd_dto_wait (\r
- IN DAPL_EVD *evd_ptr,\r
- IN uint32_t timeout);\r
-\r
-#ifdef DAT_EXTENSIONS\r
-void\r
-dapls_cqe_to_event_extension(\r
- IN DAPL_EP *ep_ptr,\r
- IN DAPL_COOKIE *cookie,\r
- IN ib_work_completion_t *cqe_ptr,\r
- IN DAT_EVENT *event_ptr);\r
-#endif\r
-\r
-/*\r
- * Values for provider DAT_NAMED_ATTR\r
- */\r
-#define IB_QP_STATE 1 /* QP state change request */\r
-\r
-\r
-#ifdef IBAPI\r
-#include "dapl_ibapi_dto.h"\r
-#elif VAPI\r
-#include "dapl_vapi_dto.h"\r
-#elif __OPENIB__\r
-#include "dapl_openib_dto.h"\r
-#elif DUMMY\r
-#include "dapl_dummy_dto.h"\r
-#elif OPENIB\r
-#include "dapl_ib_dto.h"\r
-#else\r
-#include "dapl_ibal_dto.h"\r
-#endif\r
-\r
-\r
-#endif /* _DAPL_ADAPTER_UTIL_H_ */\r
+/*
+ * Copyright (c) 2002-2005, Network Appliance, 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
+ * in the file LICENSE.txt in the root directory. The license is also
+ * 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 in the file
+ * LICENSE2.txt in the root directory. The license is also 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 in the file LICENSE3.txt in the root directory. The
+ * license is also 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.
+ */
+
+/**********************************************************************
+ *
+ * HEADER: dapl_adapter_util.h
+ *
+ * PURPOSE: Utility defs & routines for the adapter data structure
+ *
+ * $Id: dapl_adapter_util.h 1317 2005-04-25 17:29:42Z jlentini $
+ *
+ **********************************************************************/
+
+#ifndef _DAPL_ADAPTER_UTIL_H_
+#define _DAPL_ADAPTER_UTIL_H_
+
+
+typedef enum async_handler_type
+{
+ DAPL_ASYNC_UNAFILIATED,
+ DAPL_ASYNC_CQ_ERROR,
+ DAPL_ASYNC_CQ_COMPLETION,
+ DAPL_ASYNC_QP_ERROR
+} DAPL_ASYNC_HANDLER_TYPE;
+
+
+int dapls_ib_init (void);
+
+int dapls_ib_release (void);
+
+DAT_RETURN dapls_ib_enum_hcas (
+ IN const char *vendor,
+ OUT DAPL_HCA_NAME **hca_names,
+ OUT DAT_COUNT *total_hca_count);
+
+DAT_RETURN dapls_ib_get_instance_data(
+ IN DAPL_HCA_NAME hca_name,
+ OUT char *instance);
+
+DAT_RETURN dapls_ib_open_hca (
+ IN char *namestr,
+ IN DAPL_HCA *hca_ptr);
+
+DAT_RETURN dapls_ib_close_hca (
+ IN DAPL_HCA *hca_ptr);
+
+DAT_RETURN dapls_ib_qp_alloc (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_EP *ep_ptr,
+ IN DAPL_EP *ep_ctx_ptr);
+
+DAT_RETURN dapls_ib_qp_free (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_EP *ep_ptr);
+
+DAT_RETURN dapls_ib_qp_modify (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_EP *ep_ptr,
+ IN DAT_EP_ATTR *ep_attr);
+
+DAT_RETURN dapls_ib_connect (
+ IN DAT_EP_HANDLE ep_handle,
+ IN DAT_IA_ADDRESS_PTR remote_ia_address,
+ IN DAT_CONN_QUAL remote_conn_qual,
+ IN DAT_COUNT private_data_size,
+ IN DAT_PVOID private_data);
+
+DAT_RETURN dapls_ib_disconnect (
+ IN DAPL_EP *ep_ptr,
+ IN DAT_CLOSE_FLAGS close_flags);
+
+DAT_RETURN dapls_ib_setup_conn_listener (
+ IN DAPL_IA *ia_ptr,
+ IN DAT_UINT64 ServiceID,
+ IN DAPL_SP *sp_ptr);
+
+DAT_RETURN dapls_ib_remove_conn_listener (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_SP *sp_ptr);
+
+DAT_RETURN dapls_ib_accept_connection (
+ IN DAT_CR_HANDLE cr_handle,
+ IN DAT_EP_HANDLE ep_handle,
+ IN DAT_COUNT private_data_size,
+ IN const DAT_PVOID private_data);
+
+DAT_RETURN dapls_ib_reject_connection (
+ IN dp_ib_cm_handle_t cm_handle,
+ IN int reject_reason,
+ IN DAT_COUNT private_data_size,
+ IN const DAT_PVOID private_data);
+
+DAT_RETURN dapls_ib_setup_async_callback (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_ASYNC_HANDLER_TYPE handler_type,
+ IN DAPL_EVD *evd_ptr,
+ IN ib_async_handler_t callback,
+ IN void *context);
+
+DAT_RETURN dapls_ib_cq_alloc (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_EVD *evd_ptr,
+ IN DAT_COUNT *cqlen);
+
+DAT_RETURN dapls_ib_cq_free (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_EVD *evd_ptr);
+
+DAT_RETURN dapls_set_cq_notify (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_EVD *evd_ptr);
+
+DAT_RETURN dapls_ib_cq_resize (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_EVD *evd_ptr,
+ IN DAT_COUNT *cqlen);
+
+DAT_RETURN dapls_ib_pd_alloc (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_PZ *pz);
+
+DAT_RETURN dapls_ib_pd_free (
+ IN DAPL_PZ *pz);
+
+DAT_RETURN dapls_ib_mr_register (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_LMR *lmr,
+ IN DAT_PVOID virt_addr,
+ IN DAT_VLEN length,
+ IN DAT_MEM_PRIV_FLAGS privileges,
+ IN DAT_VA_TYPE va_type);
+
+#if defined(__KDAPL__)
+DAT_RETURN dapls_ib_mr_register_physical (
+ IN DAPL_IA *ia_ptr,
+ INOUT DAPL_LMR *lmr,
+ IN DAT_PADDR phys_addr,
+ IN DAT_VLEN length,
+ IN DAT_MEM_PRIV_FLAGS privileges);
+#endif /* __KDAPL__ */
+
+DAT_RETURN dapls_ib_mr_deregister (
+ IN DAPL_LMR *lmr);
+
+DAT_RETURN dapls_ib_mr_register_shared (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_LMR *lmr,
+ IN DAT_MEM_PRIV_FLAGS privileges,
+ IN DAT_VA_TYPE va_type);
+
+DAT_RETURN dapls_ib_mw_alloc (
+ IN DAPL_RMR *rmr);
+
+DAT_RETURN dapls_ib_mw_free (
+ IN DAPL_RMR *rmr);
+
+DAT_RETURN dapls_ib_mw_bind (
+ IN DAPL_RMR *rmr,
+ IN DAPL_LMR *lmr,
+ IN DAPL_EP *ep,
+ IN DAPL_COOKIE *cookie,
+ IN DAT_VADDR virtual_address,
+ IN DAT_VLEN length,
+ IN DAT_MEM_PRIV_FLAGS mem_priv,
+ IN DAT_BOOLEAN is_signaled);
+
+DAT_RETURN dapls_ib_mw_unbind (
+ IN DAPL_RMR *rmr,
+ IN DAPL_EP *ep,
+ IN DAPL_COOKIE *cookie,
+ IN DAT_BOOLEAN is_signaled);
+
+DAT_RETURN dapls_ib_query_hca (
+ IN DAPL_HCA *hca_ptr,
+ OUT DAT_IA_ATTR *ia_attr,
+ OUT DAT_EP_ATTR *ep_attr,
+ OUT DAT_SOCK_ADDR6 *ip_addr);
+
+DAT_RETURN dapls_ib_completion_poll (
+ IN DAPL_HCA *hca_ptr,
+ IN DAPL_EVD *evd_ptr,
+ IN ib_work_completion_t *cqe_ptr);
+
+DAT_RETURN dapls_ib_completion_notify (
+ IN ib_hca_handle_t hca_handle,
+ IN DAPL_EVD *evd_ptr,
+ IN ib_notification_type_t type);
+
+DAT_DTO_COMPLETION_STATUS dapls_ib_get_dto_status (
+ IN ib_work_completion_t *cqe_ptr);
+
+void dapls_ib_reinit_ep (
+ IN DAPL_EP *ep_ptr);
+
+void dapls_ib_disconnect_clean (
+ IN DAPL_EP *ep_ptr,
+ IN DAT_BOOLEAN passive,
+ IN const ib_cm_events_t ib_cm_event);
+
+DAT_RETURN dapls_ib_get_async_event (
+ IN ib_error_record_t *cause_ptr,
+ OUT DAT_EVENT_NUMBER *async_event);
+
+DAT_EVENT_NUMBER dapls_ib_get_dat_event (
+ IN const ib_cm_events_t ib_cm_event,
+ IN DAT_BOOLEAN active);
+
+ib_cm_events_t dapls_ib_get_cm_event (
+ IN DAT_EVENT_NUMBER dat_event_num);
+
+DAT_RETURN dapls_ib_cm_remote_addr (
+ IN DAT_HANDLE dat_handle,
+ OUT DAT_SOCK_ADDR6 *remote_ia_address);
+
+int dapls_ib_private_data_size(
+ IN DAPL_HCA *hca_ptr);
+
+void
+dapls_query_provider_specific_attr(
+ IN DAPL_IA *ia_ptr,
+ IN DAT_PROVIDER_ATTR *attr_ptr );
+
+DAT_RETURN
+dapls_evd_dto_wakeup (
+ IN DAPL_EVD *evd_ptr);
+
+DAT_RETURN
+dapls_evd_dto_wait (
+ IN DAPL_EVD *evd_ptr,
+ IN uint32_t timeout);
+
+#ifdef DAT_EXTENSIONS
+void
+dapls_cqe_to_event_extension(
+ IN DAPL_EP *ep_ptr,
+ IN DAPL_COOKIE *cookie,
+ IN ib_work_completion_t *cqe_ptr,
+ IN DAT_EVENT *event_ptr);
+#endif
+
+/*
+ * Values for provider DAT_NAMED_ATTR
+ */
+#define IB_QP_STATE 1 /* QP state change request */
+
+
+#ifdef IBAPI
+#include "dapl_ibapi_dto.h"
+#elif VAPI
+#include "dapl_vapi_dto.h"
+#elif __OPENIB__
+#include "dapl_openib_dto.h"
+#elif DUMMY
+#include "dapl_dummy_dto.h"
+#elif OPENIB
+#include "dapl_ib_dto.h"
+#else
+#include "dapl_ibal_dto.h"
+#endif
+
+
+#endif /* _DAPL_ADAPTER_UTIL_H_ */
-/*\r
- * Copyright (c) 2002-2003, Network Appliance, 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: dapls_cr_callback.c\r
- *\r
- * PURPOSE: implements passive side connection callbacks\r
- *\r
- * Description: Accepts asynchronous callbacks from the Communications Manager\r
- * for EVDs that have been specified as the connection_evd.\r
- *\r
- * $Id:$\r
- **********************************************************************/\r
-\r
-#include "dapl.h"\r
-#include "dapl_evd_util.h"\r
-#include "dapl_cr_util.h"\r
-#include "dapl_ia_util.h"\r
-#include "dapl_sp_util.h"\r
-#include "dapl_ep_util.h"\r
-#include "dapl_adapter_util.h"\r
-\r
-/*\r
- * Prototypes\r
- */\r
-DAT_RETURN dapli_connection_request(IN dp_ib_cm_handle_t ib_cm_handle,\r
- IN DAPL_SP * sp_ptr,\r
- IN DAPL_PRIVATE * prd_ptr,\r
- IN int private_data_size,\r
- IN DAPL_EVD * evd_ptr);\r
-\r
-DAPL_EP *dapli_get_sp_ep(IN dp_ib_cm_handle_t ib_cm_handle,\r
- IN DAPL_SP * sp_ptr,\r
- IN DAT_EVENT_NUMBER dat_event_num);\r
-\r
-/*\r
- * dapls_cr_callback\r
- *\r
- * The callback function registered with verbs for passive side of\r
- * connection requests. The interface is specified by cm_api.h\r
- *\r
- *\r
- * Input:\r
- * ib_cm_handle, Handle to CM\r
- * ib_cm_event Specific CM event\r
- * instant_data Private data with DAT ADDRESS header\r
- * context SP pointer\r
- *\r
- * Output:\r
- * None\r
- *\r
- */\r
-void dapls_cr_callback(IN dp_ib_cm_handle_t ib_cm_handle, IN const ib_cm_events_t ib_cm_event,\r
- IN const void *private_data_ptr, IN const int private_data_size,\r
- IN const void *context)\r
-{\r
- DAPL_EP *ep_ptr;\r
- DAPL_EVD *evd_ptr;\r
- DAPL_SP *sp_ptr;\r
- DAPL_PRIVATE *prd_ptr;\r
- DAT_EVENT_NUMBER dat_event_num;\r
- DAT_RETURN dat_status;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,\r
- "--> dapl_cr_callback! context: %p event: %x cm_handle %p\n",\r
- context, ib_cm_event, (void *)ib_cm_handle);\r
-\r
- /*\r
- * Passive side of the connection, context is a SP and\r
- * we need to look up the EP.\r
- */\r
- sp_ptr = (DAPL_SP *) context;\r
- /*\r
- * The context pointer could have been cleaned up in a racing\r
- * CM callback, check to see if we should just exit here\r
- */\r
- if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) {\r
- return;\r
- }\r
- dapl_os_assert(sp_ptr->header.magic == DAPL_MAGIC_PSP ||\r
- sp_ptr->header.magic == DAPL_MAGIC_RSP);\r
-\r
- /* Obtain the event number from the provider layer */\r
- dat_event_num = dapls_ib_get_dat_event(ib_cm_event, DAT_FALSE);\r
-\r
- /*\r
- * CONNECT_REQUEST events create an event on the PSP\r
- * EVD, which will trigger connection processing. The\r
- * sequence is:\r
- * CONNECT_REQUEST Event to SP\r
- * CONNECTED Event to EP\r
- * DISCONNECT Event to EP\r
- *\r
- * Obtain the EP if required and set an event up on the correct\r
- * EVD.\r
- */\r
- if (dat_event_num == DAT_CONNECTION_REQUEST_EVENT) {\r
- ep_ptr = NULL;\r
- evd_ptr = sp_ptr->evd_handle;\r
- } else {\r
- /* see if there is an EP connected with this CM handle */\r
- ep_ptr = dapli_get_sp_ep(ib_cm_handle, sp_ptr, dat_event_num);\r
-\r
- /* if we lost a race with the CM just exit. */\r
- if (ep_ptr == NULL) {\r
- return;\r
- }\r
-\r
- evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle;\r
- /* if something has happened to our EVD, bail. */\r
- if (evd_ptr == NULL) {\r
- return;\r
- }\r
- }\r
-\r
- prd_ptr = (DAPL_PRIVATE *) private_data_ptr;\r
-\r
- dat_status = DAT_INTERNAL_ERROR; /* init to ERR */\r
-\r
- switch (dat_event_num) {\r
- case DAT_CONNECTION_REQUEST_EVENT:\r
- {\r
- /*\r
- * Requests arriving on a disabled SP are immediatly rejected\r
- */\r
-\r
- dapl_os_lock(&sp_ptr->header.lock);\r
- if (sp_ptr->listening == DAT_FALSE) {\r
- dapl_os_unlock(&sp_ptr->header.lock);\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- "---> dapls_cr_callback: conn event on down SP\n");\r
- (void)dapls_ib_reject_connection(ib_cm_handle,\r
- DAT_CONNECTION_EVENT_UNREACHABLE,\r
- 0, NULL);\r
-\r
- return;\r
- }\r
-\r
- if (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_RSP) {\r
- /*\r
- * RSP connections only allow a single connection. Close\r
- * it down NOW so we reject any further connections.\r
- */\r
- sp_ptr->listening = DAT_FALSE;\r
- }\r
- dapl_os_unlock(&sp_ptr->header.lock);\r
-\r
- /*\r
- * Only occurs on the passive side of a connection\r
- * dapli_connection_request will post the connection\r
- * event if appropriate.\r
- */\r
- dat_status = dapli_connection_request(ib_cm_handle,\r
- sp_ptr, prd_ptr, private_data_size, evd_ptr);\r
- /* Set evd_ptr = NULL so we don't generate an event below */\r
- evd_ptr = NULL;\r
-\r
- break;\r
- }\r
- case DAT_CONNECTION_EVENT_ESTABLISHED:\r
- {\r
- /* This is just a notification the connection is now\r
- * established, there isn't any private data to deal with.\r
- *\r
- * Update the EP state and cache a copy of the cm handle,\r
- * then let the user know we are ready to go.\r
- */\r
- dapl_os_lock(&ep_ptr->header.lock);\r
- if (ep_ptr->header.magic != DAPL_MAGIC_EP ||\r
- ep_ptr->param.ep_state !=\r
- DAT_EP_STATE_COMPLETION_PENDING) {\r
- /* If someone pulled the plug on the EP or connection,\r
- * just exit\r
- */\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- dat_status = DAT_SUCCESS;\r
- /* Set evd_ptr = NULL so we don't generate an event below */\r
- evd_ptr = NULL;\r
-\r
- break;\r
- }\r
-\r
- ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED;\r
- ep_ptr->cm_handle = ib_cm_handle;\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
-\r
- break;\r
- }\r
- case DAT_CONNECTION_EVENT_DISCONNECTED:\r
- {\r
- /*\r
- * EP is now fully disconnected; initiate any post processing\r
- * to reset the underlying QP and get the EP ready for\r
- * another connection\r
- */\r
- dapl_os_lock(&ep_ptr->header.lock);\r
- if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) {\r
- /* The disconnect has already occurred, we are now\r
- * cleaned up and ready to exit\r
- */\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- return;\r
- }\r
- ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;\r
- dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE,\r
- ib_cm_event);\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
-\r
- break;\r
- }\r
- case DAT_CONNECTION_EVENT_NON_PEER_REJECTED:\r
- case DAT_CONNECTION_EVENT_PEER_REJECTED:\r
- case DAT_CONNECTION_EVENT_UNREACHABLE:\r
- {\r
- /*\r
- * After posting an accept the requesting node has\r
- * stopped talking.\r
- */\r
- dapl_os_lock(&ep_ptr->header.lock);\r
- ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;\r
- ep_ptr->cm_handle = IB_INVALID_HANDLE;\r
- dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE,\r
- ib_cm_event);\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
-\r
- break;\r
- }\r
- case DAT_CONNECTION_EVENT_BROKEN:\r
- {\r
- dapl_os_lock(&ep_ptr->header.lock);\r
- ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;\r
- dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE,\r
- ib_cm_event);\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
-\r
- break;\r
- }\r
- default:\r
- {\r
- evd_ptr = NULL;\r
- dapl_os_assert(0); /* shouldn't happen */\r
- break;\r
- }\r
- }\r
-\r
- if (evd_ptr != NULL) {\r
- dat_status = dapls_evd_post_connection_event(evd_ptr,\r
- dat_event_num,\r
- (DAT_HANDLE)\r
- ep_ptr, 0, NULL);\r
- }\r
-\r
- if (dat_status != DAT_SUCCESS) {\r
- /* The event post failed; take appropriate action. */\r
- (void)dapls_ib_reject_connection(ib_cm_handle,\r
- DAT_CONNECTION_EVENT_BROKEN,\r
- 0, NULL);\r
-\r
- return;\r
- }\r
-}\r
-\r
-/*\r
- * dapli_connection_request\r
- *\r
- * Process a connection request on the Passive side of a connection.\r
- * Create a CR record and link it on to the SP so we can update it\r
- * and free it later. Create an EP if specified by the PSP flags.\r
- *\r
- * Input:\r
- * ib_cm_handle,\r
- * sp_ptr\r
- * event_ptr\r
- * prd_ptr\r
- *\r
- * Output:\r
- * None\r
- *\r
- * Returns\r
- * DAT_INSUFFICIENT_RESOURCES\r
- * DAT_SUCCESS\r
- *\r
- */\r
-DAT_RETURN\r
-dapli_connection_request(IN dp_ib_cm_handle_t ib_cm_handle,\r
- IN DAPL_SP * sp_ptr,\r
- IN DAPL_PRIVATE * prd_ptr, IN int private_data_size,\r
- IN DAPL_EVD * evd_ptr)\r
-{\r
- DAT_RETURN dat_status;\r
-\r
- DAPL_CR *cr_ptr;\r
- DAPL_EP *ep_ptr;\r
- DAPL_IA *ia_ptr;\r
- DAT_SP_HANDLE sp_handle;\r
-\r
- cr_ptr = dapls_cr_alloc(sp_ptr->header.owner_ia);\r
- if (cr_ptr == NULL) {\r
- /* Invoking function will call dapls_ib_cm_reject() */\r
- return DAT_INSUFFICIENT_RESOURCES;\r
- }\r
-\r
- /*\r
- * Set up the CR\r
- */\r
- cr_ptr->sp_ptr = sp_ptr; /* maintain sp_ptr in case of reject */\r
- cr_ptr->param.remote_port_qual = 0;\r
- cr_ptr->ib_cm_handle = ib_cm_handle;\r
-#ifdef IBHOSTS_NAMING\r
- /*\r
- * Special case: pull the remote HCA address from the private data\r
- * prefix. This is a spec violation as it introduces a protocol, but\r
- * some implementations may find it necessary for a time.\r
- */\r
- cr_ptr->remote_ia_address = prd_ptr->hca_address;\r
-#endif /* IBHOSTS_NAMING */\r
- cr_ptr->param.remote_ia_address_ptr =\r
- (DAT_IA_ADDRESS_PTR) & cr_ptr->remote_ia_address;\r
- /*\r
- * Copy the remote address and private data out of the private_data\r
- * payload and put them in a local structure\r
- */\r
-\r
- /* Private data size will be determined by the provider layer */\r
- cr_ptr->param.private_data = cr_ptr->private_data;\r
- cr_ptr->param.private_data_size = private_data_size;\r
- if (cr_ptr->param.private_data_size > 0) {\r
- dapl_os_memcpy(cr_ptr->private_data,\r
- prd_ptr->private_data,\r
- DAPL_MIN(cr_ptr->param.private_data_size,\r
- DAPL_MAX_PRIVATE_DATA_SIZE));\r
- }\r
-\r
- /* EP will be NULL unless RSP service point */\r
- ep_ptr = (DAPL_EP *) sp_ptr->ep_handle;\r
-\r
- if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) {\r
- /*\r
- * Never true for RSP connections\r
- *\r
- * Create an EP for the user. If we can't allocate an\r
- * EP we are out of resources and need to tell the\r
- * requestor that we cant help them.\r
- */\r
- ia_ptr = sp_ptr->header.owner_ia;\r
- ep_ptr = dapl_ep_alloc(ia_ptr, NULL);\r
- if (ep_ptr == NULL) {\r
- dapls_cr_free(cr_ptr);\r
- /* Invoking function will call dapls_ib_cm_reject() */\r
- return DAT_INSUFFICIENT_RESOURCES;\r
- }\r
- ep_ptr->param.ia_handle = ia_ptr;\r
- ep_ptr->param.local_ia_address_ptr =\r
- (DAT_IA_ADDRESS_PTR) & ia_ptr->hca_ptr->hca_address;\r
-\r
- /* Link the EP onto the IA */\r
- dapl_ia_link_ep(ia_ptr, ep_ptr);\r
- }\r
-\r
- cr_ptr->param.local_ep_handle = ep_ptr;\r
-\r
- if (ep_ptr != NULL) {\r
- /* Assign valid EP fields: RSP and PSP_PROVIDER_FLAG only */\r
- if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) {\r
- ep_ptr->param.ep_state =\r
- DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING;\r
- } else {\r
- /* RSP */\r
- dapl_os_assert(sp_ptr->header.handle_type ==\r
- DAT_HANDLE_TYPE_RSP);\r
- ep_ptr->param.ep_state =\r
- DAT_EP_STATE_PASSIVE_CONNECTION_PENDING;\r
- }\r
- ep_ptr->cm_handle = ib_cm_handle;\r
- }\r
-\r
- /* link the CR onto the SP so we can pick it up later */\r
- dapl_sp_link_cr(sp_ptr, cr_ptr);\r
-\r
- /* Post the event. */\r
- /* assign sp_ptr to union to avoid typecast errors from some compilers */\r
- sp_handle.psp_handle = (DAT_PSP_HANDLE) sp_ptr;\r
-\r
- dat_status = dapls_evd_post_cr_arrival_event(evd_ptr,\r
- DAT_CONNECTION_REQUEST_EVENT,\r
- sp_handle,\r
- (DAT_IA_ADDRESS_PTR)\r
- & sp_ptr->header.owner_ia->\r
- hca_ptr->hca_address,\r
- sp_ptr->conn_qual,\r
- (DAT_CR_HANDLE) cr_ptr);\r
-\r
- if (dat_status != DAT_SUCCESS) {\r
- dapls_cr_free(cr_ptr);\r
- (void)dapls_ib_reject_connection(ib_cm_handle,\r
- DAT_CONNECTION_EVENT_BROKEN,\r
- 0, NULL);\r
-\r
- /* Take the CR off the list, we can't use it */\r
- dapl_os_lock(&sp_ptr->header.lock);\r
- dapl_sp_remove_cr(sp_ptr, cr_ptr);\r
- dapl_os_unlock(&sp_ptr->header.lock);\r
- return DAT_INSUFFICIENT_RESOURCES;\r
- }\r
-\r
- return DAT_SUCCESS;\r
-}\r
-\r
-/*\r
- * dapli_get_sp_ep\r
- *\r
- * Passive side of a connection is now fully established. Clean\r
- * up resources and obtain the EP pointer associated with a CR in\r
- * the SP\r
- *\r
- * Input:\r
- * ib_cm_handle,\r
- * sp_ptr\r
- * connection_event\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Returns\r
- * ep_ptr\r
- *\r
- */\r
-DAPL_EP *dapli_get_sp_ep(IN dp_ib_cm_handle_t ib_cm_handle,\r
- IN DAPL_SP * sp_ptr, IN DAT_EVENT_NUMBER dat_event_num)\r
-{\r
- DAPL_CR *cr_ptr;\r
- DAPL_EP *ep_ptr;\r
-\r
- /*\r
- * acquire the lock, we may be racing with other threads here\r
- */\r
- dapl_os_lock(&sp_ptr->header.lock);\r
-\r
- /* Verify under lock that the SP is still valid */\r
- if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) {\r
- dapl_os_unlock(&sp_ptr->header.lock);\r
- return NULL;\r
- }\r
- /*\r
- * There are potentially multiple connections in progress. Need to\r
- * go through the list and find the one we are interested\r
- * in. There is no guarantee of order. dapl_sp_search_cr\r
- * leaves the CR on the SP queue.\r
- */\r
- cr_ptr = dapl_sp_search_cr(sp_ptr, ib_cm_handle);\r
- if (cr_ptr == NULL) {\r
- dapl_os_unlock(&sp_ptr->header.lock);\r
- return NULL;\r
- }\r
-\r
- ep_ptr = (DAPL_EP *) cr_ptr->param.local_ep_handle;\r
-\r
- /* Quick check to ensure our EP is still valid */\r
- if ((DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP))) {\r
- ep_ptr = NULL;\r
- }\r
-\r
- /* The CR record is discarded in all except for the CONNECTED case,\r
- * as it will have no further relevance.\r
- */\r
- if (dat_event_num != DAT_CONNECTION_EVENT_ESTABLISHED) {\r
- /* Remove the CR from the queue */\r
- dapl_sp_remove_cr(sp_ptr, cr_ptr);\r
-\r
- if (ep_ptr != NULL) {\r
- ep_ptr->cr_ptr = NULL;\r
- }\r
-\r
- /*\r
- * If this SP has been removed from service, free it\r
- * up after the last CR is removed\r
- */\r
- if (sp_ptr->listening != DAT_TRUE && sp_ptr->cr_list_count == 0\r
- && sp_ptr->state != DAPL_SP_STATE_FREE) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- "--> dapli_get_sp_ep! disconnect dump sp: %p \n",\r
- sp_ptr);\r
- /* Decrement the ref count on the EVD */\r
- if (sp_ptr->evd_handle) {\r
- dapl_os_atomic_dec(&\r
- ((DAPL_EVD *) sp_ptr->\r
- evd_handle)->evd_ref_count);\r
- sp_ptr->evd_handle = NULL;\r
- }\r
- sp_ptr->state = DAPL_SP_STATE_FREE;\r
- dapl_os_unlock(&sp_ptr->header.lock);\r
- (void)dapls_ib_remove_conn_listener(sp_ptr->header.\r
- owner_ia, sp_ptr);\r
- dapls_ia_unlink_sp((DAPL_IA *) sp_ptr->header.owner_ia,\r
- sp_ptr);\r
- dapls_sp_free_sp(sp_ptr);\r
- dapls_cr_free(cr_ptr);\r
- goto skip_unlock;\r
- }\r
-\r
- dapl_os_unlock(&sp_ptr->header.lock);\r
- /* free memory outside of the lock */\r
- dapls_cr_free(cr_ptr);\r
- } else {\r
- dapl_os_unlock(&sp_ptr->header.lock);\r
- }\r
-\r
- skip_unlock:\r
- return ep_ptr;\r
-}\r
-\r
-/*\r
- * Local variables:\r
- * c-indent-level: 4\r
- * c-basic-offset: 4\r
- * c-brace-offset: -4\r
- * tab-width: 8\r
- * End:\r
- */\r
+/*
+ * Copyright (c) 2002-2003, Network Appliance, 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: dapls_cr_callback.c
+ *
+ * PURPOSE: implements passive side connection callbacks
+ *
+ * Description: Accepts asynchronous callbacks from the Communications Manager
+ * for EVDs that have been specified as the connection_evd.
+ *
+ * $Id:$
+ **********************************************************************/
+
+#include "dapl.h"
+#include "dapl_evd_util.h"
+#include "dapl_cr_util.h"
+#include "dapl_ia_util.h"
+#include "dapl_sp_util.h"
+#include "dapl_ep_util.h"
+#include "dapl_adapter_util.h"
+
+/*
+ * Prototypes
+ */
+DAT_RETURN dapli_connection_request(IN dp_ib_cm_handle_t ib_cm_handle,
+ IN DAPL_SP * sp_ptr,
+ IN DAPL_PRIVATE * prd_ptr,
+ IN int private_data_size,
+ IN DAPL_EVD * evd_ptr);
+
+DAPL_EP *dapli_get_sp_ep(IN dp_ib_cm_handle_t ib_cm_handle,
+ IN DAPL_SP * sp_ptr,
+ IN DAT_EVENT_NUMBER dat_event_num);
+
+/*
+ * dapls_cr_callback
+ *
+ * The callback function registered with verbs for passive side of
+ * connection requests. The interface is specified by cm_api.h
+ *
+ *
+ * Input:
+ * ib_cm_handle, Handle to CM
+ * ib_cm_event Specific CM event
+ * instant_data Private data with DAT ADDRESS header
+ * context SP pointer
+ *
+ * Output:
+ * None
+ *
+ */
+void dapls_cr_callback(IN dp_ib_cm_handle_t ib_cm_handle, IN const ib_cm_events_t ib_cm_event,
+ IN const void *private_data_ptr, IN const int private_data_size,
+ IN const void *context)
+{
+ DAPL_EP *ep_ptr;
+ DAPL_EVD *evd_ptr;
+ DAPL_SP *sp_ptr;
+ DAPL_PRIVATE *prd_ptr;
+ DAT_EVENT_NUMBER dat_event_num;
+ DAT_RETURN dat_status;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,
+ "--> dapl_cr_callback! context: %p event: %x cm_handle %p\n",
+ context, ib_cm_event, (void *)ib_cm_handle);
+
+ /*
+ * Passive side of the connection, context is a SP and
+ * we need to look up the EP.
+ */
+ sp_ptr = (DAPL_SP *) context;
+ /*
+ * The context pointer could have been cleaned up in a racing
+ * CM callback, check to see if we should just exit here
+ */
+ if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) {
+ return;
+ }
+ dapl_os_assert(sp_ptr->header.magic == DAPL_MAGIC_PSP ||
+ sp_ptr->header.magic == DAPL_MAGIC_RSP);
+
+ /* Obtain the event number from the provider layer */
+ dat_event_num = dapls_ib_get_dat_event(ib_cm_event, DAT_FALSE);
+
+ /*
+ * CONNECT_REQUEST events create an event on the PSP
+ * EVD, which will trigger connection processing. The
+ * sequence is:
+ * CONNECT_REQUEST Event to SP
+ * CONNECTED Event to EP
+ * DISCONNECT Event to EP
+ *
+ * Obtain the EP if required and set an event up on the correct
+ * EVD.
+ */
+ if (dat_event_num == DAT_CONNECTION_REQUEST_EVENT) {
+ ep_ptr = NULL;
+ evd_ptr = sp_ptr->evd_handle;
+ } else {
+ /* see if there is an EP connected with this CM handle */
+ ep_ptr = dapli_get_sp_ep(ib_cm_handle, sp_ptr, dat_event_num);
+
+ /* if we lost a race with the CM just exit. */
+ if (ep_ptr == NULL) {
+ return;
+ }
+
+ evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle;
+ /* if something has happened to our EVD, bail. */
+ if (evd_ptr == NULL) {
+ return;
+ }
+ }
+
+ prd_ptr = (DAPL_PRIVATE *) private_data_ptr;
+
+ dat_status = DAT_INTERNAL_ERROR; /* init to ERR */
+
+ switch (dat_event_num) {
+ case DAT_CONNECTION_REQUEST_EVENT:
+ {
+ /*
+ * Requests arriving on a disabled SP are immediatly rejected
+ */
+
+ dapl_os_lock(&sp_ptr->header.lock);
+ if (sp_ptr->listening == DAT_FALSE) {
+ dapl_os_unlock(&sp_ptr->header.lock);
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ "---> dapls_cr_callback: conn event on down SP\n");
+ (void)dapls_ib_reject_connection(ib_cm_handle,
+ DAT_CONNECTION_EVENT_UNREACHABLE,
+ 0, NULL);
+
+ return;
+ }
+
+ if (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_RSP) {
+ /*
+ * RSP connections only allow a single connection. Close
+ * it down NOW so we reject any further connections.
+ */
+ sp_ptr->listening = DAT_FALSE;
+ }
+ dapl_os_unlock(&sp_ptr->header.lock);
+
+ /*
+ * Only occurs on the passive side of a connection
+ * dapli_connection_request will post the connection
+ * event if appropriate.
+ */
+ dat_status = dapli_connection_request(ib_cm_handle,
+ sp_ptr, prd_ptr, private_data_size, evd_ptr);
+ /* Set evd_ptr = NULL so we don't generate an event below */
+ evd_ptr = NULL;
+
+ break;
+ }
+ case DAT_CONNECTION_EVENT_ESTABLISHED:
+ {
+ /* This is just a notification the connection is now
+ * established, there isn't any private data to deal with.
+ *
+ * Update the EP state and cache a copy of the cm handle,
+ * then let the user know we are ready to go.
+ */
+ dapl_os_lock(&ep_ptr->header.lock);
+ if (ep_ptr->header.magic != DAPL_MAGIC_EP ||
+ ep_ptr->param.ep_state !=
+ DAT_EP_STATE_COMPLETION_PENDING) {
+ /* If someone pulled the plug on the EP or connection,
+ * just exit
+ */
+ dapl_os_unlock(&ep_ptr->header.lock);
+ dat_status = DAT_SUCCESS;
+ /* Set evd_ptr = NULL so we don't generate an event below */
+ evd_ptr = NULL;
+
+ break;
+ }
+
+ ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED;
+ dapl_os_unlock(&ep_ptr->header.lock);
+
+ break;
+ }
+ case DAT_CONNECTION_EVENT_DISCONNECTED:
+ {
+ /*
+ * EP is now fully disconnected; initiate any post processing
+ * to reset the underlying QP and get the EP ready for
+ * another connection
+ */
+ dapl_os_lock(&ep_ptr->header.lock);
+ if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) {
+ /* The disconnect has already occurred, we are now
+ * cleaned up and ready to exit
+ */
+ dapl_os_unlock(&ep_ptr->header.lock);
+ return;
+ }
+ ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
+ dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE,
+ ib_cm_event);
+ dapl_os_unlock(&ep_ptr->header.lock);
+
+ break;
+ }
+ case DAT_CONNECTION_EVENT_NON_PEER_REJECTED:
+ case DAT_CONNECTION_EVENT_PEER_REJECTED:
+ case DAT_CONNECTION_EVENT_UNREACHABLE:
+ {
+ /*
+ * After posting an accept the requesting node has
+ * stopped talking.
+ */
+ dapl_os_lock(&ep_ptr->header.lock);
+ ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
+ dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE,
+ ib_cm_event);
+ dapl_os_unlock(&ep_ptr->header.lock);
+
+ break;
+ }
+ case DAT_CONNECTION_EVENT_BROKEN:
+ {
+ dapl_os_lock(&ep_ptr->header.lock);
+ ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
+ dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE,
+ ib_cm_event);
+ dapl_os_unlock(&ep_ptr->header.lock);
+
+ break;
+ }
+ default:
+ {
+ evd_ptr = NULL;
+ dapl_os_assert(0); /* shouldn't happen */
+ break;
+ }
+ }
+
+ if (evd_ptr != NULL) {
+ dat_status = dapls_evd_post_connection_event(evd_ptr,
+ dat_event_num,
+ (DAT_HANDLE)
+ ep_ptr, 0, NULL);
+ }
+
+ if (dat_status != DAT_SUCCESS) {
+ /* The event post failed; take appropriate action. */
+ (void)dapls_ib_reject_connection(ib_cm_handle,
+ DAT_CONNECTION_EVENT_BROKEN,
+ 0, NULL);
+
+ return;
+ }
+}
+
+/*
+ * dapli_connection_request
+ *
+ * Process a connection request on the Passive side of a connection.
+ * Create a CR record and link it on to the SP so we can update it
+ * and free it later. Create an EP if specified by the PSP flags.
+ *
+ * Input:
+ * ib_cm_handle,
+ * sp_ptr
+ * event_ptr
+ * prd_ptr
+ *
+ * Output:
+ * None
+ *
+ * Returns
+ * DAT_INSUFFICIENT_RESOURCES
+ * DAT_SUCCESS
+ *
+ */
+DAT_RETURN
+dapli_connection_request(IN dp_ib_cm_handle_t ib_cm_handle,
+ IN DAPL_SP * sp_ptr,
+ IN DAPL_PRIVATE * prd_ptr, IN int private_data_size,
+ IN DAPL_EVD * evd_ptr)
+{
+ DAT_RETURN dat_status;
+
+ DAPL_CR *cr_ptr;
+ DAPL_EP *ep_ptr;
+ DAPL_IA *ia_ptr;
+ DAT_SP_HANDLE sp_handle;
+
+ cr_ptr = dapls_cr_alloc(sp_ptr->header.owner_ia);
+ if (cr_ptr == NULL) {
+ /* Invoking function will call dapls_ib_cm_reject() */
+ return DAT_INSUFFICIENT_RESOURCES;
+ }
+
+ /*
+ * Set up the CR
+ */
+ cr_ptr->sp_ptr = sp_ptr; /* maintain sp_ptr in case of reject */
+ cr_ptr->param.remote_port_qual = 0;
+ cr_ptr->ib_cm_handle = ib_cm_handle;
+#ifdef IBHOSTS_NAMING
+ /*
+ * Special case: pull the remote HCA address from the private data
+ * prefix. This is a spec violation as it introduces a protocol, but
+ * some implementations may find it necessary for a time.
+ */
+ cr_ptr->remote_ia_address = prd_ptr->hca_address;
+#endif /* IBHOSTS_NAMING */
+ cr_ptr->param.remote_ia_address_ptr =
+ (DAT_IA_ADDRESS_PTR) & cr_ptr->remote_ia_address;
+ /*
+ * Copy the remote address and private data out of the private_data
+ * payload and put them in a local structure
+ */
+
+ /* Private data size will be determined by the provider layer */
+ cr_ptr->param.private_data = cr_ptr->private_data;
+ cr_ptr->param.private_data_size = private_data_size;
+ if (cr_ptr->param.private_data_size > 0) {
+ dapl_os_memcpy(cr_ptr->private_data,
+ prd_ptr->private_data,
+ DAPL_MIN(cr_ptr->param.private_data_size,
+ DAPL_MAX_PRIVATE_DATA_SIZE));
+ }
+
+ /* EP will be NULL unless RSP service point */
+ ep_ptr = (DAPL_EP *) sp_ptr->ep_handle;
+
+ if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) {
+ /*
+ * Never true for RSP connections
+ *
+ * Create an EP for the user. If we can't allocate an
+ * EP we are out of resources and need to tell the
+ * requestor that we cant help them.
+ */
+ ia_ptr = sp_ptr->header.owner_ia;
+ ep_ptr = dapl_ep_alloc(ia_ptr, NULL);
+ if (ep_ptr == NULL) {
+ dapls_cr_free(cr_ptr);
+ /* Invoking function will call dapls_ib_cm_reject() */
+ return DAT_INSUFFICIENT_RESOURCES;
+ }
+ ep_ptr->param.ia_handle = ia_ptr;
+ ep_ptr->param.local_ia_address_ptr =
+ (DAT_IA_ADDRESS_PTR) & ia_ptr->hca_ptr->hca_address;
+
+ /* Link the EP onto the IA */
+ dapl_ia_link_ep(ia_ptr, ep_ptr);
+ }
+
+ cr_ptr->param.local_ep_handle = ep_ptr;
+
+ if (ep_ptr != NULL) {
+ /* Assign valid EP fields: RSP and PSP_PROVIDER_FLAG only */
+ if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) {
+ ep_ptr->param.ep_state =
+ DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING;
+ } else {
+ /* RSP */
+ dapl_os_assert(sp_ptr->header.handle_type ==
+ DAT_HANDLE_TYPE_RSP);
+ ep_ptr->param.ep_state =
+ DAT_EP_STATE_PASSIVE_CONNECTION_PENDING;
+ }
+ dapl_ep_link_cm(ep_ptr, ib_cm_handle);
+ }
+
+ /* link the CR onto the SP so we can pick it up later */
+ dapl_sp_link_cr(sp_ptr, cr_ptr);
+
+ /* Post the event. */
+ /* assign sp_ptr to union to avoid typecast errors from some compilers */
+ sp_handle.psp_handle = (DAT_PSP_HANDLE) sp_ptr;
+
+ dat_status = dapls_evd_post_cr_arrival_event(evd_ptr,
+ DAT_CONNECTION_REQUEST_EVENT,
+ sp_handle,
+ (DAT_IA_ADDRESS_PTR)
+ & sp_ptr->header.owner_ia->
+ hca_ptr->hca_address,
+ sp_ptr->conn_qual,
+ (DAT_CR_HANDLE) cr_ptr);
+
+ if (dat_status != DAT_SUCCESS) {
+ dapls_cr_free(cr_ptr);
+ (void)dapls_ib_reject_connection(ib_cm_handle,
+ DAT_CONNECTION_EVENT_BROKEN,
+ 0, NULL);
+
+ /* Take the CR off the list, we can't use it */
+ dapl_os_lock(&sp_ptr->header.lock);
+ dapl_sp_remove_cr(sp_ptr, cr_ptr);
+ dapl_os_unlock(&sp_ptr->header.lock);
+ return DAT_INSUFFICIENT_RESOURCES;
+ }
+
+ return DAT_SUCCESS;
+}
+
+/*
+ * dapli_get_sp_ep
+ *
+ * Passive side of a connection is now fully established. Clean
+ * up resources and obtain the EP pointer associated with a CR in
+ * the SP
+ *
+ * Input:
+ * ib_cm_handle,
+ * sp_ptr
+ * connection_event
+ *
+ * Output:
+ * none
+ *
+ * Returns
+ * ep_ptr
+ *
+ */
+DAPL_EP *dapli_get_sp_ep(IN dp_ib_cm_handle_t ib_cm_handle,
+ IN DAPL_SP * sp_ptr, IN DAT_EVENT_NUMBER dat_event_num)
+{
+ DAPL_CR *cr_ptr;
+ DAPL_EP *ep_ptr;
+
+ /*
+ * acquire the lock, we may be racing with other threads here
+ */
+ dapl_os_lock(&sp_ptr->header.lock);
+
+ /* Verify under lock that the SP is still valid */
+ if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) {
+ dapl_os_unlock(&sp_ptr->header.lock);
+ return NULL;
+ }
+ /*
+ * There are potentially multiple connections in progress. Need to
+ * go through the list and find the one we are interested
+ * in. There is no guarantee of order. dapl_sp_search_cr
+ * leaves the CR on the SP queue.
+ */
+ cr_ptr = dapl_sp_search_cr(sp_ptr, ib_cm_handle);
+ if (cr_ptr == NULL) {
+ dapl_os_unlock(&sp_ptr->header.lock);
+ return NULL;
+ }
+
+ ep_ptr = (DAPL_EP *) cr_ptr->param.local_ep_handle;
+
+ /* Quick check to ensure our EP is still valid */
+ if ((DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP))) {
+ ep_ptr = NULL;
+ }
+
+ /* The CR record is discarded in all except for the CONNECTED case,
+ * as it will have no further relevance.
+ */
+ if (dat_event_num != DAT_CONNECTION_EVENT_ESTABLISHED) {
+ /* Remove the CR from the queue */
+ dapl_sp_remove_cr(sp_ptr, cr_ptr);
+
+ if (ep_ptr != NULL) {
+ ep_ptr->cr_ptr = NULL;
+ }
+
+ /*
+ * If this SP has been removed from service, free it
+ * up after the last CR is removed
+ */
+ if (sp_ptr->listening != DAT_TRUE && sp_ptr->cr_list_count == 0
+ && sp_ptr->state != DAPL_SP_STATE_FREE) {
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ "--> dapli_get_sp_ep! disconnect dump sp: %p \n",
+ sp_ptr);
+ /* Decrement the ref count on the EVD */
+ if (sp_ptr->evd_handle) {
+ dapl_os_atomic_dec(&
+ ((DAPL_EVD *) sp_ptr->
+ evd_handle)->evd_ref_count);
+ sp_ptr->evd_handle = NULL;
+ }
+ sp_ptr->state = DAPL_SP_STATE_FREE;
+ dapl_os_unlock(&sp_ptr->header.lock);
+ (void)dapls_ib_remove_conn_listener(sp_ptr->header.
+ owner_ia, sp_ptr);
+ dapls_ia_unlink_sp((DAPL_IA *) sp_ptr->header.owner_ia,
+ sp_ptr);
+ dapls_sp_free_sp(sp_ptr);
+ dapls_cr_free(cr_ptr);
+ goto skip_unlock;
+ }
+
+ dapl_os_unlock(&sp_ptr->header.lock);
+ /* free memory outside of the lock */
+ dapls_cr_free(cr_ptr);
+ } else {
+ dapl_os_unlock(&sp_ptr->header.lock);
+ }
+
+ skip_unlock:
+ return ep_ptr;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * c-brace-offset: -4
+ * tab-width: 8
+ * End:
+ */
-/*
- * Copyright (c) 2002-2003, Network Appliance, 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_cr_util.c
- *
- * PURPOSE: Manage CR (Connection Request) structure
- *
- * $Id:$
- **********************************************************************/
-
-#include "dapl.h"
-#include "dapl_cr_util.h"
-
-/*
- * dapls_cr_create
- *
- * Create a CR. Part of the passive side of a connection
- *
- * Input:
- * ia_ptr
- *
- * Returns:
- * DAPL_CR
- *
- */
-
-DAPL_CR *dapls_cr_alloc(DAPL_IA * ia_ptr)
-{
- DAPL_CR *cr_ptr;
-
- /* Allocate EP */
- cr_ptr = (DAPL_CR *) dapl_os_alloc(sizeof(DAPL_CR));
- if (cr_ptr == NULL) {
- return (NULL);
- }
-
- /* zero the structure */
- dapl_os_memzero(cr_ptr, sizeof(DAPL_CR));
-
- /*
- * initialize the header
- */
- cr_ptr->header.provider = ia_ptr->header.provider;
- cr_ptr->header.magic = DAPL_MAGIC_CR;
- cr_ptr->header.handle_type = DAT_HANDLE_TYPE_CR;
- cr_ptr->header.owner_ia = ia_ptr;
- cr_ptr->header.user_context.as_64 = 0;
- cr_ptr->header.user_context.as_ptr = NULL;
- dapl_llist_init_entry(&cr_ptr->header.ia_list_entry);
- dapl_os_lock_init(&cr_ptr->header.lock);
-
- return (cr_ptr);
-}
-
-/*
- * dapls_cr_free
- *
- * Free the passed in EP structure.
- *
- * Input:
- * entry point pointer
- *
- * Output:
- * none
- *
- * Returns:
- * none
- *
- */
-void dapls_cr_free(IN DAPL_CR * cr_ptr)
-{
- dapl_os_assert(cr_ptr->header.magic == DAPL_MAGIC_CR ||
- cr_ptr->header.magic == DAPL_MAGIC_CR_DESTROYED);
-
- cr_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */
- dapl_os_free(cr_ptr, sizeof(DAPL_CR));
-}
+/*\r
+ * Copyright (c) 2002-2003, Network Appliance, 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_cr_util.c\r
+ *\r
+ * PURPOSE: Manage CR (Connection Request) structure\r
+ *\r
+ * $Id:$\r
+ **********************************************************************/\r
+\r
+#include "dapl.h"\r
+#include "dapl_cr_util.h"\r
+\r
+/*\r
+ * dapls_cr_create\r
+ *\r
+ * Create a CR. Part of the passive side of a connection\r
+ *\r
+ * Input:\r
+ * ia_ptr\r
+ *\r
+ * Returns:\r
+ * DAPL_CR\r
+ *\r
+ */\r
+\r
+DAPL_CR *dapls_cr_alloc(DAPL_IA * ia_ptr)\r
+{\r
+ DAPL_CR *cr_ptr;\r
+\r
+ /* Allocate EP */\r
+ cr_ptr = (DAPL_CR *) dapl_os_alloc(sizeof(DAPL_CR));\r
+ if (cr_ptr == NULL) {\r
+ return (NULL);\r
+ }\r
+\r
+ /* zero the structure */\r
+ dapl_os_memzero(cr_ptr, sizeof(DAPL_CR));\r
+\r
+ /*\r
+ * initialize the header\r
+ */\r
+ cr_ptr->header.provider = ia_ptr->header.provider;\r
+ cr_ptr->header.magic = DAPL_MAGIC_CR;\r
+ cr_ptr->header.handle_type = DAT_HANDLE_TYPE_CR;\r
+ cr_ptr->header.owner_ia = ia_ptr;\r
+ cr_ptr->header.user_context.as_64 = 0;\r
+ cr_ptr->header.user_context.as_ptr = NULL;\r
+ dapl_llist_init_entry(&cr_ptr->header.ia_list_entry);\r
+ dapl_os_lock_init(&cr_ptr->header.lock);\r
+\r
+ return (cr_ptr);\r
+}\r
+\r
+/*\r
+ * dapls_cr_free\r
+ *\r
+ * Free the passed in CR structure.\r
+ *\r
+ * Input:\r
+ * entry point pointer\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * none\r
+ *\r
+ */\r
+void dapls_cr_free(IN DAPL_CR * cr_ptr)\r
+{\r
+ dapl_os_assert(cr_ptr->header.magic == DAPL_MAGIC_CR ||\r
+ cr_ptr->header.magic == DAPL_MAGIC_CR_DESTROYED);\r
+\r
+ cr_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */\r
+ dapl_os_free(cr_ptr, sizeof(DAPL_CR));\r
+}\r
-/*\r
- * Copyright (c) 2002-2003, Network Appliance, 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
- * HEADER: dapl_cr_util.h\r
- *\r
- * PURPOSE: Utility defs & routines for the CR data structure\r
- *\r
- * $Id:$\r
- *\r
- **********************************************************************/\r
-\r
-#ifndef _DAPL_CR_UTIL_H_\r
-#define _DAPL_CR_UTIL_H_\r
-\r
-#include "dapl.h" \r
-\r
-DAPL_CR *\r
-dapls_cr_alloc (\r
- DAPL_IA *ia_ptr );\r
-\r
-void\r
-dapls_cr_free (\r
- IN DAPL_CR *cr_ptr );\r
-\r
-void\r
-dapls_cr_callback (\r
- IN dp_ib_cm_handle_t ib_cm_handle,\r
- IN const ib_cm_events_t ib_cm_event,\r
- IN const void *private_data_ptr,\r
- IN const int private_data_size,\r
- IN const void *context);\r
-\r
-#endif /* _DAPL_CR_UTIL_H_ */\r
+/*
+ * Copyright (c) 2002-2003, Network Appliance, 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.
+ */
+
+/**********************************************************************
+ *
+ * HEADER: dapl_cr_util.h
+ *
+ * PURPOSE: Utility defs & routines for the CR data structure
+ *
+ * $Id:$
+ *
+ **********************************************************************/
+
+#ifndef _DAPL_CR_UTIL_H_
+#define _DAPL_CR_UTIL_H_
+
+#include "dapl.h"
+
+DAPL_CR *
+dapls_cr_alloc (
+ DAPL_IA *ia_ptr );
+
+void
+dapls_cr_free (
+ IN DAPL_CR *cr_ptr );
+
+void
+dapls_cr_callback (
+ IN dp_ib_cm_handle_t ib_cm_handle,
+ IN const ib_cm_events_t ib_cm_event,
+ IN const void *private_data_ptr,
+ IN const int private_data_size,
+ IN const void *context);
+
+#endif /* _DAPL_CR_UTIL_H_ */
-/*\r
- * Copyright (c) 2002-2003, Network Appliance, 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_ep_connect.c\r
- *\r
- * PURPOSE: Endpoint management\r
- *\r
- * $Id:$\r
- **********************************************************************/\r
-\r
-#include "dapl.h"\r
-#include "dapl_ep_util.h"\r
-#include "dapl_adapter_util.h"\r
-#include "dapl_evd_util.h"\r
-#include "dapl_timer_util.h"\r
-\r
-/*\r
- * dapl_ep_connect\r
- *\r
- * Request a connection be established between the local Endpoint\r
- * and a remote Endpoint. This operation is used by the active/client\r
- * side of a connection\r
- *\r
- * Input:\r
- * ep_handle\r
- * remote_ia_address\r
- * remote_conn_qual\r
- * timeout\r
- * private_data_size\r
- * privaet_data\r
- * qos\r
- * connect_flags\r
- *\r
- * Output:\r
- * None\r
- *\r
- * Returns:\r
- * DAT_SUCCESS\r
- * DAT_INSUFFICIENT_RESOUCRES\r
- * DAT_INVALID_PARAMETER\r
- * DAT_MODLE_NOT_SUPPORTED\r
- */\r
-DAT_RETURN DAT_API\r
-dapl_ep_connect(IN DAT_EP_HANDLE ep_handle,\r
- IN DAT_IA_ADDRESS_PTR remote_ia_address,\r
- IN DAT_CONN_QUAL remote_conn_qual,\r
- IN DAT_TIMEOUT timeout,\r
- IN DAT_COUNT private_data_size,\r
- IN const DAT_PVOID private_data,\r
- IN DAT_QOS qos, IN DAT_CONNECT_FLAGS connect_flags)\r
-{\r
- DAPL_EP *ep_ptr;\r
- DAPL_EP alloc_ep;\r
- DAT_RETURN dat_status;\r
- DAT_COUNT req_hdr_size;\r
- void *private_data_ptr;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM,\r
- "dapl_ep_connect (%p, {%u.%u.%u.%u}, %X, %d, %d, %p, %x, %x)\n",\r
- ep_handle,\r
- remote_ia_address->sa_data[2],\r
- remote_ia_address->sa_data[3],\r
- remote_ia_address->sa_data[4],\r
- remote_ia_address->sa_data[5],\r
- remote_conn_qual,\r
- timeout,\r
- private_data_size, private_data, qos, connect_flags);\r
-\r
- dat_status = DAT_SUCCESS;\r
- ep_ptr = (DAPL_EP *) ep_handle;\r
-\r
- /*\r
- * Verify parameter & state. The connection handle must be good\r
- * at this point.\r
- */\r
- if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) {\r
- dat_status =\r
- DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP);\r
- goto bail;\r
- }\r
-\r
- if (DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)) {\r
- dat_status =\r
- DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN);\r
- goto bail;\r
- }\r
-\r
- /* Can't do a connection in 0 time, reject outright */\r
- if (timeout == 0) {\r
- dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);\r
- goto bail;\r
- }\r
- DAPL_CNTR(ep_ptr, DCNT_EP_CONNECT);\r
-\r
- /*\r
- * If the endpoint needs a QP, associated the QP with it.\r
- * This needs to be done carefully, in order to:\r
- * * Avoid allocating under a lock.\r
- * * Not step on data structures being altered by\r
- * routines with which we are racing.\r
- * So we:\r
- * * Confirm that a new QP is needed and is not forbidden by the\r
- * current state.\r
- * * Allocate it into a separate EP.\r
- * * Take the EP lock.\r
- * * Reconfirm that the EP is in a state where it needs a QP.\r
- * * Assign the QP and release the lock.\r
- */\r
- if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {\r
- if (ep_ptr->param.pz_handle == NULL\r
- || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ))\r
- {\r
- dat_status =\r
- DAT_ERROR(DAT_INVALID_STATE,\r
- DAT_INVALID_STATE_EP_NOTREADY);\r
- goto bail;\r
- }\r
- alloc_ep = *ep_ptr;\r
-\r
- dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia,\r
- &alloc_ep, ep_ptr);\r
- if (dat_status != DAT_SUCCESS) {\r
- dat_status =\r
- DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,\r
- DAT_RESOURCE_MEMORY);\r
- goto bail;\r
- }\r
-\r
- dapl_os_lock(&ep_ptr->header.lock);\r
- /*\r
- * PZ shouldn't have changed since we're only racing with\r
- * dapl_cr_accept()\r
- */\r
- if (ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED) {\r
- /* Bail, cleaning up. */\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- dat_status = dapls_ib_qp_free(ep_ptr->header.owner_ia,\r
- &alloc_ep);\r
- if (dat_status != DAT_SUCCESS) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_WARN,\r
- "ep_connect: ib_qp_free failed with %x\n",\r
- dat_status);\r
- }\r
- dat_status =\r
- DAT_ERROR(DAT_INVALID_STATE,\r
- dapls_ep_state_subtype(ep_ptr));\r
- goto bail;\r
- }\r
-\r
- ep_ptr->qp_handle = alloc_ep.qp_handle;\r
- ep_ptr->qpn = alloc_ep.qpn;\r
- ep_ptr->qp_state = alloc_ep.qp_state;\r
-\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- }\r
-\r
- /*\r
- * We do state checks and transitions under lock.\r
- * The only code we're racing against is dapl_cr_accept.\r
- */\r
- dapl_os_lock(&ep_ptr->header.lock);\r
-\r
- /*\r
- * Verify the attributes of the EP handle before we connect it. Test\r
- * all of the handles to make sure they are currently valid.\r
- * Specifically:\r
- * pz_handle required\r
- * recv_evd_handle optional, but must be valid\r
- * request_evd_handle optional, but must be valid\r
- * connect_evd_handle required\r
- */\r
- if (ep_ptr->param.pz_handle == NULL\r
- || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ)\r
- /* test connect handle */\r
- || ep_ptr->param.connect_evd_handle == NULL\r
- || DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)\r
- || !(((DAPL_EVD *) ep_ptr->param.connect_evd_handle)->\r
- evd_flags & DAT_EVD_CONNECTION_FLAG)\r
- /* test optional completion handles */\r
- || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL &&\r
- (DAPL_BAD_HANDLE\r
- (ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD)))\r
- || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL\r
- &&\r
- (DAPL_BAD_HANDLE\r
- (ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) {\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- dat_status =\r
- DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY);\r
- goto bail;\r
- }\r
-\r
- /* Check both the EP state and the QP state: if we don't have a QP\r
- * we need to attach one now.\r
- */\r
- if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {\r
- dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia,\r
- ep_ptr, ep_ptr);\r
-\r
- if (dat_status != DAT_SUCCESS) {\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- dat_status =\r
- DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,\r
- DAT_RESOURCE_TEP);\r
- goto bail;\r
- }\r
- }\r
-\r
- if (ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED &&\r
- ep_ptr->param.ep_attr.service_type == DAT_SERVICE_TYPE_RC) {\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- dat_status =\r
- DAT_ERROR(DAT_INVALID_STATE,\r
- dapls_ep_state_subtype(ep_ptr));\r
- goto bail;\r
- }\r
-\r
- if (qos != DAT_QOS_BEST_EFFORT ||\r
- connect_flags != DAT_CONNECT_DEFAULT_FLAG) {\r
- /*\r
- * At this point we only support one QOS level\r
- */\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- dat_status = DAT_ERROR(DAT_MODEL_NOT_SUPPORTED, 0);\r
- goto bail;\r
- }\r
-\r
- /*\r
- * Verify the private data size doesn't exceed the max\r
- * req_hdr_size will evaluate to 0 unless IBHOSTS_NAMING is enabled.\r
- */\r
- req_hdr_size = (sizeof(DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE);\r
-\r
- /* transition the state before requesting a connection to avoid\r
- * race conditions\r
- */\r
- ep_ptr->param.ep_state = DAT_EP_STATE_ACTIVE_CONNECTION_PENDING;\r
-\r
- /*\r
- * At this point we're committed, and done with the endpoint\r
- * except for the connect, so we can drop the lock.\r
- */\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
-\r
-#ifdef IBHOSTS_NAMING\r
- /*\r
- * Special case: put the remote HCA address into the private data\r
- * prefix. This is a spec violation as it introduces a protocol, but\r
- * some implementations may find it necessary for a time.\r
- * Copy the private data into the EP area so the data is contiguous.\r
- * If the provider needs to pad the buffer with NULLs, it happens at\r
- * the provider layer.\r
- */\r
- dapl_os_memcpy(&ep_ptr->hca_address,\r
- &ep_ptr->header.owner_ia->hca_ptr->hca_address,\r
- sizeof(DAT_SOCK_ADDR));\r
- dapl_os_memcpy(ep_ptr->private.private_data, private_data,\r
- private_data_size);\r
- private_data_ptr = (void *)&ep_ptr->private.private_data;\r
-#else\r
- private_data_ptr = private_data;\r
-#endif /* IBHOSTS_NAMING */\r
-\r
- /* Copy the connection qualifiers */\r
- dapl_os_memcpy(ep_ptr->param.remote_ia_address_ptr,\r
- remote_ia_address, sizeof(DAT_SOCK_ADDR));\r
- ep_ptr->param.remote_port_qual = remote_conn_qual;\r
-\r
- dat_status = dapls_ib_connect(ep_handle,\r
- remote_ia_address,\r
- remote_conn_qual,\r
- private_data_size + req_hdr_size,\r
- private_data_ptr);\r
-\r
- if (dat_status != DAT_SUCCESS) {\r
- ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED;\r
-\r
- /*\r
- * Some implementations provide us with an error code that the\r
- * remote destination is unreachable, but DAT doesn't have a\r
- * synchronous error code to communicate this. So the provider\r
- * layer generates an INTERNAL_ERROR with a subtype; when\r
- * this happens, return SUCCESS and generate the event\r
- */\r
- if (dat_status == DAT_ERROR(DAT_INTERNAL_ERROR, 1)) {\r
- dapls_evd_post_connection_event((DAPL_EVD *) ep_ptr->\r
- param.\r
- connect_evd_handle,\r
- DAT_CONNECTION_EVENT_UNREACHABLE,\r
- (DAT_HANDLE) ep_ptr, 0,\r
- 0);\r
- dat_status = DAT_SUCCESS;\r
- }\r
- } else {\r
- /*\r
- * Acquire the lock and recheck the state of the EP; this\r
- * thread could have been descheduled after issuing the connect\r
- * request and the EP is now connected. Set up a timer if\r
- * necessary.\r
- */\r
- dapl_os_lock(&ep_ptr->header.lock);\r
- if (ep_ptr->param.ep_state ==\r
- DAT_EP_STATE_ACTIVE_CONNECTION_PENDING\r
- && timeout != DAT_TIMEOUT_INFINITE) {\r
- ep_ptr->cxn_timer =\r
- (DAPL_OS_TIMER *)\r
- dapl_os_alloc(sizeof(DAPL_OS_TIMER));\r
-\r
- dapls_timer_set(ep_ptr->cxn_timer,\r
- dapls_ep_timeout, ep_ptr, timeout);\r
- }\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- }\r
-\r
- bail:\r
- dapl_dbg_log(DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM,\r
- "dapl_ep_connect () returns 0x%x\n", dat_status);\r
-\r
- return dat_status;\r
-}\r
-\r
-/*\r
- * dapl_ep_common_connect\r
- *\r
- * DAPL Requirements Version 2.0, 6.6.x\r
- *\r
- * Requests that a connection be established\r
- * between the local Endpoint and a remote Endpoint specified by the\r
- * remote_ia_address. This operation is used by the active/client side\r
- * Consumer of the Connection establishment model.\r
- *\r
- * EP must be properly configured for this operation. The EP Communicator\r
- * must be specified. As part of the successful completion of this operation,\r
- * the local Endpoint is bound to a local IA Address if it had these assigned\r
- * before.\r
- * \r
- * The local IP Address, port and protocol are passed to the remote side of\r
- * the requested connection and is available to the remote Consumer in the\r
- * Connection Request of the DAT_CONNECTION_REQUEST_EVENT.\r
- * \r
- * The Consumer-provided private_data is passed to the remote side and is\r
- * provided to the remote Consumer in the Connection Request. Consumers\r
- * can encapsulate any local Endpoint attributes that remote Consumers\r
- * need to know as part of an upper-level protocol.\r
- *\r
- * Input:\r
- * ep_handle\r
- * remote_ia_address\r
- * timeout\r
- * private_data_size\r
- * private_date pointer\r
- *\r
- * Output:\r
- * none\r
- * \r
- * Returns:\r
- * DAT_SUCCESS\r
- * DAT_INSUFFICIENT_RESOURCES\r
- * DAT_INVALID_PARAMETER\r
- * DAT_INVALID_HANDLE\r
- * DAT_INVALID_STATE\r
- * DAT_MODEL_NOT_SUPPORTED\r
- */\r
-DAT_RETURN DAT_API dapl_ep_common_connect(IN DAT_EP_HANDLE ep, /* ep_handle */\r
- IN DAT_IA_ADDRESS_PTR remote_addr, /* remote_ia_address */\r
- IN DAT_TIMEOUT timeout, /* timeout */\r
- IN DAT_COUNT pdata_size, /* private_data_size */\r
- IN const DAT_PVOID pdata)\r
-{ /* private_data */\r
- return DAT_MODEL_NOT_SUPPORTED;\r
-}\r
-\r
-/*\r
- * Local variables:\r
- * c-indent-level: 4\r
- * c-basic-offset: 4\r
- * tab-width: 8\r
- * End:\r
- */\r
+/*
+ * Copyright (c) 2002-2003, Network Appliance, 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_ep_connect.c
+ *
+ * PURPOSE: Endpoint management
+ *
+ * $Id:$
+ **********************************************************************/
+
+#include "dapl.h"
+#include "dapl_ep_util.h"
+#include "dapl_adapter_util.h"
+#include "dapl_evd_util.h"
+#include "dapl_timer_util.h"
+
+/*
+ * dapl_ep_connect
+ *
+ * Request a connection be established between the local Endpoint
+ * and a remote Endpoint. This operation is used by the active/client
+ * side of a connection
+ *
+ * Input:
+ * ep_handle
+ * remote_ia_address
+ * remote_conn_qual
+ * timeout
+ * private_data_size
+ * privaet_data
+ * qos
+ * connect_flags
+ *
+ * Output:
+ * None
+ *
+ * Returns:
+ * DAT_SUCCESS
+ * DAT_INSUFFICIENT_RESOUCRES
+ * DAT_INVALID_PARAMETER
+ * DAT_MODLE_NOT_SUPPORTED
+ */
+DAT_RETURN DAT_API
+dapl_ep_connect(IN DAT_EP_HANDLE ep_handle,
+ IN DAT_IA_ADDRESS_PTR remote_ia_address,
+ IN DAT_CONN_QUAL remote_conn_qual,
+ IN DAT_TIMEOUT timeout,
+ IN DAT_COUNT private_data_size,
+ IN const DAT_PVOID private_data,
+ IN DAT_QOS qos, IN DAT_CONNECT_FLAGS connect_flags)
+{
+ DAPL_EP *ep_ptr;
+ DAPL_EP alloc_ep;
+ DAT_RETURN dat_status;
+ DAT_COUNT req_hdr_size;
+ void *private_data_ptr;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM,
+ "dapl_ep_connect (%p, {%u.%u.%u.%u}, %X, %d, %d, %p, %x, %x)\n",
+ ep_handle,
+ remote_ia_address->sa_data[2],
+ remote_ia_address->sa_data[3],
+ remote_ia_address->sa_data[4],
+ remote_ia_address->sa_data[5],
+ remote_conn_qual,
+ timeout,
+ private_data_size, private_data, qos, connect_flags);
+
+ dat_status = DAT_SUCCESS;
+ ep_ptr = (DAPL_EP *) ep_handle;
+
+ /*
+ * Verify parameter & state. The connection handle must be good
+ * at this point.
+ */
+ if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) {
+ dat_status =
+ DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP);
+ goto bail;
+ }
+
+ if (DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)) {
+ dat_status =
+ DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN);
+ goto bail;
+ }
+
+ /* Can't do a connection in 0 time, reject outright */
+ if (timeout == 0) {
+ dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);
+ goto bail;
+ }
+ DAPL_CNTR(ep_ptr, DCNT_EP_CONNECT);
+
+ /*
+ * If the endpoint needs a QP, associated the QP with it.
+ * This needs to be done carefully, in order to:
+ * * Avoid allocating under a lock.
+ * * Not step on data structures being altered by
+ * routines with which we are racing.
+ * So we:
+ * * Confirm that a new QP is needed and is not forbidden by the
+ * current state.
+ * * Allocate it into a separate EP.
+ * * Take the EP lock.
+ * * Reconfirm that the EP is in a state where it needs a QP.
+ * * Assign the QP and release the lock.
+ */
+ if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {
+ if (ep_ptr->param.pz_handle == NULL
+ || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ))
+ {
+ dat_status =
+ DAT_ERROR(DAT_INVALID_STATE,
+ DAT_INVALID_STATE_EP_NOTREADY);
+ goto bail;
+ }
+ alloc_ep = *ep_ptr;
+
+ dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia,
+ &alloc_ep, ep_ptr);
+ if (dat_status != DAT_SUCCESS) {
+ dat_status =
+ DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
+ DAT_RESOURCE_MEMORY);
+ goto bail;
+ }
+
+ dapl_os_lock(&ep_ptr->header.lock);
+ /*
+ * PZ shouldn't have changed since we're only racing with
+ * dapl_cr_accept()
+ */
+ if (ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED) {
+ /* Bail, cleaning up. */
+ dapl_os_unlock(&ep_ptr->header.lock);
+ dat_status = dapls_ib_qp_free(ep_ptr->header.owner_ia,
+ &alloc_ep);
+ if (dat_status != DAT_SUCCESS) {
+ dapl_dbg_log(DAPL_DBG_TYPE_WARN,
+ "ep_connect: ib_qp_free failed with %x\n",
+ dat_status);
+ }
+ dat_status =
+ DAT_ERROR(DAT_INVALID_STATE,
+ dapls_ep_state_subtype(ep_ptr));
+ goto bail;
+ }
+
+ ep_ptr->qp_handle = alloc_ep.qp_handle;
+ ep_ptr->qpn = alloc_ep.qpn;
+ ep_ptr->qp_state = alloc_ep.qp_state;
+
+ dapl_os_unlock(&ep_ptr->header.lock);
+ }
+
+ /*
+ * We do state checks and transitions under lock.
+ * The only code we're racing against is dapl_cr_accept.
+ */
+ dapl_os_lock(&ep_ptr->header.lock);
+
+ /*
+ * Verify the attributes of the EP handle before we connect it. Test
+ * all of the handles to make sure they are currently valid.
+ * Specifically:
+ * pz_handle required
+ * recv_evd_handle optional, but must be valid
+ * request_evd_handle optional, but must be valid
+ * connect_evd_handle required
+ */
+ if (ep_ptr->param.pz_handle == NULL
+ || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ)
+ /* test connect handle */
+ || ep_ptr->param.connect_evd_handle == NULL
+ || DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)
+ || !(((DAPL_EVD *) ep_ptr->param.connect_evd_handle)->
+ evd_flags & DAT_EVD_CONNECTION_FLAG)
+ /* test optional completion handles */
+ || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL &&
+ (DAPL_BAD_HANDLE
+ (ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD)))
+ || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL
+ &&
+ (DAPL_BAD_HANDLE
+ (ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) {
+ dapl_os_unlock(&ep_ptr->header.lock);
+ dat_status =
+ DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY);
+ goto bail;
+ }
+
+ /* Check both the EP state and the QP state: if we don't have a QP
+ * we need to attach one now.
+ */
+ if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {
+ dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia,
+ ep_ptr, ep_ptr);
+
+ if (dat_status != DAT_SUCCESS) {
+ dapl_os_unlock(&ep_ptr->header.lock);
+ dat_status =
+ DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
+ DAT_RESOURCE_TEP);
+ goto bail;
+ }
+ }
+
+ if (ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED &&
+ ep_ptr->param.ep_attr.service_type == DAT_SERVICE_TYPE_RC) {
+ dapl_os_unlock(&ep_ptr->header.lock);
+ dat_status =
+ DAT_ERROR(DAT_INVALID_STATE,
+ dapls_ep_state_subtype(ep_ptr));
+ goto bail;
+ }
+
+ if (qos != DAT_QOS_BEST_EFFORT ||
+ connect_flags != DAT_CONNECT_DEFAULT_FLAG) {
+ /*
+ * At this point we only support one QOS level
+ */
+ dapl_os_unlock(&ep_ptr->header.lock);
+ dat_status = DAT_ERROR(DAT_MODEL_NOT_SUPPORTED, 0);
+ goto bail;
+ }
+
+ /*
+ * Verify the private data size doesn't exceed the max
+ * req_hdr_size will evaluate to 0 unless IBHOSTS_NAMING is enabled.
+ */
+ req_hdr_size = (sizeof(DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE);
+
+ /* transition the state before requesting a connection to avoid
+ * race conditions
+ */
+ ep_ptr->param.ep_state = DAT_EP_STATE_ACTIVE_CONNECTION_PENDING;
+
+ /*
+ * At this point we're committed, and done with the endpoint
+ * except for the connect, so we can drop the lock.
+ */
+ dapl_os_unlock(&ep_ptr->header.lock);
+
+#ifdef IBHOSTS_NAMING
+ /*
+ * Special case: put the remote HCA address into the private data
+ * prefix. This is a spec violation as it introduces a protocol, but
+ * some implementations may find it necessary for a time.
+ * Copy the private data into the EP area so the data is contiguous.
+ * If the provider needs to pad the buffer with NULLs, it happens at
+ * the provider layer.
+ */
+ dapl_os_memcpy(&ep_ptr->hca_address,
+ &ep_ptr->header.owner_ia->hca_ptr->hca_address,
+ sizeof(DAT_SOCK_ADDR));
+ dapl_os_memcpy(ep_ptr->private.private_data, private_data,
+ private_data_size);
+ private_data_ptr = (void *)&ep_ptr->private.private_data;
+#else
+ private_data_ptr = private_data;
+#endif /* IBHOSTS_NAMING */
+
+ /* Copy the connection qualifiers */
+ dapl_os_memcpy(ep_ptr->param.remote_ia_address_ptr,
+ remote_ia_address, sizeof(DAT_SOCK_ADDR));
+ ep_ptr->param.remote_port_qual = remote_conn_qual;
+
+ dat_status = dapls_ib_connect(ep_handle,
+ remote_ia_address,
+ remote_conn_qual,
+ private_data_size + req_hdr_size,
+ private_data_ptr);
+
+ if (dat_status != DAT_SUCCESS) {
+ ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED;
+
+ /*
+ * Some implementations provide us with an error code that the
+ * remote destination is unreachable, but DAT doesn't have a
+ * synchronous error code to communicate this. So the provider
+ * layer generates an INTERNAL_ERROR with a subtype; when
+ * this happens, return SUCCESS and generate the event
+ */
+ if (dat_status == DAT_ERROR(DAT_INTERNAL_ERROR, 1)) {
+ dapls_evd_post_connection_event((DAPL_EVD *) ep_ptr->
+ param.
+ connect_evd_handle,
+ DAT_CONNECTION_EVENT_UNREACHABLE,
+ (DAT_HANDLE) ep_ptr, 0,
+ 0);
+ dat_status = DAT_SUCCESS;
+ }
+ } else {
+ /*
+ * Acquire the lock and recheck the state of the EP; this
+ * thread could have been descheduled after issuing the connect
+ * request and the EP is now connected. Set up a timer if
+ * necessary.
+ */
+ dapl_os_lock(&ep_ptr->header.lock);
+ if (ep_ptr->param.ep_state ==
+ DAT_EP_STATE_ACTIVE_CONNECTION_PENDING
+ && timeout != DAT_TIMEOUT_INFINITE) {
+ ep_ptr->cxn_timer =
+ (DAPL_OS_TIMER *)
+ dapl_os_alloc(sizeof(DAPL_OS_TIMER));
+
+ dapls_timer_set(ep_ptr->cxn_timer,
+ dapls_ep_timeout, ep_ptr, timeout);
+
+ dapl_log(DAPL_DBG_TYPE_WARN, " dapl_ep_connect timeout = %d us\n", timeout);
+ }
+ dapl_os_unlock(&ep_ptr->header.lock);
+ }
+
+ bail:
+ dapl_dbg_log(DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM,
+ "dapl_ep_connect () returns 0x%x\n", dat_status);
+
+ return dat_status;
+}
+
+/*
+ * dapl_ep_common_connect
+ *
+ * DAPL Requirements Version 2.0, 6.6.x
+ *
+ * Requests that a connection be established
+ * between the local Endpoint and a remote Endpoint specified by the
+ * remote_ia_address. This operation is used by the active/client side
+ * Consumer of the Connection establishment model.
+ *
+ * EP must be properly configured for this operation. The EP Communicator
+ * must be specified. As part of the successful completion of this operation,
+ * the local Endpoint is bound to a local IA Address if it had these assigned
+ * before.
+ *
+ * The local IP Address, port and protocol are passed to the remote side of
+ * the requested connection and is available to the remote Consumer in the
+ * Connection Request of the DAT_CONNECTION_REQUEST_EVENT.
+ *
+ * The Consumer-provided private_data is passed to the remote side and is
+ * provided to the remote Consumer in the Connection Request. Consumers
+ * can encapsulate any local Endpoint attributes that remote Consumers
+ * need to know as part of an upper-level protocol.
+ *
+ * Input:
+ * ep_handle
+ * remote_ia_address
+ * timeout
+ * private_data_size
+ * private_date pointer
+ *
+ * Output:
+ * none
+ *
+ * Returns:
+ * DAT_SUCCESS
+ * DAT_INSUFFICIENT_RESOURCES
+ * DAT_INVALID_PARAMETER
+ * DAT_INVALID_HANDLE
+ * DAT_INVALID_STATE
+ * DAT_MODEL_NOT_SUPPORTED
+ */
+DAT_RETURN DAT_API dapl_ep_common_connect(IN DAT_EP_HANDLE ep, /* ep_handle */
+ IN DAT_IA_ADDRESS_PTR remote_addr, /* remote_ia_address */
+ IN DAT_TIMEOUT timeout, /* timeout */
+ IN DAT_COUNT pdata_size, /* private_data_size */
+ IN const DAT_PVOID pdata)
+{ /* private_data */
+ return DAT_MODEL_NOT_SUPPORTED;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * End:
+ */
DAPL_EP *ep_ptr;
DAPL_IA *ia_ptr;
DAT_EP_PARAM *param;
+ dp_ib_cm_handle_t cm_ptr, next_cm_ptr;
ib_qp_state_t save_qp_state;
DAT_RETURN dat_status = DAT_SUCCESS;
}
}
+ /* Free all CM objects */
+ cm_ptr = (dapl_llist_is_empty(&ep_ptr->cm_list_head)
+ ? NULL : dapl_llist_peek_head(&ep_ptr->cm_list_head));
+ while (cm_ptr != NULL) {
+ dapl_log(DAPL_DBG_TYPE_EP,
+ "dapl_ep_free: Free CM: EP=%p CM=%p\n",
+ ep_ptr, cm_ptr);
+
+ next_cm_ptr = dapl_llist_next_entry(&ep_ptr->cm_list_head,
+ &cm_ptr->list_entry);
+ dapls_cm_free(cm_ptr); /* blocking call */
+ cm_ptr = next_cm_ptr;
+ }
+
/* Free the resource */
dapl_ep_dealloc(ep_ptr);
ep_ptr->header.user_context.as_ptr = NULL;\r
\r
dapl_llist_init_entry(&ep_ptr->header.ia_list_entry);\r
+ dapl_llist_init_head(&ep_ptr->cm_list_head);\r
dapl_os_lock_init(&ep_ptr->header.lock);\r
\r
/*\r
ep_ptr->qp_handle = IB_INVALID_HANDLE;\r
ep_ptr->qpn = 0;\r
ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED;\r
- ep_ptr->cm_handle = IB_INVALID_HANDLE;\r
\r
if (DAT_SUCCESS != dapls_cb_create(&ep_ptr->req_buffer,\r
ep_ptr,\r
if (NULL != ep_ptr->cxn_timer) {\r
dapl_os_free(ep_ptr->cxn_timer, sizeof(DAPL_OS_TIMER));\r
}\r
-#if defined(_WIN32) || defined(_WIN64)\r
- if (ep_ptr->ibal_cm_handle) {\r
- dapl_os_free(ep_ptr->ibal_cm_handle,\r
- sizeof(*ep_ptr->ibal_cm_handle));\r
- ep_ptr->ibal_cm_handle = NULL;\r
- }\r
-#endif\r
\r
#ifdef DAPL_COUNTERS\r
dapl_os_free(ep_ptr->cntrs, sizeof(DAT_UINT64) * DCNT_EP_ALL_COUNTERS);\r
* The disconnect_clean interface requires the provided dependent \r
*cm event number.\r
*/\r
- ib_cm_event = dapls_ib_get_cm_event(DAT_CONNECTION_EVENT_DISCONNECTED);\r
+ ib_cm_event = dapls_ib_get_cm_event(DAT_CONNECTION_EVENT_TIMED_OUT);\r
dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event);\r
\r
(void)dapls_evd_post_connection_event((DAPL_EVD *) ep_ptr->param.\r
{\r
ib_cm_events_t ib_cm_event;\r
DAPL_CR *cr_ptr;\r
+ dp_ib_cm_handle_t cm_ptr;\r
\r
/*\r
* Acquire the lock and make sure we didn't get a callback\r
dapls_ib_get_cm_event(DAT_CONNECTION_EVENT_DISCONNECTED);\r
\r
cr_ptr = ep_ptr->cr_ptr;\r
+ cm_ptr = (dapl_llist_is_empty(&ep_ptr->cm_list_head)\r
+ ? NULL : dapl_llist_peek_head(&ep_ptr->cm_list_head));\r
dapl_os_unlock(&ep_ptr->header.lock);\r
\r
if (cr_ptr != NULL) {\r
dapls_cr_callback(cr_ptr->ib_cm_handle,\r
ib_cm_event, NULL, 0, cr_ptr->sp_ptr);\r
} else {\r
- dapl_evd_connection_callback(ep_ptr->cm_handle,\r
+ dapl_evd_connection_callback(cm_ptr,\r
ib_cm_event,\r
NULL, 0, (void *)ep_ptr);\r
}\r
}\r
}\r
\r
+/*\r
+ * dapl_ep_link_cm\r
+ *\r
+ * Add linking of provider's CM object to a EP structure\r
+ * This enables multiple CM's per EP, and syncronization\r
+ *\r
+ * Input:\r
+ * DAPL_EP *ep_ptr\r
+ * dp_ib_cm_handle_t *cm_ptr defined in provider's dapl_util.h\r
+ *\r
+ * CM objects linked with EP using ->list_entry\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * none\r
+ *\r
+ */\r
+void dapl_ep_link_cm(IN DAPL_EP *ep_ptr, IN dp_ib_cm_handle_t cm_ptr)\r
+{\r
+ dapl_os_lock(&ep_ptr->header.lock);\r
+ dapls_cm_acquire(cm_ptr);\r
+ dapl_llist_add_tail(&ep_ptr->cm_list_head, &cm_ptr->list_entry, cm_ptr);\r
+ dapl_os_unlock(&ep_ptr->header.lock);\r
+}\r
+\r
+void dapl_ep_unlink_cm(IN DAPL_EP *ep_ptr, IN dp_ib_cm_handle_t cm_ptr)\r
+{\r
+ dapl_os_lock(&ep_ptr->header.lock);\r
+ dapl_llist_remove_entry(&ep_ptr->cm_list_head, &cm_ptr->list_entry);\r
+ dapls_cm_release(cm_ptr);\r
+ dapl_os_unlock(&ep_ptr->header.lock);\r
+}\r
+\r
/*\r
* Local variables:\r
* c-indent-level: 4\r
DAT_CLOSE_FLAGS disconnect_flags);
extern char *dapl_get_ep_state_str(DAT_EP_STATE state);
+
+extern void dapl_ep_link_cm(IN DAPL_EP *ep_ptr,
+ IN dp_ib_cm_handle_t cm_ptr);
+
+extern void dapl_ep_unlink_cm(IN DAPL_EP *ep_ptr,
+ IN dp_ib_cm_handle_t cm_ptr);
+
+STATIC _INLINE_ dp_ib_cm_handle_t dapl_get_cm_from_ep(IN DAPL_EP *ep_ptr)
+{
+ dp_ib_cm_handle_t cm_ptr;
+
+ dapl_os_lock(&ep_ptr->header.lock);
+ cm_ptr = (dapl_llist_is_empty(&ep_ptr->cm_list_head)
+ ? NULL : dapl_llist_peek_head(&ep_ptr->cm_list_head));
+ dapl_os_unlock(&ep_ptr->header.lock);
+
+ return cm_ptr;
+}
#endif /* _DAPL_EP_UTIL_H_ */
-/*\r
- * Copyright (c) 2002-2003, Network Appliance, 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_evd_connection_callback.c\r
- *\r
- * PURPOSE: implements connection callbacks\r
- *\r
- * Description: Accepts asynchronous callbacks from the Communications Manager\r
- * for EVDs that have been specified as the connection_evd.\r
- *\r
- * $Id:$\r
- **********************************************************************/\r
-\r
-#include "dapl.h"\r
-#include "dapl_evd_util.h"\r
-#include "dapl_ep_util.h"\r
-#include "dapl_timer_util.h"\r
-\r
-/*\r
- * dapl_evd_connection_callback\r
- *\r
- * Connection callback function for ACTIVE connection requests; callbacks\r
- * generated by the Connection Manager in response to issuing a\r
- * connect call.\r
- *\r
- * Input:\r
- * ib_cm_handle,\r
- * ib_cm_event\r
- * private_data_ptr\r
- * context (evd)\r
- * cr_pp\r
- *\r
- * Output:\r
- * None\r
- *\r
- */\r
-\r
-void\r
-dapl_evd_connection_callback(IN dp_ib_cm_handle_t ib_cm_handle,\r
- IN const ib_cm_events_t ib_cm_event,\r
- IN const void *private_data_ptr,\r
- IN const int private_data_size,\r
- IN const void *context)\r
-{\r
- DAPL_EP *ep_ptr;\r
- DAPL_EVD *evd_ptr;\r
- DAPL_PRIVATE *prd_ptr;\r
- DAT_EVENT_NUMBER dat_event_num;\r
- DAT_RETURN dat_status;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,\r
- "--> dapl_evd_connection_callback: ctxt: %p event: %x cm_handle %p\n",\r
- context, ib_cm_event, (void *)ib_cm_handle);\r
-\r
- /*\r
- * Determine the type of handle passed back to us in the context\r
- * and sort out key parameters.\r
- */\r
- if (context == NULL\r
- || ((DAPL_HEADER *) context)->magic != DAPL_MAGIC_EP) {\r
- return;\r
- }\r
-\r
- /*\r
- * Active side of the connection, context is an EP and\r
- * PSP is irrelevant.\r
- */\r
- ep_ptr = (DAPL_EP *) context;\r
- evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle;\r
- DAPL_CNTR(evd_ptr, DCNT_EVD_CONN_CALLBACK);\r
-\r
- prd_ptr = (DAPL_PRIVATE *) private_data_ptr;\r
- /*\r
- * All operations effect the EP, so lock it once and unlock\r
- * when necessary\r
- */\r
- dapl_os_lock(&ep_ptr->header.lock);\r
-\r
- /*\r
- * If a connection timer has been set up on this EP, cancel it now\r
- */\r
- if (ep_ptr->cxn_timer != NULL) {\r
- dapls_timer_cancel(ep_ptr->cxn_timer);\r
- dapl_os_free(ep_ptr->cxn_timer, sizeof(DAPL_OS_TIMER));\r
- ep_ptr->cxn_timer = NULL;\r
- }\r
-\r
- /* Obtain the event number from the provider layer */\r
- dat_event_num = dapls_ib_get_dat_event(ib_cm_event, DAT_FALSE);\r
-\r
- switch (dat_event_num) {\r
- case DAT_CONNECTION_EVENT_ESTABLISHED:\r
- {\r
- /* If we don't have an EP at this point we are very screwed\r
- * up\r
- */\r
- if (ep_ptr->param.ep_state !=\r
- DAT_EP_STATE_ACTIVE_CONNECTION_PENDING) {\r
- /* If someone pulled the plug on the connection, just\r
- * exit\r
- */\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- dat_status = DAT_SUCCESS;\r
- break;\r
- }\r
- ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED;\r
- ep_ptr->cm_handle = ib_cm_handle;\r
-\r
- if (private_data_size > 0) {\r
- /* copy in the private data */\r
- dapl_os_memcpy(ep_ptr->private.private_data,\r
- prd_ptr->private_data,\r
- DAPL_MIN(private_data_size,\r
- DAPL_MAX_PRIVATE_DATA_SIZE));\r
- }\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
-\r
- break;\r
- }\r
- case DAT_CONNECTION_EVENT_PEER_REJECTED:\r
- {\r
- /* peer reject may include private data */\r
-\r
- if (private_data_size > 0)\r
- dapl_os_memcpy(ep_ptr->private.private_data,\r
- prd_ptr->private_data,\r
- DAPL_MIN(private_data_size,\r
- DAPL_MAX_PRIVATE_DATA_SIZE));\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,\r
- "dapl_evd_connection_callback PEER REJ pd=%p sz=%d\n",\r
- prd_ptr, private_data_size);\r
- }\r
- case DAT_CONNECTION_EVENT_DISCONNECTED:\r
- case DAT_CONNECTION_EVENT_UNREACHABLE:\r
- case DAT_CONNECTION_EVENT_NON_PEER_REJECTED:\r
- {\r
- ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;\r
- dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE,\r
- ib_cm_event);\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
-\r
- break;\r
- }\r
- case DAT_CONNECTION_EVENT_BROKEN:\r
- case DAT_CONNECTION_EVENT_TIMED_OUT:\r
- {\r
- ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;\r
- dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE,\r
- ib_cm_event);\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
-\r
- break;\r
- }\r
- case DAT_CONNECTION_REQUEST_EVENT:\r
- default:\r
- {\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- evd_ptr = NULL;\r
-\r
- dapl_os_assert(0); /* shouldn't happen */\r
- break;\r
- }\r
- }\r
-\r
- /*\r
- * Post the event\r
- * If the EP has been freed, the evd_ptr will be NULL\r
- */\r
- if (evd_ptr != NULL) {\r
- dat_status = dapls_evd_post_connection_event(evd_ptr, dat_event_num, (DAT_HANDLE) ep_ptr, private_data_size, /* CONNECTED or REJECT */\r
- ep_ptr->private.\r
- private_data);\r
-\r
- if (dat_status != DAT_SUCCESS &&\r
- dat_event_num == DAT_CONNECTION_EVENT_ESTABLISHED) {\r
- /* We can't tell the user we are connected, something\r
- * is wrong locally. Just kill the connection and\r
- * reset the state to DISCONNECTED as we don't\r
- * expect a callback on an ABRUPT disconnect.\r
- */\r
- dapls_ib_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG);\r
- dapl_os_lock(&ep_ptr->header.lock);\r
- ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- }\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,\r
- "dapl_evd_connection_callback () returns\n");\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
+/*
+ * Copyright (c) 2002-2003, Network Appliance, 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_evd_connection_callback.c
+ *
+ * PURPOSE: implements connection callbacks
+ *
+ * Description: Accepts asynchronous callbacks from the Communications Manager
+ * for EVDs that have been specified as the connection_evd.
+ *
+ * $Id:$
+ **********************************************************************/
+
+#include "dapl.h"
+#include "dapl_evd_util.h"
+#include "dapl_ep_util.h"
+#include "dapl_timer_util.h"
+
+/*
+ * dapl_evd_connection_callback
+ *
+ * Connection callback function for ACTIVE connection requests; callbacks
+ * generated by the Connection Manager in response to issuing a
+ * connect call.
+ *
+ * Input:
+ * ib_cm_handle,
+ * ib_cm_event
+ * private_data_ptr
+ * context (evd)
+ * cr_pp
+ *
+ * Output:
+ * None
+ *
+ */
+
+void
+dapl_evd_connection_callback(IN dp_ib_cm_handle_t ib_cm_handle,
+ IN const ib_cm_events_t ib_cm_event,
+ IN const void *private_data_ptr,
+ IN const int private_data_size,
+ IN const void *context)
+{
+ DAPL_EP *ep_ptr;
+ DAPL_EVD *evd_ptr;
+ DAPL_PRIVATE *prd_ptr;
+ DAT_EVENT_NUMBER dat_event_num;
+ DAT_RETURN dat_status;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,
+ "--> dapl_evd_connection_callback: ctxt: %p event: %x cm_handle %p\n",
+ context, ib_cm_event, (void *)ib_cm_handle);
+
+ /*
+ * Determine the type of handle passed back to us in the context
+ * and sort out key parameters.
+ */
+ if (context == NULL
+ || ((DAPL_HEADER *) context)->magic != DAPL_MAGIC_EP) {
+ return;
+ }
+
+ /*
+ * Active side of the connection, context is an EP and
+ * PSP is irrelevant.
+ */
+ ep_ptr = (DAPL_EP *) context;
+ evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle;
+ DAPL_CNTR(evd_ptr, DCNT_EVD_CONN_CALLBACK);
+
+ prd_ptr = (DAPL_PRIVATE *) private_data_ptr;
+ /*
+ * All operations effect the EP, so lock it once and unlock
+ * when necessary
+ */
+ dapl_os_lock(&ep_ptr->header.lock);
+
+ /*
+ * If a connection timer has been set up on this EP, cancel it now
+ */
+ if (ep_ptr->cxn_timer != NULL) {
+ dapls_timer_cancel(ep_ptr->cxn_timer);
+ dapl_os_free(ep_ptr->cxn_timer, sizeof(DAPL_OS_TIMER));
+ ep_ptr->cxn_timer = NULL;
+ }
+
+ /* Obtain the event number from the provider layer */
+ dat_event_num = dapls_ib_get_dat_event(ib_cm_event, DAT_FALSE);
+
+ switch (dat_event_num) {
+ case DAT_CONNECTION_EVENT_ESTABLISHED:
+ {
+ /* If we don't have an EP at this point we are very screwed
+ * up
+ */
+ if (ep_ptr->param.ep_state !=
+ DAT_EP_STATE_ACTIVE_CONNECTION_PENDING) {
+ /* If someone pulled the plug on the connection, just
+ * exit
+ */
+ dapl_os_unlock(&ep_ptr->header.lock);
+ dat_status = DAT_SUCCESS;
+ break;
+ }
+ ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED;
+
+ if (private_data_size > 0) {
+ /* copy in the private data */
+ dapl_os_memcpy(ep_ptr->private.private_data,
+ prd_ptr->private_data,
+ DAPL_MIN(private_data_size,
+ DAPL_MAX_PRIVATE_DATA_SIZE));
+ }
+ dapl_os_unlock(&ep_ptr->header.lock);
+
+ break;
+ }
+ case DAT_CONNECTION_EVENT_PEER_REJECTED:
+ {
+ /* peer reject may include private data */
+
+ if (private_data_size > 0)
+ dapl_os_memcpy(ep_ptr->private.private_data,
+ prd_ptr->private_data,
+ DAPL_MIN(private_data_size,
+ DAPL_MAX_PRIVATE_DATA_SIZE));
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,
+ "dapl_evd_connection_callback PEER REJ pd=%p sz=%d\n",
+ prd_ptr, private_data_size);
+ }
+ case DAT_CONNECTION_EVENT_DISCONNECTED:
+ case DAT_CONNECTION_EVENT_UNREACHABLE:
+ case DAT_CONNECTION_EVENT_NON_PEER_REJECTED:
+ {
+ ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
+ dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE,
+ ib_cm_event);
+ dapl_os_unlock(&ep_ptr->header.lock);
+
+ break;
+ }
+ case DAT_CONNECTION_EVENT_BROKEN:
+ case DAT_CONNECTION_EVENT_TIMED_OUT:
+ {
+ ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
+ dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE,
+ ib_cm_event);
+ dapl_os_unlock(&ep_ptr->header.lock);
+
+ break;
+ }
+ case DAT_CONNECTION_REQUEST_EVENT:
+ default:
+ {
+ dapl_os_unlock(&ep_ptr->header.lock);
+ evd_ptr = NULL;
+
+ dapl_os_assert(0); /* shouldn't happen */
+ break;
+ }
+ }
+
+ /*
+ * Post the event
+ * If the EP has been freed, the evd_ptr will be NULL
+ */
+ if (evd_ptr != NULL) {
+ dat_status = dapls_evd_post_connection_event(evd_ptr, dat_event_num, (DAT_HANDLE) ep_ptr, private_data_size, /* CONNECTED or REJECT */
+ ep_ptr->private.
+ private_data);
+
+ if (dat_status != DAT_SUCCESS &&
+ dat_event_num == DAT_CONNECTION_EVENT_ESTABLISHED) {
+ /* We can't tell the user we are connected, something
+ * is wrong locally. Just kill the connection and
+ * reset the state to DISCONNECTED as we don't
+ * expect a callback on an ABRUPT disconnect.
+ */
+ dapls_ib_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG);
+ dapl_os_lock(&ep_ptr->header.lock);
+ ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
+ dapl_os_unlock(&ep_ptr->header.lock);
+ }
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,
+ "dapl_evd_connection_callback () returns\n");
+
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * End:
+ */
ep_ptr->param.ep_state =
DAT_EP_STATE_PASSIVE_CONNECTION_PENDING;
}
- ep_ptr->cm_handle = ib_cm_handle;
+ dapl_ep_link_cm(ep_ptr, ib_cm_handle);
}
/* link the CR onto the SP so we can pick it up later */
-/*\r
- * Copyright (c) 2002-2003, Network Appliance, 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
- * HEADER: dapl_evd_util.h\r
- *\r
- * PURPOSE: Utility defs & routines for the EVD data structure\r
- *\r
- * $Id:$\r
- *\r
- **********************************************************************/\r
-\r
-#ifndef _DAPL_EVD_UTIL_H_\r
-#define _DAPL_EVD_UTIL_H_\r
-\r
-#include "dapl.h"\r
-\r
-DAT_RETURN\r
-dapls_evd_internal_create (\r
- IN DAPL_IA *ia_ptr, \r
- IN DAPL_CNO *cno_ptr,\r
- IN DAT_COUNT min_qlen,\r
- IN DAT_EVD_FLAGS evd_flags,\r
- OUT DAPL_EVD **evd_ptr_ptr) ;\r
-\r
-DAPL_EVD *\r
-dapls_evd_alloc ( \r
- IN DAPL_IA *ia_ptr,\r
- IN DAPL_CNO *cno_ptr,\r
- IN DAT_EVD_FLAGS evd_flags,\r
- IN DAT_COUNT qlen) ;\r
-\r
-DAT_RETURN\r
-dapls_evd_dealloc ( \r
- IN DAPL_EVD *evd_ptr) ;\r
-\r
-DAT_RETURN dapls_evd_event_realloc (\r
- IN DAPL_EVD *evd_ptr,\r
- IN DAT_COUNT qlen);\r
-\r
-/*\r
- * Each of these functions will retrieve a free event from\r
- * the specified EVD, fill in the elements of that event, and\r
- * post the event back to the EVD. If there is no EVD available,\r
- * an overflow event will be posted to the async EVD associated\r
- * with the EVD.\r
- *\r
- * DAT_INSUFFICIENT_RESOURCES will be returned on overflow,\r
- * DAT_SUCCESS otherwise.\r
- */\r
-\r
-DAT_RETURN\r
-dapls_evd_post_cr_arrival_event (\r
- IN DAPL_EVD *evd_ptr,\r
- IN DAT_EVENT_NUMBER event_number,\r
- IN DAT_SP_HANDLE sp_handle,\r
- DAT_IA_ADDRESS_PTR ia_address_ptr,\r
- DAT_CONN_QUAL conn_qual,\r
- DAT_CR_HANDLE cr_handle);\r
- \r
-DAT_RETURN\r
-dapls_evd_post_connection_event (\r
- IN DAPL_EVD *evd_ptr,\r
- IN DAT_EVENT_NUMBER event_number,\r
- IN DAT_EP_HANDLE ep_handle,\r
- IN DAT_COUNT private_data_size,\r
- IN DAT_PVOID private_data);\r
-\r
-DAT_RETURN\r
-dapls_evd_post_async_error_event (\r
- IN DAPL_EVD *evd_ptr,\r
- IN DAT_EVENT_NUMBER event_number,\r
- IN DAT_IA_HANDLE ia_handle);\r
-\r
-DAT_RETURN\r
-dapls_evd_post_software_event (\r
- IN DAPL_EVD *evd_ptr,\r
- IN DAT_EVENT_NUMBER event_number,\r
- IN DAT_PVOID pointer);\r
-\r
-DAT_RETURN\r
-dapls_evd_post_generic_event (\r
- IN DAPL_EVD *evd_ptr,\r
- IN DAT_EVENT_NUMBER event_number,\r
- IN DAT_EVENT_DATA *data);\r
-\r
-#ifdef DAT_EXTENSIONS\r
-DAT_RETURN\r
-dapls_evd_post_cr_event_ext (\r
- IN DAPL_SP *sp_ptr,\r
- IN DAT_EVENT_NUMBER event_number,\r
- IN dp_ib_cm_handle_t ib_cm_handle,\r
- IN DAT_COUNT p_size,\r
- IN DAT_PVOID p_data,\r
- IN DAT_PVOID ext_data);\r
-\r
-DAT_RETURN\r
-dapls_evd_post_connection_event_ext (\r
- IN DAPL_EVD *evd_ptr,\r
- IN DAT_EVENT_NUMBER event_number,\r
- IN DAT_EP_HANDLE ep_handle,\r
- IN DAT_COUNT private_data_size,\r
- IN DAT_PVOID private_data,\r
- IN DAT_PVOID ext_data);\r
-#endif\r
-\r
-/*************************************\r
- * dapl internal callbacks functions *\r
- *************************************/\r
-\r
-/* connection verb callback */\r
-extern void dapl_evd_connection_callback (\r
- IN dp_ib_cm_handle_t ib_cm_handle,\r
- IN const ib_cm_events_t ib_cm_events,\r
- IN const void *private_data_ptr,\r
- IN const int private_data_size,\r
- IN const void * context );\r
-\r
-/* dto verb callback */\r
-extern void dapl_evd_dto_callback (\r
- IN ib_hca_handle_t ib_hca_handle, \r
- IN ib_cq_handle_t ib_cq_handle, \r
- IN void* context);\r
-\r
-/* async verb callbacks */\r
-extern void dapl_evd_un_async_error_callback (\r
- IN ib_hca_handle_t ib_hca_handle,\r
- IN ib_error_record_t * cause_ptr,\r
- IN void * context);\r
-\r
-extern void dapl_evd_cq_async_error_callback (\r
- IN ib_hca_handle_t ib_hca_handle,\r
- IN ib_cq_handle_t ib_cq_handle,\r
- IN ib_error_record_t * cause_ptr,\r
- IN void * context);\r
-\r
-extern void dapl_evd_qp_async_error_callback (\r
- IN ib_hca_handle_t ib_hca_handle,\r
- IN ib_qp_handle_t ib_qp_handle,\r
- IN ib_error_record_t * cause_ptr,\r
- IN void * context);\r
-\r
-extern void dapls_evd_copy_cq (\r
- DAPL_EVD *evd_ptr);\r
-\r
-extern DAT_RETURN dapls_evd_cq_poll_to_event (\r
- IN DAPL_EVD *evd_ptr,\r
- OUT DAT_EVENT *event);\r
-\r
-#endif\r
+/*
+ * Copyright (c) 2002-2003, Network Appliance, 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.
+ */
+
+/**********************************************************************
+ *
+ * HEADER: dapl_evd_util.h
+ *
+ * PURPOSE: Utility defs & routines for the EVD data structure
+ *
+ * $Id:$
+ *
+ **********************************************************************/
+
+#ifndef _DAPL_EVD_UTIL_H_
+#define _DAPL_EVD_UTIL_H_
+
+#include "dapl.h"
+
+DAT_RETURN
+dapls_evd_internal_create (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_CNO *cno_ptr,
+ IN DAT_COUNT min_qlen,
+ IN DAT_EVD_FLAGS evd_flags,
+ OUT DAPL_EVD **evd_ptr_ptr) ;
+
+DAPL_EVD *
+dapls_evd_alloc (
+ IN DAPL_IA *ia_ptr,
+ IN DAPL_CNO *cno_ptr,
+ IN DAT_EVD_FLAGS evd_flags,
+ IN DAT_COUNT qlen) ;
+
+DAT_RETURN
+dapls_evd_dealloc (
+ IN DAPL_EVD *evd_ptr) ;
+
+DAT_RETURN dapls_evd_event_realloc (
+ IN DAPL_EVD *evd_ptr,
+ IN DAT_COUNT qlen);
+
+/*
+ * Each of these functions will retrieve a free event from
+ * the specified EVD, fill in the elements of that event, and
+ * post the event back to the EVD. If there is no EVD available,
+ * an overflow event will be posted to the async EVD associated
+ * with the EVD.
+ *
+ * DAT_INSUFFICIENT_RESOURCES will be returned on overflow,
+ * DAT_SUCCESS otherwise.
+ */
+
+DAT_RETURN
+dapls_evd_post_cr_arrival_event (
+ IN DAPL_EVD *evd_ptr,
+ IN DAT_EVENT_NUMBER event_number,
+ IN DAT_SP_HANDLE sp_handle,
+ DAT_IA_ADDRESS_PTR ia_address_ptr,
+ DAT_CONN_QUAL conn_qual,
+ DAT_CR_HANDLE cr_handle);
+
+DAT_RETURN
+dapls_evd_post_connection_event (
+ IN DAPL_EVD *evd_ptr,
+ IN DAT_EVENT_NUMBER event_number,
+ IN DAT_EP_HANDLE ep_handle,
+ IN DAT_COUNT private_data_size,
+ IN DAT_PVOID private_data);
+
+DAT_RETURN
+dapls_evd_post_async_error_event (
+ IN DAPL_EVD *evd_ptr,
+ IN DAT_EVENT_NUMBER event_number,
+ IN DAT_IA_HANDLE ia_handle);
+
+DAT_RETURN
+dapls_evd_post_software_event (
+ IN DAPL_EVD *evd_ptr,
+ IN DAT_EVENT_NUMBER event_number,
+ IN DAT_PVOID pointer);
+
+DAT_RETURN
+dapls_evd_post_generic_event (
+ IN DAPL_EVD *evd_ptr,
+ IN DAT_EVENT_NUMBER event_number,
+ IN DAT_EVENT_DATA *data);
+
+#ifdef DAT_EXTENSIONS
+DAT_RETURN
+dapls_evd_post_cr_event_ext (
+ IN DAPL_SP *sp_ptr,
+ IN DAT_EVENT_NUMBER event_number,
+ IN dp_ib_cm_handle_t ib_cm_handle,
+ IN DAT_COUNT p_size,
+ IN DAT_PVOID p_data,
+ IN DAT_PVOID ext_data);
+
+DAT_RETURN
+dapls_evd_post_connection_event_ext (
+ IN DAPL_EVD *evd_ptr,
+ IN DAT_EVENT_NUMBER event_number,
+ IN DAT_EP_HANDLE ep_handle,
+ IN DAT_COUNT private_data_size,
+ IN DAT_PVOID private_data,
+ IN DAT_PVOID ext_data);
+#endif
+
+/*************************************
+ * dapl internal callbacks functions *
+ *************************************/
+
+/* connection verb callback */
+extern void dapl_evd_connection_callback (
+ IN dp_ib_cm_handle_t ib_cm_handle,
+ IN const ib_cm_events_t ib_cm_events,
+ IN const void *private_data_ptr,
+ IN const int private_data_size,
+ IN const void * context );
+
+/* dto verb callback */
+extern void dapl_evd_dto_callback (
+ IN ib_hca_handle_t ib_hca_handle,
+ IN ib_cq_handle_t ib_cq_handle,
+ IN void* context);
+
+/* async verb callbacks */
+extern void dapl_evd_un_async_error_callback (
+ IN ib_hca_handle_t ib_hca_handle,
+ IN ib_error_record_t * cause_ptr,
+ IN void * context);
+
+extern void dapl_evd_cq_async_error_callback (
+ IN ib_hca_handle_t ib_hca_handle,
+ IN ib_cq_handle_t ib_cq_handle,
+ IN ib_error_record_t * cause_ptr,
+ IN void * context);
+
+extern void dapl_evd_qp_async_error_callback (
+ IN ib_hca_handle_t ib_hca_handle,
+ IN ib_qp_handle_t ib_qp_handle,
+ IN ib_error_record_t * cause_ptr,
+ IN void * context);
+
+extern void dapls_evd_copy_cq (
+ DAPL_EVD *evd_ptr);
+
+extern DAT_RETURN dapls_evd_cq_poll_to_event (
+ IN DAPL_EVD *evd_ptr,
+ OUT DAT_EVENT *event);
+
+#endif
-/*\r
- * Copyright (c) 2002-2003, Network Appliance, 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_ia_query.c\r
- *\r
- * PURPOSE: Interface Adapter management\r
- * Description: Interfaces in this file are completely described in\r
- * the DAPL 1.1 API, Chapter 6, section 2\r
- *\r
- * $Id:$\r
- **********************************************************************/\r
-\r
-#include "dapl.h"\r
-#include "dapl_adapter_util.h"\r
-#include "dapl_vendor.h"\r
-\r
-/*\r
- * dapl_ia_query\r
- *\r
- * DAPL Requirements Version xxx, 6.2.1.3\r
- *\r
- * Provide the consumer with Interface Adapter and Provider parameters.\r
- *\r
- * Input:\r
- * ia_handle\r
- * ia_mask\r
- * provider_mask\r
- *\r
- * Output:\r
- * async_evd_handle\r
- * ia_parameters\r
- * provider_parameters\r
- *\r
- * Returns:\r
- * DAT_SUCCESS\r
- * DAT_INVALID_PARAMETER\r
- */\r
-DAT_RETURN DAT_API\r
-dapl_ia_query(IN DAT_IA_HANDLE ia_handle,\r
- OUT DAT_EVD_HANDLE * async_evd_handle,\r
- IN DAT_IA_ATTR_MASK ia_attr_mask,\r
- OUT DAT_IA_ATTR * ia_attr,\r
- IN DAT_PROVIDER_ATTR_MASK provider_attr_mask,\r
- OUT DAT_PROVIDER_ATTR * provider_attr)\r
-{\r
- DAPL_IA *ia_ptr;\r
- DAT_RETURN dat_status;\r
- struct evd_merge_type {\r
- DAT_BOOLEAN array[6][6];\r
- } *evd_merge;\r
- DAT_BOOLEAN val;\r
- int i;\r
- int j;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_API,\r
- "dapl_ia_query (%p, %p, 0x%llx, %p, 0x%x, %p)\n",\r
- ia_handle,\r
- async_evd_handle,\r
- ia_attr_mask, ia_attr, provider_attr_mask, provider_attr);\r
-\r
- ia_ptr = (DAPL_IA *) ia_handle;\r
- dat_status = DAT_SUCCESS;\r
-\r
- if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) {\r
- dat_status =\r
- DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA);\r
- goto bail;\r
- }\r
-\r
- if (NULL != async_evd_handle) {\r
- *async_evd_handle = ia_ptr->async_error_evd;\r
- }\r
-\r
- if (ia_attr_mask & DAT_IA_FIELD_ALL) {\r
- if (NULL == ia_attr) {\r
- dat_status =\r
- DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);\r
- goto bail;\r
- }\r
-\r
- /*\r
- * Obtain parameters from the HCA. Protect against multiple\r
- * IAs beating on the HCA at the same time.\r
- */\r
- dat_status =\r
- dapls_ib_query_hca(ia_ptr->hca_ptr, ia_attr, NULL, NULL);\r
- if (dat_status != DAT_SUCCESS) {\r
- goto bail;\r
- }\r
- }\r
-\r
- if (ia_attr_mask & ~DAT_IA_FIELD_ALL) {\r
- dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);\r
- goto bail;\r
- }\r
-\r
- if (provider_attr_mask & DAT_PROVIDER_FIELD_ALL) {\r
- if (NULL == provider_attr) {\r
- dat_status =\r
- DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG6);\r
- goto bail;\r
- }\r
-\r
- strncpy(provider_attr->provider_name,\r
- ia_ptr->header.provider->device_name,\r
- DAT_NAME_MAX_LENGTH);\r
- provider_attr->provider_version_major = VN_PROVIDER_MAJOR;\r
- provider_attr->provider_version_minor = VN_PROVIDER_MINOR;\r
- provider_attr->dapl_version_major = DAT_VERSION_MAJOR;\r
- provider_attr->dapl_version_minor = DAT_VERSION_MINOR;\r
- provider_attr->lmr_mem_types_supported =\r
- DAT_MEM_TYPE_VIRTUAL | DAT_MEM_TYPE_LMR;\r
-#if VN_MEM_SHARED_VIRTUAL_SUPPORT > 0 && !defined(__KDAPL__)\r
- provider_attr->lmr_mem_types_supported |=\r
- DAT_MEM_TYPE_SHARED_VIRTUAL;\r
-#endif\r
- provider_attr->iov_ownership_on_return = DAT_IOV_CONSUMER;\r
- provider_attr->dat_qos_supported = DAT_QOS_BEST_EFFORT;\r
- provider_attr->completion_flags_supported =\r
- DAT_COMPLETION_DEFAULT_FLAG;\r
- provider_attr->is_thread_safe = DAT_FALSE;\r
- /*\r
- * N.B. The second part of the following equation will evaluate\r
- * to 0 unless IBHOSTS_NAMING is enabled.\r
- */\r
- provider_attr->max_private_data_size =\r
- dapls_ib_private_data_size(ia_ptr->hca_ptr) -\r
- (sizeof(DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE);\r
- provider_attr->supports_multipath = DAT_FALSE;\r
- provider_attr->ep_creator = DAT_PSP_CREATES_EP_NEVER;\r
- provider_attr->optimal_buffer_alignment = DAT_OPTIMAL_ALIGNMENT;\r
- /* The value of pz_support may vary by transport */\r
- provider_attr->num_provider_specific_attr = 0;\r
- provider_attr->provider_specific_attr = NULL;\r
-#if !defined(__KDAPL__)\r
- provider_attr->pz_support = DAT_PZ_UNIQUE;\r
-#endif /* !KDAPL */\r
-\r
- /*\r
- * Query for provider specific attributes\r
- */\r
- dapls_query_provider_specific_attr(ia_ptr, provider_attr);\r
-\r
- /*\r
- * Set up evd_stream_merging_supported options. Note there is\r
- * one bit per allowable combination, using the ordinal\r
- * position of the DAT_EVD_FLAGS as positions in the\r
- * array. e.g.\r
- * [0][0] is DAT_EVD_SOFTWARE_FLAG | DAT_EVD_SOFTWARE_FLAG,\r
- * [0][1] is DAT_EVD_SOFTWARE_FLAG | DAT_EVD_CR_FLAG, and\r
- * [2][4] is DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG\r
- *\r
- * Most combinations are true, so initialize the array that way.\r
- * Then finish by resetting the bad combinations.\r
- *\r
- * DAT_EVD_ASYNC_FLAG is not supported. InfiniBand only allows\r
- * a single asynchronous event handle per HCA, and the first\r
- * dat_ia_open forces the creation of the only one that can be\r
- * used. We disallow the user from creating an ASYNC EVD here.\r
- */\r
-\r
- evd_merge =\r
- (struct evd_merge_type *)&provider_attr->\r
- evd_stream_merging_supported[0][0];\r
- val = DAT_TRUE;\r
- for (i = 0; i < 6; i++) {\r
- if (i > 4) {\r
- /* ASYNC EVD is 5, so entire row will be 0 */\r
- val = DAT_FALSE;\r
- }\r
- for (j = 0; j < 5; j++) {\r
- evd_merge->array[i][j] = val;\r
- }\r
- /* Set the ASYNC_EVD column to FALSE */\r
- evd_merge->array[i][5] = DAT_FALSE;\r
- }\r
-\r
-#ifndef DAPL_MERGE_CM_DTO\r
- /*\r
- * If an implementation supports CM and DTO completions on\r
- * the same EVD then DAPL_MERGE_CM_DTO should be set to\r
- * skip the following code\r
- */\r
- /* DAT_EVD_DTO_FLAG | DAT_EVD_CONNECTION_FLAG */\r
- evd_merge->array[2][3] = DAT_FALSE;\r
- /* DAT_EVD_CONNECTION_FLAG | DAT_EVD_DTO_FLAG */\r
- evd_merge->array[3][2] = DAT_FALSE;\r
-#endif /* DAPL_MERGE_CM_DTO */\r
- }\r
-\r
- bail:\r
- if (dat_status != DAT_SUCCESS) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_RTN,\r
- "dapl_ia_query () returns 0x%x\n", dat_status);\r
- }\r
-\r
- return dat_status;\r
-}\r
-\r
-/*\r
- * Local variables:\r
- * c-indent-level: 4\r
- * c-basic-offset: 4\r
- * tab-width: 8\r
- * End:\r
- */\r
+/*
+ * Copyright (c) 2002-2003, Network Appliance, 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_ia_query.c
+ *
+ * PURPOSE: Interface Adapter management
+ * Description: Interfaces in this file are completely described in
+ * the DAPL 1.1 API, Chapter 6, section 2
+ *
+ * $Id:$
+ **********************************************************************/
+
+#include "dapl.h"
+#include "dapl_adapter_util.h"
+#include "dapl_vendor.h"
+
+/*
+ * dapl_ia_query
+ *
+ * DAPL Requirements Version xxx, 6.2.1.3
+ *
+ * Provide the consumer with Interface Adapter and Provider parameters.
+ *
+ * Input:
+ * ia_handle
+ * ia_mask
+ * provider_mask
+ *
+ * Output:
+ * async_evd_handle
+ * ia_parameters
+ * provider_parameters
+ *
+ * Returns:
+ * DAT_SUCCESS
+ * DAT_INVALID_PARAMETER
+ */
+DAT_RETURN DAT_API
+dapl_ia_query(IN DAT_IA_HANDLE ia_handle,
+ OUT DAT_EVD_HANDLE * async_evd_handle,
+ IN DAT_IA_ATTR_MASK ia_attr_mask,
+ OUT DAT_IA_ATTR * ia_attr,
+ IN DAT_PROVIDER_ATTR_MASK provider_attr_mask,
+ OUT DAT_PROVIDER_ATTR * provider_attr)
+{
+ DAPL_IA *ia_ptr;
+ DAT_RETURN dat_status;
+ struct evd_merge_type {
+ DAT_BOOLEAN array[6][6];
+ } *evd_merge;
+ DAT_BOOLEAN val;
+ int i;
+ int j;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_API,
+ "dapl_ia_query (%p, %p, 0x%llx, %p, 0x%x, %p)\n",
+ ia_handle,
+ async_evd_handle,
+ ia_attr_mask, ia_attr, provider_attr_mask, provider_attr);
+
+ ia_ptr = (DAPL_IA *) ia_handle;
+ dat_status = DAT_SUCCESS;
+
+ if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) {
+ dat_status =
+ DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA);
+ goto bail;
+ }
+
+ if (NULL != async_evd_handle) {
+ *async_evd_handle = ia_ptr->async_error_evd;
+ }
+
+ if (ia_attr_mask & DAT_IA_FIELD_ALL) {
+ if (NULL == ia_attr) {
+ dat_status =
+ DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);
+ goto bail;
+ }
+
+ /*
+ * Obtain parameters from the HCA. Protect against multiple
+ * IAs beating on the HCA at the same time.
+ */
+ dat_status =
+ dapls_ib_query_hca(ia_ptr->hca_ptr, ia_attr, NULL, NULL);
+ if (dat_status != DAT_SUCCESS) {
+ goto bail;
+ }
+ }
+
+ if (ia_attr_mask & ~DAT_IA_FIELD_ALL) {
+ dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
+ goto bail;
+ }
+
+ if (provider_attr_mask & DAT_PROVIDER_FIELD_ALL) {
+ if (NULL == provider_attr) {
+ dat_status =
+ DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG6);
+ goto bail;
+ }
+
+ strncpy(provider_attr->provider_name,
+ ia_ptr->header.provider->device_name,
+ DAT_NAME_MAX_LENGTH);
+ provider_attr->provider_version_major = VN_PROVIDER_MAJOR;
+ provider_attr->provider_version_minor = VN_PROVIDER_MINOR;
+ provider_attr->dapl_version_major = DAT_VERSION_MAJOR;
+ provider_attr->dapl_version_minor = DAT_VERSION_MINOR;
+ provider_attr->lmr_mem_types_supported =
+ DAT_MEM_TYPE_VIRTUAL | DAT_MEM_TYPE_LMR;
+#if VN_MEM_SHARED_VIRTUAL_SUPPORT > 0 && !defined(__KDAPL__)
+ provider_attr->lmr_mem_types_supported |=
+ DAT_MEM_TYPE_SHARED_VIRTUAL;
+#endif
+ provider_attr->iov_ownership_on_return = DAT_IOV_CONSUMER;
+ provider_attr->dat_qos_supported = DAT_QOS_BEST_EFFORT;
+ provider_attr->completion_flags_supported =
+ DAT_COMPLETION_DEFAULT_FLAG;
+ provider_attr->is_thread_safe = DAT_FALSE;
+ /*
+ * N.B. The second part of the following equation will evaluate
+ * to 0 unless IBHOSTS_NAMING is enabled.
+ */
+ provider_attr->max_private_data_size =
+ dapls_ib_private_data_size(ia_ptr->hca_ptr) -
+ (sizeof(DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE);
+ provider_attr->supports_multipath = DAT_FALSE;
+ provider_attr->ep_creator = DAT_PSP_CREATES_EP_NEVER;
+ provider_attr->optimal_buffer_alignment = DAT_OPTIMAL_ALIGNMENT;
+ /* The value of pz_support may vary by transport */
+ provider_attr->num_provider_specific_attr = 0;
+ provider_attr->provider_specific_attr = NULL;
+#if !defined(__KDAPL__)
+ provider_attr->pz_support = DAT_PZ_UNIQUE;
+#endif /* !KDAPL */
+
+ /*
+ * Query for provider specific attributes
+ */
+ dapls_query_provider_specific_attr(ia_ptr, provider_attr);
+
+ /*
+ * Set up evd_stream_merging_supported options. Note there is
+ * one bit per allowable combination, using the ordinal
+ * position of the DAT_EVD_FLAGS as positions in the
+ * array. e.g.
+ * [0][0] is DAT_EVD_SOFTWARE_FLAG | DAT_EVD_SOFTWARE_FLAG,
+ * [0][1] is DAT_EVD_SOFTWARE_FLAG | DAT_EVD_CR_FLAG, and
+ * [2][4] is DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG
+ *
+ * Most combinations are true, so initialize the array that way.
+ * Then finish by resetting the bad combinations.
+ *
+ * DAT_EVD_ASYNC_FLAG is not supported. InfiniBand only allows
+ * a single asynchronous event handle per HCA, and the first
+ * dat_ia_open forces the creation of the only one that can be
+ * used. We disallow the user from creating an ASYNC EVD here.
+ */
+
+ evd_merge =
+ (struct evd_merge_type *)&provider_attr->
+ evd_stream_merging_supported[0][0];
+ val = DAT_TRUE;
+ for (i = 0; i < 6; i++) {
+ if (i > 4) {
+ /* ASYNC EVD is 5, so entire row will be 0 */
+ val = DAT_FALSE;
+ }
+ for (j = 0; j < 5; j++) {
+ evd_merge->array[i][j] = val;
+ }
+ /* Set the ASYNC_EVD column to FALSE */
+ evd_merge->array[i][5] = DAT_FALSE;
+ }
+
+#ifndef DAPL_MERGE_CM_DTO
+ /*
+ * If an implementation supports CM and DTO completions on
+ * the same EVD then DAPL_MERGE_CM_DTO should be set to
+ * skip the following code
+ */
+ /* DAT_EVD_DTO_FLAG | DAT_EVD_CONNECTION_FLAG */
+ evd_merge->array[2][3] = DAT_FALSE;
+ /* DAT_EVD_CONNECTION_FLAG | DAT_EVD_DTO_FLAG */
+ evd_merge->array[3][2] = DAT_FALSE;
+#endif /* DAPL_MERGE_CM_DTO */
+ }
+
+ bail:
+ if (dat_status != DAT_SUCCESS) {
+ dapl_dbg_log(DAPL_DBG_TYPE_RTN,
+ "dapl_ia_query () returns 0x%x\n", dat_status);
+ }
+
+ return dat_status;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * End:
+ */
*\r
* PURPOSE: IB Connection routines for access to IBAL APIs\r
*\r
- * $Id$\r
+ * $Id: dapl_ibal_cm.c 584 2007-02-07 13:12:18Z sleybo $\r
*\r
**********************************************************************/\r
\r
if ( !pd || len <= 0 )\r
return;\r
\r
- dapl_log ( DAPL_DBG_TYPE_CM, "--> %s: private_data:\n ",prefix);\r
+ dapl_log ( DAPL_DBG_TYPE_CM, "--> %s: private_data(len %d)\n ",prefix,len);\r
\r
if (len > IB_MAX_REP_PDATA_SIZE)\r
{\r
for ( i = 0 ; i < len; i++ )\r
{\r
dapl_log ( DAPL_DBG_TYPE_CM, "%2x ", pd[i]);\r
- if ( ((i+1) % 20) == 0 ) \r
+ if ( ((i+1) % 5) == 0 ) \r
dapl_log ( DAPL_DBG_TYPE_CM, "\n ");\r
}\r
dapl_log ( DAPL_DBG_TYPE_CM, "\n");\r
}\r
#endif\r
\r
+/* EP-CM linking support */\r
+dp_ib_cm_handle_t ibal_cm_alloc(void)\r
+{\r
+ dp_ib_cm_handle_t cm_ptr;\r
+\r
+ /* Allocate CM, init lock, and initialize */\r
+ if ((cm_ptr = dapl_os_alloc(sizeof(*cm_ptr))) == NULL)\r
+ return NULL;\r
+\r
+ (void)dapl_os_memzero(cm_ptr, sizeof(*cm_ptr));\r
+ cm_ptr->ref_count = 1;\r
+\r
+ if (dapl_os_lock_init(&cm_ptr->lock)) {\r
+ dapl_os_free(cm_ptr, sizeof(*cm_ptr));\r
+ return NULL;\r
+ }\r
+\r
+ dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm_ptr->list_entry);\r
+ \r
+ return cm_ptr;\r
+}\r
+\r
+/* free CM object resources */\r
+static void ibal_cm_dealloc(dp_ib_cm_handle_t cm_ptr) \r
+{\r
+ dapl_os_assert(!cm_ptr->ref_count);\r
+ dapl_os_lock_destroy(&cm_ptr->lock);\r
+ dapl_os_free(cm_ptr, sizeof(*cm_ptr));\r
+}\r
+\r
+void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr)\r
+{\r
+ dapl_os_lock(&cm_ptr->lock);\r
+ cm_ptr->ref_count++;\r
+ dapl_os_unlock(&cm_ptr->lock);\r
+}\r
+\r
+void dapls_cm_release(dp_ib_cm_handle_t cm_ptr)\r
+{\r
+ dapl_os_lock(&cm_ptr->lock);\r
+ cm_ptr->ref_count--;\r
+ if (cm_ptr->ref_count) {\r
+ dapl_os_unlock(&cm_ptr->lock);\r
+ return;\r
+ }\r
+ dapl_os_unlock(&cm_ptr->lock);\r
+ ibal_cm_dealloc(cm_ptr);\r
+}\r
+\r
+/* blocking: called from user thread dapl_ep_free() only */\r
+void dapls_cm_free(dp_ib_cm_handle_t cm_ptr)\r
+{\r
+ dapl_ep_unlink_cm(cm_ptr->ep, cm_ptr);\r
+\r
+ /* final reference, alloc */\r
+ dapls_cm_release(cm_ptr);\r
+}\r
\r
static void \r
dapli_ib_cm_apr_cb (\r
ib_cm_drep_t cm_drep;\r
DAPL_EP *ep_ptr;\r
int bail=10;\r
+ dp_ib_cm_handle_t cm_ptr;\r
\r
dapl_os_assert (p_cm_dreq_rec);\r
\r
DAPL_MAGIC_EP );\r
return;\r
}\r
+ cm_ptr = dapl_get_cm_from_ep(ep_ptr);\r
+ if (!cm_ptr)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr);\r
+ return;\r
+ }\r
+ dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_dreq_rec->h_cm_dreq.h_qp);\r
\r
dapl_dbg_log (DAPL_DBG_TYPE_CM, \r
"--> %s() EP %p, %s sent_discreq %s\n",\r
\r
if (ep_ptr->cr_ptr)\r
{\r
- dapl_os_assert(ep_ptr->ibal_cm_handle->cid\r
- == p_cm_dreq_rec->h_cm_dreq.cid);\r
/* passive side */\r
- dapls_cr_callback ( ep_ptr->cm_handle,\r
+ dapls_cr_callback ( cm_ptr,\r
IB_CME_DISCONNECTED,\r
(void * __ptr64) p_cm_dreq_rec->p_dreq_pdata,\r
IB_DREQ_PDATA_SIZE,\r
{\r
/* active side */\r
dapl_evd_connection_callback (\r
- (dp_ib_cm_handle_t) &p_cm_dreq_rec->h_cm_dreq,\r
+ cm_ptr,\r
IB_CME_DISCONNECTED,\r
(void * __ptr64)\r
p_cm_dreq_rec->p_dreq_pdata,\r
IN ib_cm_drep_rec_t *p_cm_drep_rec )\r
{\r
DAPL_EP *ep_ptr;\r
+ dp_ib_cm_handle_t cm_ptr;\r
\r
dapl_os_assert (p_cm_drep_rec != NULL);\r
\r
"--> %s: BAD EP Handle EP=%lx\n", __FUNCTION__,ep_ptr); \r
return;\r
}\r
+ cm_ptr = dapl_get_cm_from_ep(ep_ptr);\r
+ if (!cm_ptr)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr);\r
+ return;\r
+ }\r
+ dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_drep_rec->h_qp);\r
\r
dapl_dbg_log (DAPL_DBG_TYPE_CM, \r
"--> DiCDpcb: EP %p state %s cm_hdl %p\n",ep_ptr,\r
dapl_get_ep_state_str(ep_ptr->param.ep_state),\r
- ep_ptr->cm_handle);\r
+ cm_ptr);\r
\r
if ( ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED )\r
{\r
return;\r
}\r
\r
- if (ep_ptr->cm_handle == DAPL_IB_INVALID_HANDLE )\r
- {\r
- dapl_dbg_log (DAPL_DBG_TYPE_CM,\r
- "--> %s: Invalid EP->CM handle?\n", __FUNCTION__); \r
- return;\r
- }\r
-\r
if (ep_ptr->cr_ptr)\r
{\r
/* passive connection side */\r
- dapls_cr_callback ( ep_ptr->cm_handle,\r
+ dapls_cr_callback ( cm_ptr,\r
IB_CME_DISCONNECTED,\r
(void * __ptr64) p_cm_drep_rec->p_drep_pdata,\r
IB_DREP_PDATA_SIZE,\r
{\r
/* active connection side */\r
dapl_evd_connection_callback (\r
- ep_ptr->cm_handle,\r
+ cm_ptr,\r
IB_CME_DISCONNECTED,\r
(void * __ptr64) p_cm_drep_rec->p_drep_pdata,\r
IB_DREP_PDATA_SIZE,\r
DAPL_PRIVATE *prd_ptr;\r
DAPL_EP *ep_ptr;\r
dapl_ibal_ca_t *p_ca;\r
+ dp_ib_cm_handle_t cm_ptr;\r
\r
dapl_os_assert (p_cm_rep_rec != NULL);\r
\r
__FUNCTION__, ep_ptr);\r
return;\r
}\r
+ cm_ptr = dapl_get_cm_from_ep(ep_ptr);\r
+ if (!cm_ptr)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr);\r
+ return;\r
+ }\r
+ dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_rep_rec->h_cm_rep.h_qp);\r
+\r
dapl_dbg_log (DAPL_DBG_TYPE_CM, \r
- "--> DiCRpcb: EP = %lx local_max_rdma_read_in %d\n", \r
+ "--> DiCRpcb: EP %lx local_max_rdma_read_in %d\n", \r
ep_ptr, p_cm_rep_rec->resp_res);\r
\r
p_ca = (dapl_ibal_ca_t *) \r
#endif\r
\r
dapl_evd_connection_callback ( \r
- (dp_ib_cm_handle_t)&p_cm_rep_rec->h_cm_rep,\r
+ cm_ptr,\r
cm_cb_op,\r
(void *) prd_ptr,\r
IB_REP_PDATA_SIZE,\r
{\r
DAPL_EP *ep_ptr;\r
ib_cm_events_t cm_event;\r
+ dp_ib_cm_handle_t cm_ptr;\r
\r
dapl_os_assert (p_cm_rej_rec);\r
\r
__FUNCTION__, ep_ptr);\r
return;\r
}\r
+ cm_ptr = dapl_get_cm_from_ep(ep_ptr);\r
+ if (!cm_ptr)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR, \r
+ "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr);\r
+ return;\r
+ }\r
+ dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_rej_rec->h_qp);\r
\r
dapl_dbg_log (DAPL_DBG_TYPE_CM, \r
"--> DiCRjcb: EP = %lx QP = %lx rej reason = 0x%x\n", \r
\r
if (ep_ptr->cr_ptr)\r
{\r
- dapls_cr_callback ( ep_ptr->cm_handle,\r
+ dapls_cr_callback ( cm_ptr,\r
cm_event,\r
(void * __ptr64) p_cm_rej_rec->p_rej_pdata,\r
IB_REJ_PDATA_SIZE,\r
else\r
{\r
dapl_evd_connection_callback (\r
- ep_ptr->cm_handle,\r
+ cm_ptr,\r
cm_event,\r
(void * __ptr64) p_cm_rej_rec->p_rej_pdata,\r
IB_REJ_PDATA_SIZE,\r
{\r
DAPL_SP *sp_ptr;\r
DAT_SOCK_ADDR6 dest_ia_addr;\r
- dp_ib_cm_handle_t cm_handle;\r
-\r
- struct ibal_cr_data {\r
- ib_cm_handle_t cm_hdl;\r
- DAT_SOCK_ADDR6 dst_ip_addr;\r
- } *crd;\r
+ dp_ib_cm_handle_t cm_ptr;\r
\r
dapl_os_assert (p_cm_req_rec);\r
\r
* EP struct deallocation is where this memory is released or prior in the\r
* error case.\r
*/\r
- crd = dapl_os_alloc ( sizeof(struct ibal_cr_data) );\r
- if ( !crd )\r
+ cm_ptr = ibal_cm_alloc();\r
+ if (!cm_ptr)\r
{\r
dapl_dbg_log ( DAPL_DBG_TYPE_ERR,\r
"%s: FAILED to alloc IB CM handle storage?\n",\r
return;\r
}\r
\r
- cm_handle = &crd->cm_hdl;\r
- dapl_os_memzero ( (void*)crd, sizeof(*crd) );\r
-\r
/*\r
* Save the cm_srvc_handle to avoid the race condition between\r
* the return of the ib_cm_listen and the notification of a conn req\r
\r
#endif /* NO_NAME_SERVICE */\r
\r
+ /* preserve CR cm handle data */\r
+ dapl_os_memcpy( (void*)&cm_ptr->ib_cm,\r
+ (void*)&p_cm_req_rec->h_cm_req,\r
+ sizeof(ib_cm_handle_t));\r
+\r
+ /* preserve remote IP address */\r
+ dapl_os_memcpy( (void*)&cm_ptr->dst_ip_addr,\r
+ (void*)&dest_ia_addr,\r
+ sizeof(dest_ia_addr));\r
+\r
#if defined(DAPL_DBG)\r
{\r
char ipa[20];\r
//rval = ((struct sockaddr_in *) (&dest_ia_addr))->sin_addr.s_addr;\r
\r
dapl_dbg_log (DAPL_DBG_TYPE_CM|DAPL_DBG_TYPE_CALLBACK, \r
- "%s: query SA for RemoteAddr: %s\n",\r
- __FUNCTION__,\r
- dapli_get_ip_addr_str( (DAT_SOCK_ADDR6*)\r
- &dest_ia_addr, ipa) );\r
+ "%s: query SA (CM %lx)->dst_ip_addr: %s\n",\r
+ __FUNCTION__,cm_ptr,\r
+ dapli_get_ip_addr_str(\r
+ (DAT_SOCK_ADDR6*) &cm_ptr->dst_ip_addr, ipa) );\r
}\r
#endif\r
\r
- /* preserve CR cm handle data */\r
- dapl_os_memcpy( (void*)cm_handle,\r
- (void*)&p_cm_req_rec->h_cm_req,\r
- sizeof(ib_cm_handle_t) );\r
-\r
- /* preserve remote IP address */\r
- dapl_os_memcpy( (void*)&crd->dst_ip_addr,\r
- (void*)&dest_ia_addr,\r
- sizeof(dest_ia_addr) );\r
-\r
/* FIXME - Vu\r
* We have NOT used/saved the primary and alternative path record\r
* ie. p_cm_req_rec->p_primary_path and p_cm_req_rec->p_alt_path\r
__FUNCTION__, sp_ptr, p_cm_req_rec->resp_res,\r
p_cm_req_rec->p_req_pdata);\r
\r
- dapls_cr_callback ( cm_handle,\r
+ dapls_cr_callback ( cm_ptr,\r
IB_CME_CONNECTION_REQUEST_PENDING,\r
(void * __ptr64) p_cm_req_rec->p_req_pdata,\r
- IB_REQ_PDATA_SIZE,\r
+ IB_REQ_PDATA_SIZE,\r
(void * __ptr64) sp_ptr );\r
}\r
\r
IN ib_cm_mra_rec_t *p_cm_mra_rec )\r
{\r
UNUSED_PARAM( p_cm_mra_rec );\r
- dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, \r
+ dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, \r
"--> DiCMcb: CM callback MRA\n");\r
}\r
\r
dapli_ib_cm_rtu_cb (\r
IN ib_cm_rtu_rec_t *p_cm_rtu_rec )\r
{\r
- DAPL_EP *ep_ptr;\r
+ DAPL_EP *ep_ptr;\r
+ dp_ib_cm_handle_t cm_ptr;\r
\r
dapl_os_assert (p_cm_rtu_rec != NULL);\r
\r
__FUNCTION__, ep_ptr);\r
return;\r
}\r
+ cm_ptr = dapl_get_cm_from_ep(ep_ptr);\r
+ if (!cm_ptr)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr);\r
+ return;\r
+ }\r
+ dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_rtu_rec->h_qp);\r
\r
dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, \r
- "--> DiCRucb: EP %lx QP %lx\n", ep_ptr, ep_ptr->qp_handle); \r
+ "--> DiCRucb: EP %lx QP %lx CR %lx\n",\r
+ ep_ptr, ep_ptr->qp_handle, ep_ptr->cr_ptr); \r
\r
if (ep_ptr->cr_ptr)\r
{\r
\r
sp_ptr = ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr;\r
\r
- dapls_cr_callback ( ep_ptr->cm_handle,\r
+ /* passive connection side */\r
+ dapls_cr_callback ( cm_ptr,\r
IB_CME_CONNECTED,\r
(void * __ptr64) p_cm_rtu_rec->p_rtu_pdata,\r
IB_RTU_PDATA_SIZE,\r
else\r
{\r
dapl_evd_connection_callback ( \r
- ep_ptr->cm_handle,\r
+ cm_ptr,\r
IB_CME_CONNECTED,\r
(void * __ptr64) p_cm_rtu_rec->p_rtu_pdata,\r
IB_RTU_PDATA_SIZE,\r
{\r
\r
DAPL_HEADER *header;\r
- void *vp;\r
+ dp_ib_cm_handle_t cm;\r
char ipa[20];\r
+ char *rtype;\r
\r
header = (DAPL_HEADER *)dat_handle;\r
\r
if (header->magic == DAPL_MAGIC_EP) \r
{\r
- vp = &((DAPL_EP *) dat_handle)->remote_ia_address;\r
+ cm = dapl_get_cm_from_ep((DAPL_EP *)dat_handle);\r
+ rtype = "EP";\r
}\r
else if (header->magic == DAPL_MAGIC_CR) \r
{\r
- vp = &((DAPL_CR *) dat_handle)->remote_ia_address;\r
+ cm = ((DAPL_CR *) dat_handle)->ib_cm_handle;\r
+ rtype = "CR";\r
}\r
else \r
{\r
return DAT_INVALID_HANDLE;\r
}\r
\r
- dapl_os_memcpy( remote_address, vp, sizeof(DAT_SOCK_ADDR6) );\r
+ dapl_os_memcpy( remote_address, &cm->dst_ip_addr, sizeof(DAT_SOCK_ADDR6) );\r
\r
- dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%s: returns %s\n",\r
- __FUNCTION__,\r
+ dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%s: returns %s remote Addrs %s\n",\r
+ __FUNCTION__, rtype,\r
dapli_get_ip_addr_str((DAT_SOCK_ADDR6*)remote_address,ipa) );\r
\r
return DAT_SUCCESS;\r
IN DAT_CLOSE_FLAGS disconnect_flags )\r
{\r
ib_api_status_t ib_status = IB_SUCCESS;\r
- ib_cm_dreq_t cm_dreq;\r
+ ib_cm_dreq_t cm_dreq;\r
+ dp_ib_cm_handle_t cm_ptr;\r
\r
dapl_os_assert(ep_ptr);\r
\r
"--> %s: BAD EP Magic EP=%lx\n", __FUNCTION__,ep_ptr); \r
return DAT_SUCCESS;\r
}\r
-\r
- if (ep_ptr->cm_handle == DAPL_IB_INVALID_HANDLE )\r
+ cm_ptr = dapl_get_cm_from_ep(ep_ptr);\r
+ if (!cm_ptr)\r
{\r
- dapl_dbg_log (DAPL_DBG_TYPE_CM,\r
- "--> %s: Invalid EP->CM handle, OK.\n", __FUNCTION__); \r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR, \r
+ "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr);\r
return DAT_SUCCESS;\r
}\r
-\r
+ \r
dapl_dbg_log (DAPL_DBG_TYPE_CM,\r
"--> %s() EP %p %s rx_drq %d tx_drq %d Close %s\n", __FUNCTION__,\r
ep_ptr, dapl_get_ep_state_str(ep_ptr->param.ep_state),\r
dapli_print_private_data("DsRjC",private_data,private_data_size);\r
#endif\r
\r
- ib_status = ib_cm_rej ( *ib_cm_handle, &cm_rej);\r
+ ib_status = ib_cm_rej(ib_cm_handle->ib_cm, &cm_rej);\r
\r
if (ib_status != IB_SUCCESS)\r
{\r
dapl_dbg_log ( DAPL_DBG_TYPE_ERR,\r
- "--> DsRjC: cm_handle %lx reject failed %s\n", \r
+ "--> DsRjC: cm_handle %p reject failed %s\n", \r
ib_cm_handle, ib_get_err_str(ib_status) );\r
}\r
\r
dapl_ibal_port_t *p_active_port;\r
ib_cm_rep_t cm_rep;\r
ib_qp_attr_t qpa;\r
+ dp_ib_cm_handle_t cm_ptr;\r
\r
cr_ptr = (DAPL_CR *) cr_handle;\r
ep_ptr = (DAPL_EP *) ep_handle;\r
}\r
\r
cr_ptr->param.local_ep_handle = ep_handle;\r
- ep_ptr->cm_handle = cr_ptr->ib_cm_handle;\r
+\r
/*\r
* assume ownership, in that once the EP is released the dynamic\r
* memory containing the IBAL CM handle (ib_cm_handle_t) struct will\r
* be released; see dapl_ep_dealloc().\r
*/\r
- ep_ptr->ibal_cm_handle = cr_ptr->ib_cm_handle;\r
-\r
+ \r
+ /* EP-CM, save/release CR CM object, use EP CM object already linked */\r
+ cm_ptr = dapl_get_cm_from_ep(ep_ptr);\r
+ if (!cm_ptr) {\r
+ dapl_dbg_log ( DAPL_DBG_TYPE_ERR,\r
+ "--> DsIBAC: CM linking to EP %p not available\n",\r
+ ep_ptr);\r
+ return (DAT_INVALID_STATE);\r
+ }\r
+ \r
/* set remote IP addr fields. IP addr data is deduced from Connection\r
* Request record (gid/lib) and stashed away for use here. DAPL 1.1\r
* had an interface for passing the IP info down, interface went away\r
* in 2.0?\r
*/\r
dapl_os_memcpy( (void*)&ep_ptr->remote_ia_address,\r
- (void*)(ep_ptr->cm_handle+1),\r
+ (void*)&cr_ptr->ib_cm_handle->dst_ip_addr,\r
sizeof(DAT_SOCK_ADDR6) );\r
\r
dapl_os_memcpy( (void*)&cr_ptr->remote_ia_address,\r
(void*)&ep_ptr->remote_ia_address,\r
sizeof(DAT_SOCK_ADDR6) );\r
\r
-#if defined(DAPL_DBG) && 0\r
+#if defined(DAPL_DBG)\r
{\r
char ipa[20];\r
\r
"%s: EP(%lx) RemoteAddr: %s\n",\r
__FUNCTION__, ep_ptr,\r
dapli_get_ip_addr_str(\r
- (DAT_SOCK_ADDR6*)&ep_ptr->remote_ia_address, ipa));\r
+ (DAT_SOCK_ADDR6*)&ep_ptr->remote_ia_address, ipa) );\r
}\r
#endif\r
\r
- ep_ptr->qp_state = IB_QPS_INIT;\r
+ dapl_os_memcpy( (void*)&cm_ptr->dst_ip_addr,\r
+ (void*)&cr_ptr->ib_cm_handle->dst_ip_addr,\r
+ sizeof(DAT_SOCK_ADDR6) );\r
+\r
+ /* get h_al and connection ID from CR CM object, h_qp already set */\r
+ cm_ptr->ib_cm.cid = cr_ptr->ib_cm_handle->ib_cm.cid; \r
+ cm_ptr->ib_cm.h_al = cr_ptr->ib_cm_handle->ib_cm.h_al;\r
+ dapls_cm_release(cr_ptr->ib_cm_handle);\r
+\r
+ cr_ptr->ib_cm_handle = cm_ptr; /* for dapli_get_sp_ep() upcall */\r
+\r
ep_ptr->cr_ptr = cr_ptr;\r
\r
dapl_os_memzero ( (void*)&cm_rep, sizeof (ib_cm_rep_t) );\r
cm_rep.access_ctrl, cm_rep.init_depth,cm_rep.qp_type,\r
dapls_cb_pending(&ep_ptr->req_buffer));\r
\r
- ib_status = ib_cm_rep ( *ep_ptr->cm_handle, &cm_rep );\r
+ ib_status = ib_cm_rep ( cm_ptr->ib_cm, &cm_rep );\r
\r
if (ib_status != IB_SUCCESS)\r
{\r
dapl_dbg_log ( DAPL_DBG_TYPE_ERR,\r
"--> DsIBAC: EP %lx QP %lx CR reply failed '%s'\n",\r
ep_ptr, ep_ptr->qp_handle, ib_get_err_str(ib_status) );\r
-\r
- /* errors not perculated back to CR callback which allocated the\r
- * memory, free it here on error.\r
- */\r
- dapl_os_free ( (void*)ep_ptr->ibal_cm_handle, sizeof(ib_cm_handle_t) );\r
- ep_ptr->ibal_cm_handle = NULL;\r
}\r
\r
return ( dapl_ib_status_convert ( ib_status ) );\r
\r
ep_ptr->sent_discreq = DAT_FALSE;\r
ep_ptr->recv_discreq = DAT_FALSE;\r
- if ( ep_ptr->ibal_cm_handle )\r
- {\r
- dapl_os_free ( (void*)ep_ptr->ibal_cm_handle, sizeof(ib_cm_handle_t) );\r
- }\r
- ep_ptr->ibal_cm_handle = NULL;\r
\r
/* \r
* Query the QP to get the current state */\r
\r
cr_ptr = (DAPL_CR *) cr_handle;\r
\r
- if (cr_ptr->ib_cm_handle->cid == 0xFFFFFFFF)\r
+ if (cr_ptr->ib_cm_handle->ib_cm.cid == 0xFFFFFFFF)\r
{\r
dapl_dbg_log ( DAPL_DBG_TYPE_ERR,\r
"--> DsCH: CR = %lx invalid cm handle\n", cr_ptr);\r
return DAT_INVALID_PARAMETER;\r
}\r
\r
- ib_status = ib_cm_handoff (*cr_ptr->ib_cm_handle, handoff_serv_id);\r
+ ib_status = ib_cm_handoff (cr_ptr->ib_cm_handle->ib_cm, handoff_serv_id);\r
\r
if (ib_status != IB_SUCCESS)\r
{\r
-
-/*
- * Copyright (c) 2005-2007 Intel Corporation. All rights reserved.
- * Copyright (c) 2002, Network Appliance, Inc. All rights reserved.
- *
- * This Software is licensed under the terms of the "Common Public
- * License" a copy of which is in the file LICENSE.txt in the root
- * directory. The license is also available from the Open Source
- * Initiative, see http://www.opensource.org/licenses/cpl.php.
- *
- */
-
-/**********************************************************************
- *
- * MODULE: dapl_ibal_qp.c
- *
- * PURPOSE: IB QP routines for access to IBAL APIs
- *
- * $Id: dapl_ibal_qp.c 33 2005-07-11 19:51:17Z ftillier $
- *
- **********************************************************************/
-
-#include "dapl.h"
-#include "dapl_adapter_util.h"
-#include "dapl_evd_util.h"
-#include "dapl_ibal_util.h"
-
-#define DAPL_IBAL_QKEY 0
-#define DAPL_IBAL_START_PSN 0
-
-extern DAT_RETURN
-dapls_ib_cq_late_alloc ( IN ib_pd_handle_t pd_handle,
- IN DAPL_EVD *evd_ptr );
-
-static void
-dapli_ib_qp_async_error_cb( IN ib_async_event_rec_t* p_err_rec )
-{
- DAPL_EP *ep_ptr = (DAPL_EP *)p_err_rec->context;
- DAPL_EVD *evd_ptr;
- DAPL_IA *ia_ptr;
- dapl_ibal_ca_t *p_ca;
- dapl_ibal_evd_cb_t *evd_cb;
-
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC QP event %s qp ctx %p\n",
- ib_get_async_event_str(p_err_rec->code), p_err_rec->context);
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC qp_handle %p qpn %u\n",
- ((DAPL_EP *)p_err_rec->context)->qp_handle,
- ((DAPL_EP *)p_err_rec->context)->qpn);
-
- /*
- * Verify handles EP, EVD, and hca_handle
- */
- if (DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) ||
- DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD))
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DiQpAEC: invalid EP %p \n", ep_ptr);
- return;
- }
- ia_ptr = ep_ptr->header.owner_ia;
- evd_ptr = ia_ptr->async_error_evd;
-
- if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD) ||
- ! (evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG))
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DiQpAEC: invalid EVD %p \n", evd_ptr);
- return;
- }
- p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle;
- if (p_ca == NULL)
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DiQpAEC: can't find %s HCA\n",
- (ia_ptr->header.provider)->device_name);
- return;
- }
-
- /* find QP error callback using ia_ptr for context */
- evd_cb = dapli_find_evd_cb_by_context (ia_ptr, p_ca);
- if ((evd_cb == NULL) || (evd_cb->pfn_async_qp_err_cb == NULL))
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DiQpAEC: no ERROR cb on p_ca %p found\n", p_ca);
- return;
- }
-
- dapl_os_lock (&ep_ptr->header.lock);
- ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING;
- dapl_os_unlock (&ep_ptr->header.lock);
-
- /* force disconnect, QP error state, to insure DTO's get flushed */
- dapls_ib_disconnect ( ep_ptr, DAT_CLOSE_ABRUPT_FLAG );
-
- /* maps to dapl_evd_qp_async_error_callback(), context is EP */
- evd_cb->pfn_async_qp_err_cb( (ib_hca_handle_t)p_ca,
- ep_ptr->qp_handle,
- (ib_error_record_t*)&p_err_rec->code,
- ep_ptr );
-}
-
-/*
- * dapls_ib_qp_alloc
- *
- * Alloc a QP
- *
- * Input:
- * *ia_ptr pointer to DAPL IA
- * *ep_ptr pointer to DAPL EP
- * *ep_ctx_ptr pointer to DAPL EP context
- *
- * Output:
- * none
- *
- * Returns:
- * DAT_SUCCESS
- * DAT_INSUFFICIENT_RESOURCES
- *
- */
-DAT_RETURN
-dapls_ib_qp_alloc (
- IN DAPL_IA *ia_ptr,
- IN DAPL_EP *ep_ptr,
- IN DAPL_EP *ep_ctx_ptr)
-{
- DAT_EP_ATTR *attr;
- DAPL_EVD *recv_evd_ptr, *request_evd_ptr;
- DAT_RETURN dat_status;
- ib_api_status_t ib_status;
- ib_qp_create_t qp_create;
- ib_pd_handle_t ib_pd_handle;
- ib_cq_handle_t cq_recv;
- ib_cq_handle_t cq_send;
- dapl_ibal_ca_t *p_ca;
- dapl_ibal_port_t *p_active_port;
- ib_qp_attr_t qp_attr;
-
- attr = &ep_ptr->param.ep_attr;
-
- dapl_os_assert ( ep_ptr->param.pz_handle != NULL );
-
- ib_pd_handle = ((DAPL_PZ *)ep_ptr->param.pz_handle)->pd_handle;
- dapl_os_assert(ib_pd_handle);
- recv_evd_ptr = (DAPL_EVD *) ep_ptr->param.recv_evd_handle;
- request_evd_ptr = (DAPL_EVD *) ep_ptr->param.request_evd_handle;
-
- cq_recv = IB_INVALID_HANDLE;
- cq_send = IB_INVALID_HANDLE;
-
- dapl_os_assert ( recv_evd_ptr != DAT_HANDLE_NULL );
- {
- cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle;
-
- if ((cq_recv == IB_INVALID_HANDLE) &&
- ( 0 != (recv_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) ))
- {
- dat_status = dapls_ib_cq_late_alloc ( ib_pd_handle, recv_evd_ptr);
- if (dat_status != DAT_SUCCESS)
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> %s: failed to create CQ\n","DsQA");
- return (dat_status);
- }
-
- dat_status = dapls_set_cq_notify (ia_ptr, recv_evd_ptr);
-
- if (dat_status != DAT_SUCCESS)
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> %s: failed to enable notify CQ\n","DsQA");
- return (dat_status);
- }
-
- cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle;
- dapl_dbg_log (DAPL_DBG_TYPE_EP,
- "--> DsQA: alloc_recv_CQ = %p\n", cq_recv);
-
- }
- }
-
- dapl_os_assert ( request_evd_ptr != DAT_HANDLE_NULL );
- {
- cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle;
-
- if ((cq_send == IB_INVALID_HANDLE) &&
- ( 0 != (request_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) ))
- {
- dat_status = dapls_ib_cq_late_alloc (ib_pd_handle, request_evd_ptr);
- if (dat_status != DAT_SUCCESS)
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> %s: failed to create CQ\n","DsQA");
- return (dat_status);
- }
-
- dat_status = dapls_set_cq_notify (ia_ptr, request_evd_ptr);
-
- if (dat_status != DAT_SUCCESS)
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> %s: failed to enable notify CQ\n","DsQA");
- return (dat_status);
- }
-
- cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle;
- dapl_dbg_log (DAPL_DBG_TYPE_EP,
- "--> DsQA: alloc_send_CQ = %p\n", cq_send);
- }
- }
-
- /*
- * Get the CA structure
- */
- p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle;
-
- dapl_os_memzero (&qp_create, sizeof (qp_create));
- qp_create.qp_type = IB_QPT_RELIABLE_CONN;
- qp_create.sq_depth = attr->max_request_dtos;
- qp_create.rq_depth = attr->max_recv_dtos;
- qp_create.sq_sge = attr->max_recv_iov;
- qp_create.rq_sge = attr->max_request_iov;
- qp_create.h_sq_cq = cq_send;
- qp_create.h_rq_cq = cq_recv;
- qp_create.sq_signaled = FALSE;
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP,
- "--> DsQA: sqd,iov=%d,%d rqd,iov=%d,%d\n",
- attr->max_request_dtos, attr->max_request_iov,
- attr->max_recv_dtos, attr->max_recv_iov);
-
- ib_status = ib_create_qp (
- ib_pd_handle,
- &qp_create,
- (void *) ep_ctx_ptr /* context */,
- dapli_ib_qp_async_error_cb,
- &ep_ptr->qp_handle);
-
- if (ib_status != IB_SUCCESS)
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsQA: Create QP failed = %s\n",
- ib_get_err_str(ib_status));
- return (DAT_INSUFFICIENT_RESOURCES);
- }
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQA: EP=%p, tEVD=%p, rEVD=%p QP=%p\n",
- ep_ptr, ep_ptr->param.request_evd_handle,
- ep_ptr->param.recv_evd_handle,
- ep_ptr->qp_handle );
-
- ep_ptr->qp_state = IB_QPS_RESET;
-
- p_active_port = dapli_ibal_get_port(p_ca,(uint8_t)ia_ptr->hca_ptr->port_num);
-
- if (NULL == p_active_port)
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DsQA: Port %d is not available = %d\n",
- ia_ptr->hca_ptr->port_num, __LINE__);
- return (DAT_INVALID_STATE);
- }
-
- ib_status = dapls_modify_qp_state_to_init ( ep_ptr->qp_handle,
- &ep_ptr->param.ep_attr,
- p_active_port );
-
- if ( ib_status != IB_SUCCESS )
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DsQA: Change QP state to INIT failed = %s\n",
- ib_get_err_str(ib_status));
- return (DAT_INVALID_HANDLE);
- }
- ib_status = ib_query_qp ( ep_ptr->qp_handle, &qp_attr );
-
- ep_ptr->qp_state = qp_attr.state;
- ep_ptr->qpn = qp_attr.num;
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQAQA: EP:%p new_QP %p state %s\n",
- ep_ptr,
- ep_ptr->qp_handle,
- ib_get_port_state_str(ep_ptr->qp_state));
-
- return (DAT_SUCCESS);
-}
-
-
-/*
- * dapls_ib_qp_free
- *
- * Free a QP
- *
- * Input:
- * *ia_ptr pointer to IA structure
- * *ep_ptr pointer to EP structure
- *
- * Output:
- * none
- *
- * Returns:
- * none
- *
- */
-DAT_RETURN
-dapls_ib_qp_free (
- IN DAPL_IA *ia_ptr,
- IN DAPL_EP *ep_ptr )
-{
-
- ib_qp_handle_t qp_handle;
- UNREFERENCED_PARAMETER(ia_ptr);
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQF: free %p, state %s\n",
- ep_ptr->qp_handle,
- ib_get_port_state_str(ep_ptr->qp_state));
-
- if (( ep_ptr->qp_handle != IB_INVALID_HANDLE ) &&
- ( ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED ))
- {
- qp_handle = ep_ptr->qp_handle;
- ep_ptr->qp_handle = IB_INVALID_HANDLE;
- ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED;
- ib_destroy_qp ( qp_handle, NULL /* callback */);
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQF: freed QP %p\n",
- qp_handle );
- }
-
- return DAT_SUCCESS;
-}
-
-
-/*
- * dapls_ib_qp_modify
- *
- * Set the QP to the parameters specified in an EP_PARAM
- *
- * We can't be sure what state the QP is in so we first obtain the state
- * from the driver. The EP_PARAM structure that is provided has been
- * sanitized such that only non-zero values are valid.
- *
- * Input:
- * *ia_ptr pointer to DAPL IA
- * *ep_ptr pointer to DAPL EP
- * *ep_attr pointer to DAT EP attribute
- *
- * Output:
- * none
- *
- * Returns:
- * DAT_SUCCESS
- * DAT_INSUFFICIENT_RESOURCES
- * DAT_INVALID_PARAMETER
- *
- */
-DAT_RETURN
-dapls_ib_qp_modify (
- IN DAPL_IA *ia_ptr,
- IN DAPL_EP *ep_ptr,
- IN DAT_EP_ATTR *ep_attr )
-{
- ib_qp_attr_t qp_attr;
- ib_api_status_t ib_status;
- ib_qp_handle_t qp_handle;
- ib_qp_state_t qp_state;
- ib_qp_mod_t qp_mod;
- ib_av_attr_t *p_av_attr;
- ib_qp_opts_t *p_qp_opts;
- uint32_t *p_sq_depth, *p_rq_depth;
- DAT_BOOLEAN need_modify;
- DAT_RETURN dat_status;
-
- qp_handle = ep_ptr->qp_handle;
- need_modify = DAT_FALSE;
- dat_status = DAT_SUCCESS;
- if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA )
- {
- dat_status = DAT_INVALID_HANDLE;
- goto bail;
- }
- /*
- * Query the QP to get the current state.
- */
- ib_status = ib_query_qp ( qp_handle, &qp_attr );
-
- if ( ib_status != IB_SUCCESS )
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIQM: Query QP failed = %s\n",
- ib_get_err_str(ib_status));
- dat_status = DAT_INTERNAL_ERROR;
- goto bail;
- }
-
- qp_state = qp_attr.state;
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM: modify qp state=%d\n",qp_state);
- /*
- * Check if we have the right qp_state or not
- */
- if ( (qp_state != IB_QPS_RTR ) && (qp_state != IB_QPS_RTS ) )
- {
- dapl_dbg_log (DAPL_DBG_TYPE_EP,
- "--> DsIQM: postpone to modify qp to EP values later\n");
- dat_status = DAT_SUCCESS;
- goto bail;
- }
-
- dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));
-
- if (qp_state == IB_QPS_RTR)
- {
- p_av_attr = &qp_mod.state.rtr.primary_av;
- p_qp_opts = &qp_mod.state.rtr.opts;
- p_sq_depth = &qp_mod.state.rtr.sq_depth;
- p_rq_depth = &qp_mod.state.rtr.rq_depth;
- }
- else
- {
- /*
- * RTS does not have primary_av field
- */
- p_av_attr = &qp_mod.state.rts.alternate_av;
- p_qp_opts = &qp_mod.state.rts.opts;
- p_sq_depth = &qp_mod.state.rts.sq_depth;
- p_rq_depth = &qp_mod.state.rts.rq_depth;
- }
-
- if ( (ep_attr->max_recv_dtos > 0) &&
- ((DAT_UINT32)ep_attr->max_recv_dtos != qp_attr.rq_depth) )
- {
- dapl_dbg_log (DAPL_DBG_TYPE_EP,"--> DsIQM: rq_depth modified (%d,%d)\n",
- qp_attr.rq_depth, ep_attr->max_recv_dtos);
-
- *p_rq_depth = ep_attr->max_recv_dtos;
- *p_qp_opts |= IB_MOD_QP_RQ_DEPTH;
- need_modify = DAT_TRUE;
- }
-
- if ( (ep_attr->max_request_dtos > 0) &&
- ((DAT_UINT32)ep_attr->max_request_dtos != qp_attr.sq_depth) )
- {
- dapl_dbg_log (DAPL_DBG_TYPE_EP,
- "--> DsIQM: sq_depth modified (%d,%d)\n",
- qp_attr.sq_depth, ep_attr->max_request_dtos);
-
- *p_sq_depth = ep_attr->max_request_dtos;
- *p_qp_opts |= IB_MOD_QP_SQ_DEPTH;
- need_modify = DAT_TRUE;
- }
-
- qp_mod.req_state = qp_state;
-
- if ( need_modify == DAT_TRUE )
- {
- ib_status = ib_modify_qp (qp_handle, &qp_mod);
- if ( ib_status != IB_SUCCESS)
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: ib_status = %d\n",
- "DsIQM", ib_status);
- dat_status = DAT_INTERNAL_ERROR;
- }
- }
-
-bail:
-
- return dat_status;
-}
-
-
-ib_api_status_t
-dapls_modify_qp_state_to_error ( ib_qp_handle_t qp_handle )
-{
- ib_qp_mod_t qp_mod;
- ib_api_status_t ib_status;
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_Err: QP state change --> Err\n");
-
- dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));
-
- qp_mod.req_state = IB_QPS_ERROR;
-
- ib_status = ib_modify_qp (qp_handle, &qp_mod);
-
- return (ib_status);
-}
-
-
-ib_api_status_t
-dapls_modify_qp_state_to_reset ( ib_qp_handle_t qp_handle )
-{
- ib_qp_mod_t qp_mod;
- ib_api_status_t ib_status;
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RESET: QP state change\n");
-
- dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));
-
- qp_mod.req_state = IB_QPS_RESET;
-
- ib_status = ib_modify_qp (qp_handle, &qp_mod);
-
- return (ib_status);
-}
-
-
-ib_api_status_t
-dapls_modify_qp_state_to_init (
- IN ib_qp_handle_t qp_handle,
- IN DAT_EP_ATTR *p_attr,
- IN dapl_ibal_port_t *p_port )
-{
- ib_qp_mod_t qp_mod;
- ib_api_status_t ib_status;
-
- dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));
-
- qp_mod.req_state = IB_QPS_INIT;
- qp_mod.state.init.primary_port = p_port->p_attr->port_num;
- qp_mod.state.init.qkey = DAPL_IBAL_QKEY;
- qp_mod.state.init.pkey_index = 0;
- qp_mod.state.init.access_ctrl = IB_AC_LOCAL_WRITE |
- IB_AC_RDMA_WRITE |
- IB_AC_MW_BIND |
- IB_AC_ATOMIC;
- if ((p_attr->max_rdma_read_in > 0) || (p_attr->max_rdma_read_out > 0))
- {
- qp_mod.state.init.access_ctrl |= IB_AC_RDMA_READ;
- }
- ib_status = ib_modify_qp (qp_handle, &qp_mod);
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_INIT: QP(%p) state change, %s\n",
- qp_handle, ib_get_err_str(ib_status));
-
- return (ib_status);
-}
-
-
-ib_api_status_t
-dapls_modify_qp_state_to_rtr (
- ib_qp_handle_t qp_handle,
- ib_net32_t dest_qp,
- ib_lid_t dest_lid,
- dapl_ibal_port_t *p_port)
-{
- ib_qp_mod_t qp_mod;
- ib_api_status_t ib_status;
-
- dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));
-
- qp_mod.req_state = IB_QPS_RTR;
- qp_mod.state.rtr.rq_psn = DAPL_IBAL_START_PSN;
- qp_mod.state.rtr.dest_qp = dest_qp;
- qp_mod.state.rtr.primary_av.port_num = p_port->p_attr->port_num;
- qp_mod.state.rtr.primary_av.sl = 0;
- qp_mod.state.rtr.primary_av.dlid = dest_lid;
- qp_mod.state.rtr.primary_av.grh_valid = 0; /* FALSE */
- qp_mod.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS;
- qp_mod.state.rtr.primary_av.path_bits = 0;
- qp_mod.state.rtr.primary_av.conn.path_mtu = p_port->p_attr->mtu;
- qp_mod.state.rtr.primary_av.conn.local_ack_timeout = 7;
- qp_mod.state.rtr.primary_av.conn.seq_err_retry_cnt = 7;
- qp_mod.state.rtr.primary_av.conn.rnr_retry_cnt = IB_RNR_RETRY_CNT;
- qp_mod.state.rtr.resp_res = 4; // in-flight RDMAs
- qp_mod.state.rtr.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT;
-
- ib_status = ib_modify_qp (qp_handle, &qp_mod);
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RTR: QP(%p) state change %s\n",
- qp_handle, ib_get_err_str(ib_status));
-
- return (ib_status);
-}
-
-ib_api_status_t
-dapls_modify_qp_state_to_rts ( ib_qp_handle_t qp_handle )
-{
- ib_qp_mod_t qp_mod;
- ib_api_status_t ib_status;
-
- dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));
-
- qp_mod.req_state = IB_QPS_RTS;
- qp_mod.state.rts.sq_psn = DAPL_IBAL_START_PSN;
- qp_mod.state.rts.retry_cnt = 7;
- qp_mod.state.rts.rnr_retry_cnt = IB_RNR_RETRY_CNT;
- qp_mod.state.rtr.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT;
- qp_mod.state.rts.local_ack_timeout = 7;
- qp_mod.state.rts.init_depth = 4;
-
- ib_status = ib_modify_qp (qp_handle, &qp_mod);
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RTS: QP(%p) state change %s\n",
- qp_handle, ib_get_err_str(ib_status));
-
- return (ib_status);
-}
-
-
-/*
- * dapls_ib_reinit_ep
- *
- * Move the QP to INIT state again.
- *
- * Input:
- * ep_ptr DAPL_EP
- *
- * Output:
- * none
- *
- * Returns:
- * void
- *
- */
-void
-dapls_ib_reinit_ep ( IN DAPL_EP *ep_ptr )
-{
- DAPL_IA *ia_ptr;
- ib_api_status_t ib_status;
- dapl_ibal_ca_t *p_ca;
- dapl_ibal_port_t *p_active_port;
-
- dapl_dbg_log (DAPL_DBG_TYPE_EP,
- "--> DsIQM_REINIT: EP(%p) QP(%p) state change\n",
- ep_ptr, ep_ptr->qp_handle );
-
- if ( ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED )
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIRE: EP invalid state(%d)\n",
- ep_ptr->param.ep_state);
- return /*DAT_INVALID_STATE*/;
- }
-
- ia_ptr = ep_ptr->header.owner_ia;
-
- /* Re-create QP if cleaned up, alloc will return init state */
- if ( ep_ptr->qp_handle == IB_INVALID_HANDLE )
- {
- dapl_dbg_log (DAPL_DBG_TYPE_EP,
- "--> DsIRE: !EP(%p)->qp_handle, re-create QP\n",ep_ptr);
- ib_status = dapls_ib_qp_alloc ( ia_ptr, ep_ptr, ep_ptr );
- if ( ib_status != IB_SUCCESS )
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DsIRE: failed to move qp to RESET status = %s\n",
- ib_get_err_str(ib_status));
- }
- return /*ib_status*/;
- }
-
- ib_status = dapls_modify_qp_state_to_reset (ep_ptr->qp_handle);
-
- if ( ib_status != IB_SUCCESS )
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DsIRE: failed to move qp to RESET status = %s\n",
- ib_get_err_str(ib_status));
- return /*DAT_INTERNAL_ERROR*/;
- }
-
- ep_ptr->qp_state = IB_QPS_RESET;
-
- p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle;
- p_active_port = dapli_ibal_get_port ( p_ca,
- (uint8_t)ia_ptr->hca_ptr->port_num );
- if (NULL == p_active_port)
- {
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DsIRE: Port %d is not available = %d\n",
- ia_ptr->hca_ptr->port_num, __LINE__);
- return /*DAT_INTERNAL_ERROR*/;
- }
-
- /* May fail if QP still RESET and in timewait, keep in reset state */
- ib_status = dapls_modify_qp_state_to_init ( ep_ptr->qp_handle,
- &ep_ptr->param.ep_attr,
- p_active_port);
- if ( ib_status != IB_SUCCESS )
- {
- ep_ptr->qp_state = IB_QPS_RESET;
-
- dapl_dbg_log (DAPL_DBG_TYPE_ERR,
- "--> DsIRE: failed to move qp to INIT status %s\n",
- ib_get_err_str(ib_status));
- return /*DAT_INTERNAL_ERROR*/;
- }
- ep_ptr->qp_state = IB_QPS_INIT;
-}
-
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * End:
- */
-
+\r
+/*\r
+ * Copyright (c) 2005-2007 Intel Corporation. All rights reserved.\r
+ * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. \r
+ * \r
+ * This Software is licensed under the terms of the "Common Public\r
+ * License" a copy of which is in the file LICENSE.txt in the root\r
+ * directory. The license is also available from the Open Source\r
+ * Initiative, see http://www.opensource.org/licenses/cpl.php.\r
+ *\r
+ */\r
+\r
+/**********************************************************************\r
+ * \r
+ * MODULE: dapl_ibal_qp.c\r
+ *\r
+ * PURPOSE: IB QP routines for access to IBAL APIs\r
+ *\r
+ * $Id: dapl_ibal_qp.c 33 2005-07-11 19:51:17Z ftillier $\r
+ *\r
+ **********************************************************************/\r
+\r
+#include "dapl.h"\r
+#include "dapl_adapter_util.h"\r
+#include "dapl_evd_util.h"\r
+#include "dapl_ibal_util.h"\r
+#include "dapl_ep_util.h"\r
+\r
+#define DAPL_IBAL_QKEY 0\r
+#define DAPL_IBAL_START_PSN 0\r
+\r
+extern DAT_RETURN\r
+dapls_ib_cq_late_alloc ( IN ib_pd_handle_t pd_handle,\r
+ IN DAPL_EVD *evd_ptr );\r
+\r
+static void\r
+dapli_ib_qp_async_error_cb( IN ib_async_event_rec_t* p_err_rec )\r
+{\r
+ DAPL_EP *ep_ptr = (DAPL_EP *)p_err_rec->context;\r
+ DAPL_EVD *evd_ptr;\r
+ DAPL_IA *ia_ptr;\r
+ dapl_ibal_ca_t *p_ca;\r
+ dapl_ibal_evd_cb_t *evd_cb;\r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC QP event %s qp ctx %p\n", \r
+ ib_get_async_event_str(p_err_rec->code), p_err_rec->context);\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC qp_handle %p qpn %u\n", \r
+ ((DAPL_EP *)p_err_rec->context)->qp_handle, \r
+ ((DAPL_EP *)p_err_rec->context)->qpn);\r
+\r
+ /*\r
+ * Verify handles EP, EVD, and hca_handle\r
+ */\r
+ if (DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) ||\r
+ DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD))\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DiQpAEC: invalid EP %p \n", ep_ptr);\r
+ return;\r
+ }\r
+ ia_ptr = ep_ptr->header.owner_ia;\r
+ evd_ptr = ia_ptr->async_error_evd;\r
+\r
+ if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD) ||\r
+ ! (evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG))\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DiQpAEC: invalid EVD %p \n", evd_ptr);\r
+ return;\r
+ }\r
+ p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle;\r
+ if (p_ca == NULL)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DiQpAEC: can't find %s HCA\n", \r
+ (ia_ptr->header.provider)->device_name);\r
+ return;\r
+ }\r
+\r
+ /* find QP error callback using ia_ptr for context */\r
+ evd_cb = dapli_find_evd_cb_by_context (ia_ptr, p_ca);\r
+ if ((evd_cb == NULL) || (evd_cb->pfn_async_qp_err_cb == NULL))\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DiQpAEC: no ERROR cb on p_ca %p found\n", p_ca);\r
+ return;\r
+ }\r
+\r
+ dapl_os_lock (&ep_ptr->header.lock);\r
+ ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING;\r
+ dapl_os_unlock (&ep_ptr->header.lock);\r
+\r
+ /* force disconnect, QP error state, to insure DTO's get flushed */\r
+ dapls_ib_disconnect ( ep_ptr, DAT_CLOSE_ABRUPT_FLAG );\r
+ \r
+ /* maps to dapl_evd_qp_async_error_callback(), context is EP */\r
+ evd_cb->pfn_async_qp_err_cb( (ib_hca_handle_t)p_ca, \r
+ ep_ptr->qp_handle,\r
+ (ib_error_record_t*)&p_err_rec->code,\r
+ ep_ptr );\r
+}\r
+\r
+/*\r
+ * dapls_ib_qp_alloc\r
+ *\r
+ * Alloc a QP\r
+ *\r
+ * Input:\r
+ * *ia_ptr pointer to DAPL IA\r
+ * *ep_ptr pointer to DAPL EP\r
+ * *ep_ctx_ptr pointer to DAPL EP context\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * DAT_SUCCESS\r
+ * DAT_INSUFFICIENT_RESOURCES\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_qp_alloc (\r
+ IN DAPL_IA *ia_ptr,\r
+ IN DAPL_EP *ep_ptr,\r
+ IN DAPL_EP *ep_ctx_ptr)\r
+{\r
+ DAT_EP_ATTR *attr;\r
+ DAPL_EVD *recv_evd_ptr, *request_evd_ptr;\r
+ DAT_RETURN dat_status;\r
+ ib_api_status_t ib_status;\r
+ ib_qp_create_t qp_create;\r
+ ib_pd_handle_t ib_pd_handle;\r
+ ib_cq_handle_t cq_recv;\r
+ ib_cq_handle_t cq_send;\r
+ dapl_ibal_ca_t *p_ca;\r
+ dapl_ibal_port_t *p_active_port;\r
+ ib_qp_attr_t qp_attr;\r
+ dp_ib_cm_handle_t cm_ptr;\r
+\r
+ attr = &ep_ptr->param.ep_attr;\r
+\r
+ dapl_os_assert ( ep_ptr->param.pz_handle != NULL );\r
+\r
+ ib_pd_handle = ((DAPL_PZ *)ep_ptr->param.pz_handle)->pd_handle;\r
+ dapl_os_assert(ib_pd_handle);\r
+ recv_evd_ptr = (DAPL_EVD *) ep_ptr->param.recv_evd_handle;\r
+ request_evd_ptr = (DAPL_EVD *) ep_ptr->param.request_evd_handle;\r
+ \r
+ cq_recv = IB_INVALID_HANDLE;\r
+ cq_send = IB_INVALID_HANDLE;\r
+\r
+ dapl_os_assert ( recv_evd_ptr != DAT_HANDLE_NULL );\r
+ {\r
+ cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle;\r
+ \r
+ if ((cq_recv == IB_INVALID_HANDLE) && \r
+ ( 0 != (recv_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) ))\r
+ {\r
+ dat_status = dapls_ib_cq_late_alloc ( ib_pd_handle, recv_evd_ptr);\r
+ if (dat_status != DAT_SUCCESS)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> %s: failed to create CQ\n","DsQA");\r
+ return (dat_status);\r
+ }\r
+\r
+ dat_status = dapls_set_cq_notify (ia_ptr, recv_evd_ptr);\r
+\r
+ if (dat_status != DAT_SUCCESS)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> %s: failed to enable notify CQ\n","DsQA");\r
+ return (dat_status);\r
+ }\r
+ \r
+ cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle;\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, \r
+ "--> DsQA: alloc_recv_CQ = %p\n", cq_recv); \r
+ \r
+ }\r
+ }\r
+\r
+ dapl_os_assert ( request_evd_ptr != DAT_HANDLE_NULL );\r
+ {\r
+ cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle;\r
+ \r
+ if ((cq_send == IB_INVALID_HANDLE) && \r
+ ( 0 != (request_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) ))\r
+ {\r
+ dat_status = dapls_ib_cq_late_alloc (ib_pd_handle, request_evd_ptr);\r
+ if (dat_status != DAT_SUCCESS)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> %s: failed to create CQ\n","DsQA");\r
+ return (dat_status);\r
+ }\r
+\r
+ dat_status = dapls_set_cq_notify (ia_ptr, request_evd_ptr);\r
+\r
+ if (dat_status != DAT_SUCCESS)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> %s: failed to enable notify CQ\n","DsQA");\r
+ return (dat_status);\r
+ }\r
+\r
+ cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle;\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, \r
+ "--> DsQA: alloc_send_CQ = %p\n", cq_send); \r
+ }\r
+ }\r
+\r
+ /*\r
+ * Get the CA structure\r
+ */\r
+ p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle;\r
+\r
+ dapl_os_memzero (&qp_create, sizeof (qp_create));\r
+ qp_create.qp_type = IB_QPT_RELIABLE_CONN;\r
+ qp_create.sq_depth = attr->max_request_dtos;\r
+ qp_create.rq_depth = attr->max_recv_dtos;\r
+ qp_create.sq_sge = attr->max_recv_iov;\r
+ qp_create.rq_sge = attr->max_request_iov; \r
+ qp_create.h_sq_cq = cq_send;\r
+ qp_create.h_rq_cq = cq_recv;\r
+ qp_create.sq_signaled = FALSE;\r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, \r
+ "--> DsQA: sqd,iov=%d,%d rqd,iov=%d,%d\n", \r
+ attr->max_request_dtos, attr->max_request_iov,\r
+ attr->max_recv_dtos, attr->max_recv_iov); \r
+ \r
+ ib_status = ib_create_qp ( \r
+ ib_pd_handle,\r
+ &qp_create,\r
+ (void *) ep_ctx_ptr /* context */,\r
+ dapli_ib_qp_async_error_cb,\r
+ &ep_ptr->qp_handle);\r
+\r
+ if (ib_status != IB_SUCCESS)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsQA: Create QP failed = %s\n",\r
+ ib_get_err_str(ib_status));\r
+ return (DAT_INSUFFICIENT_RESOURCES);\r
+ }\r
+ /* EP-CM linking */\r
+ cm_ptr = ibal_cm_alloc();\r
+ if (!cm_ptr) \r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsQA: Create CM failed\n");\r
+ return (DAT_INSUFFICIENT_RESOURCES);\r
+ }\r
+ cm_ptr->ib_cm.h_qp = ep_ptr->qp_handle;\r
+ cm_ptr->ep = ep_ptr;\r
+ dapl_ep_link_cm(ep_ptr, cm_ptr); \r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQA: EP=%p, tEVD=%p, rEVD=%p QP=%p\n",\r
+ ep_ptr, ep_ptr->param.request_evd_handle,\r
+ ep_ptr->param.recv_evd_handle,\r
+ ep_ptr->qp_handle ); \r
+\r
+ ep_ptr->qp_state = IB_QPS_RESET;\r
+\r
+ p_active_port = dapli_ibal_get_port(p_ca,(uint8_t)ia_ptr->hca_ptr->port_num);\r
+\r
+ if (NULL == p_active_port)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DsQA: Port %d is not available = %d\n",\r
+ ia_ptr->hca_ptr->port_num, __LINE__);\r
+ return (DAT_INVALID_STATE);\r
+ }\r
+\r
+ ib_status = dapls_modify_qp_state_to_init ( ep_ptr->qp_handle, \r
+ &ep_ptr->param.ep_attr,\r
+ p_active_port );\r
+\r
+ if ( ib_status != IB_SUCCESS )\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DsQA: Change QP state to INIT failed = %s\n",\r
+ ib_get_err_str(ib_status));\r
+ return (DAT_INVALID_HANDLE);\r
+ }\r
+ ib_status = ib_query_qp ( ep_ptr->qp_handle, &qp_attr );\r
+\r
+ ep_ptr->qp_state = qp_attr.state;\r
+ ep_ptr->qpn = qp_attr.num;\r
+ \r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQAQA: EP:%p new_QP %p state %s\n",\r
+ ep_ptr,\r
+ ep_ptr->qp_handle,\r
+ ib_get_port_state_str(ep_ptr->qp_state));\r
+\r
+ return (DAT_SUCCESS);\r
+}\r
+\r
+\r
+/*\r
+ * dapls_ib_qp_free\r
+ *\r
+ * Free a QP\r
+ *\r
+ * Input:\r
+ * *ia_ptr pointer to IA structure\r
+ * *ep_ptr pointer to EP structure\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * none\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_qp_free (\r
+ IN DAPL_IA *ia_ptr,\r
+ IN DAPL_EP *ep_ptr )\r
+{\r
+\r
+ ib_qp_handle_t qp_handle;\r
+ UNREFERENCED_PARAMETER(ia_ptr);\r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQF: free %p, state %s\n", \r
+ ep_ptr->qp_handle,\r
+ ib_get_port_state_str(ep_ptr->qp_state));\r
+\r
+ if (( ep_ptr->qp_handle != IB_INVALID_HANDLE ) &&\r
+ ( ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED ))\r
+ {\r
+ qp_handle = ep_ptr->qp_handle;\r
+ ep_ptr->qp_handle = IB_INVALID_HANDLE;\r
+ ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED;\r
+ ib_destroy_qp ( qp_handle, NULL /* callback */);\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQF: freed QP %p\n",\r
+ qp_handle ); \r
+ }\r
+\r
+ return DAT_SUCCESS;\r
+}\r
+\r
+\r
+/*\r
+ * dapls_ib_qp_modify\r
+ *\r
+ * Set the QP to the parameters specified in an EP_PARAM\r
+ *\r
+ * We can't be sure what state the QP is in so we first obtain the state\r
+ * from the driver. The EP_PARAM structure that is provided has been\r
+ * sanitized such that only non-zero values are valid.\r
+ *\r
+ * Input:\r
+ * *ia_ptr pointer to DAPL IA\r
+ * *ep_ptr pointer to DAPL EP\r
+ * *ep_attr pointer to DAT EP attribute\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * DAT_SUCCESS\r
+ * DAT_INSUFFICIENT_RESOURCES\r
+ * DAT_INVALID_PARAMETER\r
+ *\r
+ */\r
+DAT_RETURN\r
+dapls_ib_qp_modify (\r
+ IN DAPL_IA *ia_ptr,\r
+ IN DAPL_EP *ep_ptr,\r
+ IN DAT_EP_ATTR *ep_attr )\r
+{\r
+ ib_qp_attr_t qp_attr;\r
+ ib_api_status_t ib_status;\r
+ ib_qp_handle_t qp_handle;\r
+ ib_qp_state_t qp_state;\r
+ ib_qp_mod_t qp_mod;\r
+ ib_av_attr_t *p_av_attr;\r
+ ib_qp_opts_t *p_qp_opts;\r
+ uint32_t *p_sq_depth, *p_rq_depth;\r
+ DAT_BOOLEAN need_modify;\r
+ DAT_RETURN dat_status;\r
+\r
+ qp_handle = ep_ptr->qp_handle;\r
+ need_modify = DAT_FALSE;\r
+ dat_status = DAT_SUCCESS;\r
+ if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA )\r
+ {\r
+ dat_status = DAT_INVALID_HANDLE;\r
+ goto bail;\r
+ }\r
+ /* \r
+ * Query the QP to get the current state.\r
+ */\r
+ ib_status = ib_query_qp ( qp_handle, &qp_attr );\r
+ \r
+ if ( ib_status != IB_SUCCESS )\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIQM: Query QP failed = %s\n",\r
+ ib_get_err_str(ib_status));\r
+ dat_status = DAT_INTERNAL_ERROR;\r
+ goto bail;\r
+ }\r
+\r
+ qp_state = qp_attr.state;\r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM: modify qp state=%d\n",qp_state);\r
+ /*\r
+ * Check if we have the right qp_state or not\r
+ */\r
+ if ( (qp_state != IB_QPS_RTR ) && (qp_state != IB_QPS_RTS ) )\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP,\r
+ "--> DsIQM: postpone to modify qp to EP values later\n");\r
+ dat_status = DAT_SUCCESS;\r
+ goto bail;\r
+ }\r
+\r
+ dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));\r
+\r
+ if (qp_state == IB_QPS_RTR)\r
+ {\r
+ p_av_attr = &qp_mod.state.rtr.primary_av;\r
+ p_qp_opts = &qp_mod.state.rtr.opts;\r
+ p_sq_depth = &qp_mod.state.rtr.sq_depth;\r
+ p_rq_depth = &qp_mod.state.rtr.rq_depth;\r
+ }\r
+ else\r
+ {\r
+ /*\r
+ * RTS does not have primary_av field\r
+ */\r
+ p_av_attr = &qp_mod.state.rts.alternate_av;\r
+ p_qp_opts = &qp_mod.state.rts.opts;\r
+ p_sq_depth = &qp_mod.state.rts.sq_depth;\r
+ p_rq_depth = &qp_mod.state.rts.rq_depth;\r
+ }\r
+\r
+ if ( (ep_attr->max_recv_dtos > 0) &&\r
+ ((DAT_UINT32)ep_attr->max_recv_dtos != qp_attr.rq_depth) )\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP,"--> DsIQM: rq_depth modified (%d,%d)\n",\r
+ qp_attr.rq_depth, ep_attr->max_recv_dtos);\r
+\r
+ *p_rq_depth = ep_attr->max_recv_dtos;\r
+ *p_qp_opts |= IB_MOD_QP_RQ_DEPTH;\r
+ need_modify = DAT_TRUE;\r
+ }\r
+\r
+ if ( (ep_attr->max_request_dtos > 0) &&\r
+ ((DAT_UINT32)ep_attr->max_request_dtos != qp_attr.sq_depth) ) \r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP,\r
+ "--> DsIQM: sq_depth modified (%d,%d)\n",\r
+ qp_attr.sq_depth, ep_attr->max_request_dtos);\r
+\r
+ *p_sq_depth = ep_attr->max_request_dtos;\r
+ *p_qp_opts |= IB_MOD_QP_SQ_DEPTH;\r
+ need_modify = DAT_TRUE;\r
+ }\r
+\r
+ qp_mod.req_state = qp_state;\r
+\r
+ if ( need_modify == DAT_TRUE )\r
+ {\r
+ ib_status = ib_modify_qp (qp_handle, &qp_mod);\r
+ if ( ib_status != IB_SUCCESS)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: ib_status = %d\n",\r
+ "DsIQM", ib_status);\r
+ dat_status = DAT_INTERNAL_ERROR;\r
+ }\r
+ }\r
+\r
+bail:\r
+\r
+ return dat_status;\r
+}\r
+\r
+\r
+ib_api_status_t \r
+dapls_modify_qp_state_to_error ( ib_qp_handle_t qp_handle )\r
+{\r
+ ib_qp_mod_t qp_mod;\r
+ ib_api_status_t ib_status;\r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_Err: QP state change --> Err\n");\r
+\r
+ dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));\r
+\r
+ qp_mod.req_state = IB_QPS_ERROR;\r
+\r
+ ib_status = ib_modify_qp (qp_handle, &qp_mod);\r
+\r
+ return (ib_status);\r
+}\r
+\r
+\r
+ib_api_status_t \r
+dapls_modify_qp_state_to_reset ( ib_qp_handle_t qp_handle )\r
+{\r
+ ib_qp_mod_t qp_mod;\r
+ ib_api_status_t ib_status;\r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RESET: QP state change\n");\r
+\r
+ dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));\r
+\r
+ qp_mod.req_state = IB_QPS_RESET;\r
+\r
+ ib_status = ib_modify_qp (qp_handle, &qp_mod);\r
+\r
+ return (ib_status);\r
+}\r
+\r
+\r
+ib_api_status_t \r
+dapls_modify_qp_state_to_init (\r
+ IN ib_qp_handle_t qp_handle,\r
+ IN DAT_EP_ATTR *p_attr,\r
+ IN dapl_ibal_port_t *p_port )\r
+{\r
+ ib_qp_mod_t qp_mod;\r
+ ib_api_status_t ib_status;\r
+\r
+ dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));\r
+\r
+ qp_mod.req_state = IB_QPS_INIT;\r
+ qp_mod.state.init.primary_port = p_port->p_attr->port_num;\r
+ qp_mod.state.init.qkey = DAPL_IBAL_QKEY;\r
+ qp_mod.state.init.pkey_index = 0;\r
+ qp_mod.state.init.access_ctrl = IB_AC_LOCAL_WRITE |\r
+ IB_AC_RDMA_WRITE |\r
+ IB_AC_MW_BIND |\r
+ IB_AC_ATOMIC;\r
+ if ((p_attr->max_rdma_read_in > 0) || (p_attr->max_rdma_read_out > 0))\r
+ {\r
+ qp_mod.state.init.access_ctrl |= IB_AC_RDMA_READ;\r
+ }\r
+ ib_status = ib_modify_qp (qp_handle, &qp_mod);\r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_INIT: QP(%p) state change, %s\n",\r
+ qp_handle, ib_get_err_str(ib_status));\r
+\r
+ return (ib_status);\r
+}\r
+\r
+\r
+ib_api_status_t \r
+dapls_modify_qp_state_to_rtr (\r
+ ib_qp_handle_t qp_handle,\r
+ ib_net32_t dest_qp,\r
+ ib_lid_t dest_lid,\r
+ dapl_ibal_port_t *p_port)\r
+{\r
+ ib_qp_mod_t qp_mod;\r
+ ib_api_status_t ib_status;\r
+\r
+ dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));\r
+\r
+ qp_mod.req_state = IB_QPS_RTR;\r
+ qp_mod.state.rtr.rq_psn = DAPL_IBAL_START_PSN;\r
+ qp_mod.state.rtr.dest_qp = dest_qp;\r
+ qp_mod.state.rtr.primary_av.port_num = p_port->p_attr->port_num;\r
+ qp_mod.state.rtr.primary_av.sl = 0;\r
+ qp_mod.state.rtr.primary_av.dlid = dest_lid;\r
+ qp_mod.state.rtr.primary_av.grh_valid = 0; /* FALSE */\r
+ qp_mod.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS;\r
+ qp_mod.state.rtr.primary_av.path_bits = 0;\r
+ qp_mod.state.rtr.primary_av.conn.path_mtu = p_port->p_attr->mtu;\r
+ qp_mod.state.rtr.primary_av.conn.local_ack_timeout = 7;\r
+ qp_mod.state.rtr.primary_av.conn.seq_err_retry_cnt = 7;\r
+ qp_mod.state.rtr.primary_av.conn.rnr_retry_cnt = IB_RNR_RETRY_CNT;\r
+ qp_mod.state.rtr.resp_res = 4; // in-flight RDMAs\r
+ qp_mod.state.rtr.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT;\r
+ \r
+ ib_status = ib_modify_qp (qp_handle, &qp_mod);\r
+ \r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RTR: QP(%p) state change %s\n",\r
+ qp_handle, ib_get_err_str(ib_status));\r
+\r
+ return (ib_status);\r
+}\r
+\r
+ib_api_status_t \r
+dapls_modify_qp_state_to_rts ( ib_qp_handle_t qp_handle )\r
+{\r
+ ib_qp_mod_t qp_mod;\r
+ ib_api_status_t ib_status;\r
+\r
+ dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t));\r
+\r
+ qp_mod.req_state = IB_QPS_RTS;\r
+ qp_mod.state.rts.sq_psn = DAPL_IBAL_START_PSN;\r
+ qp_mod.state.rts.retry_cnt = 7;\r
+ qp_mod.state.rts.rnr_retry_cnt = IB_RNR_RETRY_CNT;\r
+ qp_mod.state.rtr.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT;\r
+ qp_mod.state.rts.local_ack_timeout = 7;\r
+ qp_mod.state.rts.init_depth = 4; \r
+\r
+ ib_status = ib_modify_qp (qp_handle, &qp_mod);\r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RTS: QP(%p) state change %s\n",\r
+ qp_handle, ib_get_err_str(ib_status));\r
+\r
+ return (ib_status);\r
+}\r
+\r
+\r
+/*\r
+ * dapls_ib_reinit_ep\r
+ *\r
+ * Move the QP to INIT state again.\r
+ *\r
+ * Input:\r
+ * ep_ptr DAPL_EP\r
+ *\r
+ * Output:\r
+ * none\r
+ *\r
+ * Returns:\r
+ * void\r
+ *\r
+ */\r
+void\r
+dapls_ib_reinit_ep ( IN DAPL_EP *ep_ptr )\r
+{\r
+ DAPL_IA *ia_ptr;\r
+ ib_api_status_t ib_status;\r
+ dapl_ibal_ca_t *p_ca;\r
+ dapl_ibal_port_t *p_active_port;\r
+ \r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP,\r
+ "--> DsIQM_REINIT: EP(%p) QP(%p) state change\n", \r
+ ep_ptr, ep_ptr->qp_handle );\r
+\r
+ if ( ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED )\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIRE: EP invalid state(%d)\n",\r
+ ep_ptr->param.ep_state);\r
+ return /*DAT_INVALID_STATE*/;\r
+ }\r
+\r
+ ia_ptr = ep_ptr->header.owner_ia;\r
+\r
+ /* Re-create QP if cleaned up, alloc will return init state */\r
+ if ( ep_ptr->qp_handle == IB_INVALID_HANDLE )\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_EP,\r
+ "--> DsIRE: !EP(%p)->qp_handle, re-create QP\n",ep_ptr);\r
+ ib_status = dapls_ib_qp_alloc ( ia_ptr, ep_ptr, ep_ptr );\r
+ if ( ib_status != IB_SUCCESS )\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DsIRE: failed to move qp to RESET status = %s\n", \r
+ ib_get_err_str(ib_status));\r
+ }\r
+ return /*ib_status*/;\r
+ }\r
+\r
+ ib_status = dapls_modify_qp_state_to_reset (ep_ptr->qp_handle);\r
+\r
+ if ( ib_status != IB_SUCCESS )\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DsIRE: failed to move qp to RESET status = %s\n", \r
+ ib_get_err_str(ib_status));\r
+ return /*DAT_INTERNAL_ERROR*/;\r
+ }\r
+\r
+ ep_ptr->qp_state = IB_QPS_RESET;\r
+\r
+ p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle;\r
+ p_active_port = dapli_ibal_get_port ( p_ca,\r
+ (uint8_t)ia_ptr->hca_ptr->port_num );\r
+ if (NULL == p_active_port)\r
+ {\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DsIRE: Port %d is not available = %d\n",\r
+ ia_ptr->hca_ptr->port_num, __LINE__);\r
+ return /*DAT_INTERNAL_ERROR*/;\r
+ }\r
+\r
+ /* May fail if QP still RESET and in timewait, keep in reset state */\r
+ ib_status = dapls_modify_qp_state_to_init ( ep_ptr->qp_handle,\r
+ &ep_ptr->param.ep_attr,\r
+ p_active_port);\r
+ if ( ib_status != IB_SUCCESS )\r
+ {\r
+ ep_ptr->qp_state = IB_QPS_RESET;\r
+\r
+ dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
+ "--> DsIRE: failed to move qp to INIT status %s\n", \r
+ ib_get_err_str(ib_status));\r
+ return /*DAT_INTERNAL_ERROR*/;\r
+ }\r
+ ep_ptr->qp_state = IB_QPS_INIT;\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
+\r
-
-/*
- * Copyright (c) 2005-2007 Intel Corporation. All rights reserved.
- * Copyright (c) 2002, Network Appliance, Inc. All rights reserved.
- *
- * This Software is licensed under the terms of the "Common Public
- * License" a copy of which is in the file LICENSE.txt in the root
- * directory. The license is also available from the Open Source
- * Initiative, see http://www.opensource.org/licenses/cpl.php.
- *
- */
-
-/**********************************************************************
- *
- * MODULE: dapl_ibal_util.h
- *
- * PURPOSE: Utility defs & routines for access to openib-windows IBAL APIs
- *
- * $Id: dapl_ibal_util.h 33 2005-07-11 19:51:17Z ftillier $
- *
- **********************************************************************/
-
-#ifndef _DAPL_IBAL_UTIL_H_
-#define _DAPL_IBAL_UTIL_H_
-
-#include <iba/ib_al.h>
-#include <complib/cl_spinlock.h>
-#include <complib/cl_qlist.h>
-#include <complib/cl_atomic.h>
-
-#ifdef DAT_EXTENSIONS
-#include <dat2\dat_ib_extensions.h>
-#endif
-
-/*
- * Typedefs to map IBAL types to more generic 'ib' types
- */
-#ifdef SOCK_CM
-typedef struct ib_cm_handle *dp_ib_cm_handle_t;
-typedef struct ib_cm_handle *ib_cm_srvc_handle_t;
-#else
-typedef ib_cm_handle_t *dp_ib_cm_handle_t;
-typedef ib_listen_handle_t ib_cm_srvc_handle_t;
-#endif
-
-typedef ib_net64_t IB_HCA_NAME;
-typedef ib_ca_handle_t ib_hca_handle_t;
-typedef DAT_PVOID ib_cqd_handle_t;
-typedef ib_async_event_rec_t ib_error_record_t;
-typedef ib_wr_type_t ib_send_op_type_t;
-typedef ib_wc_t ib_work_completion_t;
-typedef uint32_t ib_hca_port_t;
-typedef uint32_t ib_uint32_t;
-typedef ib_local_ds_t ib_data_segment_t;
-
-typedef unsigned __int3264 cl_dev_handle_t;
-
-
-typedef void (*ib_async_handler_t)(
- IN ib_hca_handle_t ib_hca_handle,
- IN ib_error_record_t *err_code,
- IN void *context);
-
-typedef void (*ib_async_qp_handler_t)(
- IN ib_hca_handle_t ib_hca_handle,
- IN ib_qp_handle_t ib_qp_handle,
- IN ib_error_record_t *err_code,
- IN void *context);
-
-typedef void (*ib_async_cq_handler_t)(
- IN ib_hca_handle_t ib_hca_handle,
- IN ib_cq_handle_t ib_cq_handle,
- IN ib_error_record_t *err_code,
- IN void *context);
-
-typedef ib_net64_t ib_guid_t;
-typedef ib_net16_t ib_lid_t;
-typedef boolean_t ib_bool_t;
-
-typedef struct _GID
-{
- uint64_t gid_prefix;
- uint64_t guid;
-} GID;
-
-typedef enum
-{
- IB_CME_CONNECTED,
- IB_CME_DISCONNECTED,
- IB_CME_DISCONNECTED_ON_LINK_DOWN,
- IB_CME_CONNECTION_REQUEST_PENDING,
- IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA,
- IB_CME_DESTINATION_REJECT,
- IB_CME_DESTINATION_REJECT_PRIVATE_DATA,
- IB_CME_DESTINATION_UNREACHABLE,
- IB_CME_TOO_MANY_CONNECTION_REQUESTS,
- IB_CME_LOCAL_FAILURE,
- IB_CME_REPLY_RECEIVED,
- IB_CME_REPLY_RECEIVED_PRIVATE_DATA,
- IB_CM_LOCAL_FAILURE
-} ib_cm_events_t;
-
-
-typedef enum
-{
- IB_NOTIFY_ON_NEXT_COMP,
- IB_NOTIFY_ON_SOLIC_COMP
-} ib_notification_type_t;
-
-typedef struct _ib_hca_name
-{
- DAT_NAME_PTR hca_name[DAT_NAME_MAX_LENGTH];
-} ib_hca_name_t;
-
-
-#define IB_INVALID_HANDLE NULL
-#define true TRUE
-#define false FALSE
-
-#define IB_MAX_REQ_PDATA_SIZE 92
-#define IB_MAX_REP_PDATA_SIZE 196
-#define IB_MAX_REJ_PDATA_SIZE 148
-#define IB_MAX_DREQ_PDATA_SIZE 220
-#define IB_MAX_DREP_PDATA_SIZE 224
-
-
-/* Resource Not Ready
- 1-6 is an actual retry count which is decremented to zero before
- an error condition is set.
- 7 is 'magic' in that it implies Infinite retry, just keeps trying.
-*/
-#define IB_RNR_RETRY_CNT 7
-
-/*
-IB 1.2 spec, page 331, table 45, RNR NAK timeout encoding (5-bits)
-
-00000=655.36ms(milliseconds)
-00001=0.01ms
-00010=0.02ms
-00011=0.03ms
-00100=0.04ms
-00101=0.06ms
-00110=0.08ms
-00111=0.12ms
-
-11100=163.84ms 28d
-11101=245.76ms 29d
-11110=327.68ms 30d
-11111=491.52ms 31d
-*/
-#define IB_RNR_NAK_TIMEOUT 0
-
-
-typedef void
-(*dapl_ibal_pfn_destructor_t)(
- IN void* context );
-
-typedef struct _dapl_ibal_refs
-{
- atomic32_t count; // number of references
- void* context; // context for destructor
- dapl_ibal_pfn_destructor_t destructor; // called when reference goes to zero
-
-} dapl_ibal_refs_t;
-
-
-typedef struct _dapl_ibal_root
-{
- ib_al_handle_t h_al; // handle to Access Layer
- cl_spinlock_t ca_lock; // CA list lock
- cl_qlist_t ca_head; // list head of CAs
- boolean_t shutdown; // when true, driver is shutting down
- boolean_t initialized; // when true, lib is initialized
-
-} dapl_ibal_root_t;
-
-
-typedef struct _dapl_ibal_ca
-{
- cl_list_item_t next; // peer CA list
- ib_ca_handle_t h_ca; // handle to open CA
- ib_ca_attr_t *p_ca_attr; // CA attributes
- uint32_t ca_attr_size;// size of ca attribute
- dapl_ibal_refs_t refs; // reference counting
- cl_spinlock_t port_lock; // port list lock
- cl_qlist_t port_head; // port list head for this CA
- cl_spinlock_t evd_cb_lock; // EVD async error cb list lock
- cl_qlist_t evd_cb_head; // EVD async error cb list head for this CA
- cl_dev_handle_t mlnx_device;
- DAT_PVOID *ia_ptr; // hook for CA async callbacks
-} dapl_ibal_ca_t;
-
-
-typedef struct _dapl_ibal_port
-{
- cl_list_item_t next; // peer CA list
- dapl_ibal_ca_t *ca; // pointer to parent CA
- ib_port_attr_t *p_attr; // port attributes
- dapl_ibal_refs_t refs; // reference counting
-} dapl_ibal_port_t;
-
-typedef struct _dapl_ibal_evd_cb
-{
- cl_list_item_t next; // peer CA list
- ib_async_handler_t pfn_async_err_cb;
- ib_async_qp_handler_t pfn_async_qp_err_cb;
- ib_async_cq_handler_t pfn_async_cq_err_cb;
- void *context;
-} dapl_ibal_evd_cb_t;
-
-/*
- * Definitions to map DTO OPs to IBAL Work-Request ops.
- */
-#define OP_BAD_OPCODE 0
-#define OP_RDMA_READ WR_RDMA_READ
-#define OP_RDMA_WRITE WR_RDMA_WRITE
-#define OP_SEND WR_SEND
-#define OP_COMP_AND_SWAP WR_COMPARE_SWAP
-#define OP_FETCH_AND_ADD WR_FETCH_ADD
-
-#define OP_RECEIVE 8 /* (8) */
-#define OP_BIND_MW 9 /* no-equivalent */
-#define OP_RDMA_WRITE_IMM 10 /* RDMA_WRITE+Immediate data */
-#define OP_RECEIVE_IMM 11 /* no-equivalent */
-
-/*
- * Definitions to map QP state
- */
-#define IB_QP_STATE_RESET IB_QPS_RESET
-#define IB_QP_STATE_INIT IB_QPS_INIT
-#define IB_QP_STATE_RTR IB_QPS_RTR
-#define IB_QP_STATE_RTS IB_QPS_RTS
-#define IB_QP_STATE_SQE IB_QPS_SQERR
-#define IB_QP_STATE_SQD IB_QPS_SQD
-#define IB_QP_STATE_ERROR IB_QPS_ERROR
-
-/*
- * Definitions to map Memory OPs
- */
-#define IB_ACCESS_LOCAL_WRITE IB_AC_LOCAL_WRITE
-#define IB_ACCESS_REMOTE_READ IB_AC_RDMA_READ
-#define IB_ACCESS_REMOTE_WRITE IB_AC_RDMA_WRITE
-#define IB_ACCESS_REMOTE_ATOMIC IB_AC_ATOMIC
-#define IB_ACCESS_MEM_WINDOW_BIND IB_AC_MW_BIND
-
-/*
- * CQE status
- */
-enum _dapl_comp_status
-{
- IB_COMP_ST_SUCCESS = IB_WCS_SUCCESS,
- IB_COMP_ST_LOCAL_LEN_ERR = IB_WCS_LOCAL_LEN_ERR,
- IB_COMP_ST_LOCAL_OP_ERR = IB_WCS_LOCAL_OP_ERR,
- IB_COMP_ST_LOCAL_PROTECT_ERR = IB_WCS_LOCAL_PROTECTION_ERR,
- IB_COMP_ST_WR_FLUSHED_ERR = IB_WCS_WR_FLUSHED_ERR,
- IB_COMP_ST_MW_BIND_ERR = IB_WCS_MEM_WINDOW_BIND_ERR,
- IB_COMP_ST_REM_ACC_ERR = IB_WCS_REM_ACCESS_ERR,
- IB_COMP_ST_REM_OP_ERR = IB_WCS_REM_OP_ERR,
- IB_COMP_ST_RNR_COUNTER = IB_WCS_RNR_RETRY_ERR,
- IB_COMP_ST_TRANSP_COUNTER = IB_WCS_TIMEOUT_RETRY_ERR,
- IB_COMP_ST_REM_REQ_ERR = IB_WCS_REM_INVALID_REQ_ERR,
- IB_COMP_ST_BAD_RESPONSE_ERR = IB_WCS_UNMATCHED_RESPONSE,
- IB_COMP_ST_EE_STATE_ERR,
- IB_COMP_ST_EE_CTX_NO_ERR
-};
-
-
-/*
- * Macro to check the state of an EP/QP
- */
-#define DAPLIB_NEEDS_INIT(ep) ((ep)->qp_state == IB_QPS_ERROR)
-
-
-/*
- * Resolve IBAL return codes to their DAPL equivelent.
- * Do not return invalid Handles, the user is not able
- * to deal with them.
- */
-STATIC _INLINE_ DAT_RETURN
-dapl_ib_status_convert (
- IN int32_t ib_status)
-{
- switch ( ib_status )
- {
- case IB_SUCCESS:
- {
- return DAT_SUCCESS;
- }
- case IB_INSUFFICIENT_RESOURCES:
- case IB_INSUFFICIENT_MEMORY:
- case IB_RESOURCE_BUSY:
- {
- return DAT_INSUFFICIENT_RESOURCES;
- }
- case IB_INVALID_CA_HANDLE:
- case IB_INVALID_CQ_HANDLE:
- case IB_INVALID_QP_HANDLE:
- case IB_INVALID_PD_HANDLE:
- case IB_INVALID_MR_HANDLE:
- case IB_INVALID_MW_HANDLE:
- case IB_INVALID_AL_HANDLE:
- case IB_INVALID_AV_HANDLE:
- {
- return DAT_INVALID_HANDLE;
- }
- case IB_INVALID_PKEY:
- {
- return DAT_PROTECTION_VIOLATION;
- }
- case IB_INVALID_LKEY:
- case IB_INVALID_RKEY:
- case IB_INVALID_PERMISSION:
- {
- return DAT_PRIVILEGES_VIOLATION;
- }
- case IB_INVALID_MAX_WRS:
- case IB_INVALID_MAX_SGE:
- case IB_INVALID_CQ_SIZE:
- case IB_INVALID_SETTING:
- case IB_INVALID_SERVICE_TYPE:
- case IB_INVALID_GID:
- case IB_INVALID_LID:
- case IB_INVALID_GUID:
- case IB_INVALID_PARAMETER:
- {
- return DAT_INVALID_PARAMETER;
- }
- case IB_INVALID_QP_STATE:
- case IB_INVALID_APM_STATE:
- case IB_INVALID_PORT_STATE:
- case IB_INVALID_STATE:
- {
- return DAT_INVALID_STATE;
- }
- case IB_NOT_FOUND:
- {
- return DAT_QUEUE_EMPTY;
- }
- case IB_OVERFLOW:
- {
- return DAT_QUEUE_FULL;
- }
- case IB_UNSUPPORTED:
- {
- return DAT_NOT_IMPLEMENTED;
- }
- case IB_TIMEOUT:
- {
- return DAT_TIMEOUT_EXPIRED;
- }
- case IB_CANCELED:
- {
- return DAT_ABORT;
- }
- default:
- {
- return DAT_INTERNAL_ERROR;
- }
- }
-}
-
-#define TAKE_LOCK( lock ) \
- cl_spinlock_acquire( &(lock) )
-
-#define RELEASE_LOCK( lock ) \
- cl_spinlock_release( &(lock) )
-
-#define LOCK_INSERT_HEAD( lock, head, item ) \
-{ \
- TAKE_LOCK( lock ); \
- cl_qlist_insert_head( &head, (cl_list_item_t*)(&item) ); \
- RELEASE_LOCK( lock ); \
-}
-
-#define LOCK_INSERT_TAIL( lock, tail, item ) \
-{ \
- TAKE_LOCK( lock ); \
- cl_qlist_insert_tail( &tail, (cl_list_item_t*)(&item) ); \
- RELEASE_LOCK( lock ); \
-}
-
-#define INIT_REFERENCE( p_ref, n, con, destruct ) \
-{ \
- (p_ref)->count = n; \
- (p_ref)->context = con; \
- (p_ref)->destructor = destruct; \
-}
-
-#define TAKE_REFERENCE( p_ref ) \
- cl_atomic_inc( &(p_ref)->count )
-
-#define REMOVE_REFERENCE( p_ref ) \
-{ \
- if ( cl_atomic_dec( &(p_ref)->count ) == 0 ) \
- if ( (p_ref)->destructor ) \
- (p_ref)->destructor( (p_ref)->context ); \
-}
-
-/*
- * dapl_llist_entry in dapl.h but dapl.h depends on provider
- * typedef's in this file first. move dapl_llist_entry out of dapl.h
- */
-struct ib_llist_entry
-{
- struct dapl_llist_entry *flink;
- struct dapl_llist_entry *blink;
- void *data;
- struct dapl_llist_entry *list_head;
-};
-
-#ifdef SOCK_CM
-
-typedef enum
-{
- IB_THREAD_INIT,
- IB_THREAD_RUN,
- IB_THREAD_CANCEL,
- IB_THREAD_EXIT
-
-} ib_thread_state_t;
-
-typedef enum scm_state
-{
- SCM_INIT,
- SCM_LISTEN,
- SCM_CONN_PENDING,
- SCM_ACCEPTING,
- SCM_ACCEPTED,
- SCM_REJECTED,
- SCM_CONNECTED,
- SCM_DISCONNECTED,
- SCM_DESTROY
-
-} SCM_STATE;
-
-#endif /* SOCK_CM */
-
-typedef struct _ib_hca_transport
-{
-#ifdef SOCK_CM
- int max_inline_send;
- ib_thread_state_t cr_state; /* CR thread */
- DAPL_OS_THREAD thread; /* CR thread */
- DAPL_OS_LOCK lock; /* CR serialization */
- struct ib_llist_entry *list; /* Connection Requests */
-#endif
- struct dapl_hca *d_hca;
- DAPL_OS_WAIT_OBJECT wait_object;
- DAPL_ATOMIC handle_ref_count; /* # of ia_opens on handle */
- ib_cqd_handle_t ib_cqd_handle; /* cq domain handle */
-
- /* Name service support */
- void *name_service_handle;
-
-} ib_hca_transport_t;
-
-/* provider specfic fields for shared memory support */
-typedef uint32_t ib_shm_transport_t;
-
-#ifdef SOCK_CM
-
-/* inline send rdma threshold */
-#define INLINE_SEND_DEFAULT 128
-
-/* CM mappings use SOCKETS */
-
-/* destination info exchanged between dapl, define wire protocol version */
-#define DSCM_VER 2
-
-typedef struct _ib_qp_cm
-{
- ib_net16_t ver;
- ib_net16_t rej;
- ib_net16_t lid;
- ib_net16_t port;
- ib_net32_t qpn;
- ib_net32_t p_size;
- DAT_SOCK_ADDR6 ia_address;
- GID gid;
-
-} ib_qp_cm_t;
-
-struct ib_cm_handle
-{
- struct ib_llist_entry entry;
- DAPL_OS_LOCK lock;
- SCM_STATE state;
- int socket;
- int l_socket;
- struct dapl_hca *hca;
- DAT_HANDLE sp;
- DAT_HANDLE cr;
- struct dapl_ep *ep;
- ib_qp_cm_t dst;
- unsigned char p_data[256];
-};
-
-DAT_RETURN dapli_init_sock_cm ( IN DAPL_HCA *hca_ptr );
-
-#endif /* SOCK_CM */
-
-/*
- * Prototype
- */
-
-extern ib_api_status_t
-dapls_modify_qp_state_to_error (
- ib_qp_handle_t qp_handle );
-
-extern ib_api_status_t
-dapls_modify_qp_state_to_reset (
- ib_qp_handle_t);
-
-extern ib_api_status_t
-dapls_modify_qp_state_to_init (
- ib_qp_handle_t, DAT_EP_ATTR *, dapl_ibal_port_t *);
-
-extern ib_api_status_t
-dapls_modify_qp_state_to_rtr (
- ib_qp_handle_t, ib_net32_t, ib_lid_t, dapl_ibal_port_t *);
-
-extern ib_api_status_t
-dapls_modify_qp_state_to_rts (
- ib_qp_handle_t);
-
-extern void
-dapli_ibal_ca_async_error_callback(
- IN ib_async_event_rec_t* p_err_rec );
-
-extern dapl_ibal_port_t *
-dapli_ibal_get_port (
- IN dapl_ibal_ca_t *p_ca,
- IN uint8_t port_num);
-
-extern int32_t dapls_ib_init (void);
-extern int32_t dapls_ib_release (void);
-
-extern dapl_ibal_evd_cb_t *
-dapli_find_evd_cb_by_context(
- IN void *context,
- IN dapl_ibal_ca_t *ca);
-
-extern IB_HCA_NAME
-dapl_ib_convert_name(IN char *name);
-
-
-STATIC _INLINE_ int32_t
-dapli_ibal_convert_privileges (IN DAT_MEM_PRIV_FLAGS privileges )
-{
- int32_t value = DAT_MEM_PRIV_NONE_FLAG;
-
- /*
- * if (DAT_MEM_PRIV_LOCAL_READ_FLAG & privileges)
- * do nothing
- */
- if (DAT_MEM_PRIV_LOCAL_WRITE_FLAG & privileges)
- value |= IB_ACCESS_LOCAL_WRITE;
-
- if (DAT_MEM_PRIV_REMOTE_WRITE_FLAG & privileges)
- value |= IB_ACCESS_REMOTE_WRITE;
-
- if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges)
- value |= IB_ACCESS_REMOTE_READ;
-
-#ifdef DAT_EXTENSIONS
- if (DAT_IB_MEM_PRIV_REMOTE_ATOMIC & privileges)
- value |= IB_ACCESS_REMOTE_ATOMIC;
-#endif
-
-#ifdef DAPL_DBG
- if (value == DAT_MEM_PRIV_NONE_FLAG)
- {
- dapl_dbg_log(DAPL_DBG_TYPE_ERR,"%s() Unknown DAT_MEM_PRIV_ 0x%x\n",
- __FUNCTION__,privileges);
- }
-#endif
- return value;
-}
-
-#define dapl_rmr_convert_privileges(p) dapli_ibal_convert_privileges(p)
-#define dapl_lmr_convert_privileges(p) dapli_ibal_convert_privileges(p)
-
-#endif /* _DAPL_IBAL_UTIL_H_ */
+\r
+/*\r
+ * Copyright (c) 2005-2007 Intel Corporation. All rights reserved.\r
+ * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. \r
+ * \r
+ * This Software is licensed under the terms of the "Common Public\r
+ * License" a copy of which is in the file LICENSE.txt in the root\r
+ * directory. The license is also available from the Open Source\r
+ * Initiative, see http://www.opensource.org/licenses/cpl.php.\r
+ *\r
+ */\r
+\r
+/**********************************************************************\r
+ * \r
+ * MODULE: dapl_ibal_util.h\r
+ *\r
+ * PURPOSE: Utility defs & routines for access to openib-windows IBAL APIs\r
+ *\r
+ * $Id: dapl_ibal_util.h 33 2005-07-11 19:51:17Z ftillier $\r
+ *\r
+ **********************************************************************/\r
+\r
+#ifndef _DAPL_IBAL_UTIL_H_\r
+#define _DAPL_IBAL_UTIL_H_\r
+\r
+#include <iba/ib_al.h>\r
+#include <complib/cl_spinlock.h>\r
+#include <complib/cl_qlist.h>\r
+#include <complib/cl_atomic.h>\r
+\r
+#ifdef DAT_EXTENSIONS\r
+#include <dat2\dat_ib_extensions.h>\r
+#endif\r
+\r
+/*\r
+ * Typedefs to map IBAL types to more generic 'ib' types\r
+ */\r
+#ifdef SOCK_CM\r
+typedef struct ib_cm_handle *dp_ib_cm_handle_t;\r
+typedef struct ib_cm_handle *ib_cm_srvc_handle_t;\r
+#else\r
+\r
+/* EP-CM linking requires list_entry, protected ref counting */\r
+typedef struct dapl_ibal_cm\r
+{ \r
+ struct dapl_llist_entry list_entry;\r
+ DAPL_OS_LOCK lock;\r
+ int ref_count;\r
+ DAT_SOCK_ADDR6 dst_ip_addr; \r
+ ib_cm_handle_t ib_cm; /* h_al, h_qp, cid */\r
+ DAPL_EP *ep;\r
+\r
+} dapl_ibal_cm_t;\r
+\r
+typedef dapl_ibal_cm_t *dp_ib_cm_handle_t;\r
+typedef ib_listen_handle_t ib_cm_srvc_handle_t;\r
+\r
+/* EP-CM linking prototypes */\r
+extern void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr);\r
+extern void dapls_cm_release(dp_ib_cm_handle_t cm_ptr);\r
+extern void dapls_cm_free(dp_ib_cm_handle_t cm_ptr);\r
+extern dp_ib_cm_handle_t ibal_cm_alloc(void);\r
+\r
+#endif\r
+\r
+typedef ib_net64_t IB_HCA_NAME;\r
+typedef ib_ca_handle_t ib_hca_handle_t;\r
+typedef DAT_PVOID ib_cqd_handle_t;\r
+typedef ib_async_event_rec_t ib_error_record_t;\r
+typedef ib_wr_type_t ib_send_op_type_t;\r
+typedef ib_wc_t ib_work_completion_t;\r
+typedef uint32_t ib_hca_port_t;\r
+typedef uint32_t ib_uint32_t;\r
+typedef ib_local_ds_t ib_data_segment_t;\r
+\r
+typedef unsigned __int3264 cl_dev_handle_t;\r
+\r
+\r
+typedef void (*ib_async_handler_t)(\r
+ IN ib_hca_handle_t ib_hca_handle,\r
+ IN ib_error_record_t *err_code,\r
+ IN void *context);\r
+\r
+typedef void (*ib_async_qp_handler_t)(\r
+ IN ib_hca_handle_t ib_hca_handle,\r
+ IN ib_qp_handle_t ib_qp_handle,\r
+ IN ib_error_record_t *err_code,\r
+ IN void *context);\r
+\r
+typedef void (*ib_async_cq_handler_t)(\r
+ IN ib_hca_handle_t ib_hca_handle,\r
+ IN ib_cq_handle_t ib_cq_handle,\r
+ IN ib_error_record_t *err_code,\r
+ IN void *context);\r
+\r
+typedef ib_net64_t ib_guid_t;\r
+typedef ib_net16_t ib_lid_t;\r
+typedef boolean_t ib_bool_t;\r
+\r
+typedef struct _GID\r
+{\r
+ uint64_t gid_prefix;\r
+ uint64_t guid;\r
+} GID;\r
+\r
+typedef enum \r
+{\r
+ IB_CME_CONNECTED,\r
+ IB_CME_DISCONNECTED,\r
+ IB_CME_DISCONNECTED_ON_LINK_DOWN,\r
+ IB_CME_CONNECTION_REQUEST_PENDING,\r
+ IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA,\r
+ IB_CME_DESTINATION_REJECT,\r
+ IB_CME_DESTINATION_REJECT_PRIVATE_DATA,\r
+ IB_CME_DESTINATION_UNREACHABLE,\r
+ IB_CME_TOO_MANY_CONNECTION_REQUESTS,\r
+ IB_CME_LOCAL_FAILURE,\r
+ IB_CME_REPLY_RECEIVED,\r
+ IB_CME_REPLY_RECEIVED_PRIVATE_DATA,\r
+ IB_CM_LOCAL_FAILURE\r
+} ib_cm_events_t;\r
+\r
+\r
+typedef enum\r
+{\r
+ IB_NOTIFY_ON_NEXT_COMP,\r
+ IB_NOTIFY_ON_SOLIC_COMP\r
+} ib_notification_type_t;\r
+\r
+typedef struct _ib_hca_name\r
+{\r
+ DAT_NAME_PTR hca_name[DAT_NAME_MAX_LENGTH];\r
+} ib_hca_name_t;\r
+\r
+\r
+#define IB_INVALID_HANDLE NULL\r
+#define true TRUE\r
+#define false FALSE\r
+\r
+#define IB_MAX_REQ_PDATA_SIZE 92\r
+#define IB_MAX_REP_PDATA_SIZE 196\r
+#define IB_MAX_REJ_PDATA_SIZE 148\r
+#define IB_MAX_DREQ_PDATA_SIZE 220\r
+#define IB_MAX_DREP_PDATA_SIZE 224\r
+\r
+\r
+/* Resource Not Ready\r
+ 1-6 is an actual retry count which is decremented to zero before\r
+ an error condition is set.\r
+ 7 is 'magic' in that it implies Infinite retry, just keeps trying.\r
+*/\r
+#define IB_RNR_RETRY_CNT 7\r
+\r
+/*\r
+IB 1.2 spec, page 331, table 45, RNR NAK timeout encoding (5-bits)\r
+ \r
+00000=655.36ms(milliseconds)\r
+00001=0.01ms\r
+00010=0.02ms\r
+00011=0.03ms\r
+00100=0.04ms\r
+00101=0.06ms\r
+00110=0.08ms\r
+00111=0.12ms\r
+\r
+11100=163.84ms 28d\r
+11101=245.76ms 29d\r
+11110=327.68ms 30d\r
+11111=491.52ms 31d\r
+*/\r
+#define IB_RNR_NAK_TIMEOUT 0\r
+\r
+\r
+typedef void\r
+(*dapl_ibal_pfn_destructor_t)(\r
+ IN void* context );\r
+\r
+typedef struct _dapl_ibal_refs\r
+{\r
+ atomic32_t count; // number of references\r
+ void* context; // context for destructor\r
+ dapl_ibal_pfn_destructor_t destructor; // called when reference goes to zero\r
+\r
+} dapl_ibal_refs_t;\r
+\r
+\r
+typedef struct _dapl_ibal_root\r
+{\r
+ ib_al_handle_t h_al; // handle to Access Layer\r
+ cl_spinlock_t ca_lock; // CA list lock\r
+ cl_qlist_t ca_head; // list head of CAs\r
+ boolean_t shutdown; // when true, driver is shutting down\r
+ boolean_t initialized; // when true, lib is initialized \r
+\r
+} dapl_ibal_root_t;\r
+\r
+\r
+typedef struct _dapl_ibal_ca\r
+{\r
+ cl_list_item_t next; // peer CA list\r
+ ib_ca_handle_t h_ca; // handle to open CA\r
+ ib_ca_attr_t *p_ca_attr; // CA attributes\r
+ uint32_t ca_attr_size;// size of ca attribute\r
+ dapl_ibal_refs_t refs; // reference counting\r
+ cl_spinlock_t port_lock; // port list lock\r
+ cl_qlist_t port_head; // port list head for this CA\r
+ cl_spinlock_t evd_cb_lock; // EVD async error cb list lock\r
+ cl_qlist_t evd_cb_head; // EVD async error cb list head for this CA\r
+ cl_dev_handle_t mlnx_device;\r
+ DAT_PVOID *ia_ptr; // hook for CA async callbacks\r
+} dapl_ibal_ca_t;\r
+\r
+\r
+typedef struct _dapl_ibal_port\r
+{\r
+ cl_list_item_t next; // peer CA list\r
+ dapl_ibal_ca_t *ca; // pointer to parent CA\r
+ ib_port_attr_t *p_attr; // port attributes\r
+ dapl_ibal_refs_t refs; // reference counting\r
+} dapl_ibal_port_t;\r
+\r
+typedef struct _dapl_ibal_evd_cb\r
+{\r
+ cl_list_item_t next; // peer CA list\r
+ ib_async_handler_t pfn_async_err_cb;\r
+ ib_async_qp_handler_t pfn_async_qp_err_cb;\r
+ ib_async_cq_handler_t pfn_async_cq_err_cb;\r
+ void *context;\r
+} dapl_ibal_evd_cb_t;\r
+\r
+/*\r
+ * Definitions to map DTO OPs to IBAL Work-Request ops.\r
+ */\r
+#define OP_BAD_OPCODE 0\r
+#define OP_RDMA_READ WR_RDMA_READ\r
+#define OP_RDMA_WRITE WR_RDMA_WRITE\r
+#define OP_SEND WR_SEND\r
+#define OP_COMP_AND_SWAP WR_COMPARE_SWAP\r
+#define OP_FETCH_AND_ADD WR_FETCH_ADD\r
+\r
+#define OP_RECEIVE 8 /* (8) */\r
+#define OP_BIND_MW 9 /* no-equivalent */\r
+#define OP_RDMA_WRITE_IMM 10 /* RDMA_WRITE+Immediate data */\r
+#define OP_RECEIVE_IMM 11 /* no-equivalent */\r
+\r
+/*\r
+ * Definitions to map QP state\r
+ */\r
+#define IB_QP_STATE_RESET IB_QPS_RESET\r
+#define IB_QP_STATE_INIT IB_QPS_INIT\r
+#define IB_QP_STATE_RTR IB_QPS_RTR\r
+#define IB_QP_STATE_RTS IB_QPS_RTS\r
+#define IB_QP_STATE_SQE IB_QPS_SQERR\r
+#define IB_QP_STATE_SQD IB_QPS_SQD\r
+#define IB_QP_STATE_ERROR IB_QPS_ERROR\r
+\r
+/*\r
+ * Definitions to map Memory OPs\r
+ */\r
+#define IB_ACCESS_LOCAL_WRITE IB_AC_LOCAL_WRITE\r
+#define IB_ACCESS_REMOTE_READ IB_AC_RDMA_READ\r
+#define IB_ACCESS_REMOTE_WRITE IB_AC_RDMA_WRITE\r
+#define IB_ACCESS_REMOTE_ATOMIC IB_AC_ATOMIC\r
+#define IB_ACCESS_MEM_WINDOW_BIND IB_AC_MW_BIND\r
+\r
+/*\r
+ * CQE status \r
+ */\r
+enum _dapl_comp_status\r
+{\r
+ IB_COMP_ST_SUCCESS = IB_WCS_SUCCESS,\r
+ IB_COMP_ST_LOCAL_LEN_ERR = IB_WCS_LOCAL_LEN_ERR,\r
+ IB_COMP_ST_LOCAL_OP_ERR = IB_WCS_LOCAL_OP_ERR,\r
+ IB_COMP_ST_LOCAL_PROTECT_ERR = IB_WCS_LOCAL_PROTECTION_ERR,\r
+ IB_COMP_ST_WR_FLUSHED_ERR = IB_WCS_WR_FLUSHED_ERR,\r
+ IB_COMP_ST_MW_BIND_ERR = IB_WCS_MEM_WINDOW_BIND_ERR,\r
+ IB_COMP_ST_REM_ACC_ERR = IB_WCS_REM_ACCESS_ERR,\r
+ IB_COMP_ST_REM_OP_ERR = IB_WCS_REM_OP_ERR,\r
+ IB_COMP_ST_RNR_COUNTER = IB_WCS_RNR_RETRY_ERR,\r
+ IB_COMP_ST_TRANSP_COUNTER = IB_WCS_TIMEOUT_RETRY_ERR,\r
+ IB_COMP_ST_REM_REQ_ERR = IB_WCS_REM_INVALID_REQ_ERR,\r
+ IB_COMP_ST_BAD_RESPONSE_ERR = IB_WCS_UNMATCHED_RESPONSE,\r
+ IB_COMP_ST_EE_STATE_ERR,\r
+ IB_COMP_ST_EE_CTX_NO_ERR\r
+};\r
+\r
+\r
+/*\r
+ * Macro to check the state of an EP/QP\r
+ */\r
+#define DAPLIB_NEEDS_INIT(ep) ((ep)->qp_state == IB_QPS_ERROR)\r
+\r
+\r
+/*\r
+ * Resolve IBAL return codes to their DAPL equivelent.\r
+ * Do not return invalid Handles, the user is not able\r
+ * to deal with them.\r
+ */\r
+STATIC _INLINE_ DAT_RETURN \r
+dapl_ib_status_convert (\r
+ IN int32_t ib_status)\r
+{\r
+ switch ( ib_status )\r
+ {\r
+ case IB_SUCCESS:\r
+ {\r
+ return DAT_SUCCESS;\r
+ }\r
+ case IB_INSUFFICIENT_RESOURCES:\r
+ case IB_INSUFFICIENT_MEMORY:\r
+ case IB_RESOURCE_BUSY:\r
+ {\r
+ return DAT_INSUFFICIENT_RESOURCES;\r
+ }\r
+ case IB_INVALID_CA_HANDLE:\r
+ case IB_INVALID_CQ_HANDLE:\r
+ case IB_INVALID_QP_HANDLE:\r
+ case IB_INVALID_PD_HANDLE:\r
+ case IB_INVALID_MR_HANDLE:\r
+ case IB_INVALID_MW_HANDLE:\r
+ case IB_INVALID_AL_HANDLE:\r
+ case IB_INVALID_AV_HANDLE:\r
+ {\r
+ return DAT_INVALID_HANDLE;\r
+ }\r
+ case IB_INVALID_PKEY:\r
+ {\r
+ return DAT_PROTECTION_VIOLATION;\r
+ }\r
+ case IB_INVALID_LKEY:\r
+ case IB_INVALID_RKEY:\r
+ case IB_INVALID_PERMISSION:\r
+ {\r
+ return DAT_PRIVILEGES_VIOLATION;\r
+ }\r
+ case IB_INVALID_MAX_WRS:\r
+ case IB_INVALID_MAX_SGE:\r
+ case IB_INVALID_CQ_SIZE:\r
+ case IB_INVALID_SETTING:\r
+ case IB_INVALID_SERVICE_TYPE:\r
+ case IB_INVALID_GID:\r
+ case IB_INVALID_LID:\r
+ case IB_INVALID_GUID:\r
+ case IB_INVALID_PARAMETER:\r
+ {\r
+ return DAT_INVALID_PARAMETER;\r
+ }\r
+ case IB_INVALID_QP_STATE:\r
+ case IB_INVALID_APM_STATE:\r
+ case IB_INVALID_PORT_STATE:\r
+ case IB_INVALID_STATE:\r
+ {\r
+ return DAT_INVALID_STATE;\r
+ }\r
+ case IB_NOT_FOUND:\r
+ {\r
+ return DAT_QUEUE_EMPTY;\r
+ }\r
+ case IB_OVERFLOW:\r
+ {\r
+ return DAT_QUEUE_FULL;\r
+ }\r
+ case IB_UNSUPPORTED:\r
+ {\r
+ return DAT_NOT_IMPLEMENTED;\r
+ }\r
+ case IB_TIMEOUT:\r
+ {\r
+ return DAT_TIMEOUT_EXPIRED;\r
+ }\r
+ case IB_CANCELED:\r
+ {\r
+ return DAT_ABORT;\r
+ }\r
+ default:\r
+ {\r
+ return DAT_INTERNAL_ERROR;\r
+ }\r
+ }\r
+}\r
+ \r
+#define TAKE_LOCK( lock ) \\r
+ cl_spinlock_acquire( &(lock) )\r
+\r
+#define RELEASE_LOCK( lock ) \\r
+ cl_spinlock_release( &(lock) )\r
+\r
+#define LOCK_INSERT_HEAD( lock, head, item ) \\r
+{ \\r
+ TAKE_LOCK( lock ); \\r
+ cl_qlist_insert_head( &head, (cl_list_item_t*)(&item) ); \\r
+ RELEASE_LOCK( lock ); \\r
+}\r
+\r
+#define LOCK_INSERT_TAIL( lock, tail, item ) \\r
+{ \\r
+ TAKE_LOCK( lock ); \\r
+ cl_qlist_insert_tail( &tail, (cl_list_item_t*)(&item) ); \\r
+ RELEASE_LOCK( lock ); \\r
+}\r
+\r
+#define INIT_REFERENCE( p_ref, n, con, destruct ) \\r
+{ \\r
+ (p_ref)->count = n; \\r
+ (p_ref)->context = con; \\r
+ (p_ref)->destructor = destruct; \\r
+}\r
+\r
+#define TAKE_REFERENCE( p_ref ) \\r
+ cl_atomic_inc( &(p_ref)->count )\r
+\r
+#define REMOVE_REFERENCE( p_ref ) \\r
+{ \\r
+ if ( cl_atomic_dec( &(p_ref)->count ) == 0 ) \\r
+ if ( (p_ref)->destructor ) \\r
+ (p_ref)->destructor( (p_ref)->context ); \\r
+}\r
+\r
+/* \r
+ * dapl_llist_entry in dapl.h but dapl.h depends on provider \r
+ * typedef's in this file first. move dapl_llist_entry out of dapl.h\r
+ */\r
+struct ib_llist_entry\r
+{\r
+ struct dapl_llist_entry *flink;\r
+ struct dapl_llist_entry *blink;\r
+ void *data;\r
+ struct dapl_llist_entry *list_head;\r
+};\r
+\r
+#ifdef SOCK_CM\r
+\r
+typedef enum\r
+{\r
+ IB_THREAD_INIT,\r
+ IB_THREAD_RUN,\r
+ IB_THREAD_CANCEL,\r
+ IB_THREAD_EXIT\r
+\r
+} ib_thread_state_t;\r
+\r
+typedef enum scm_state \r
+{\r
+ SCM_INIT,\r
+ SCM_LISTEN,\r
+ SCM_CONN_PENDING,\r
+ SCM_ACCEPTING,\r
+ SCM_ACCEPTED,\r
+ SCM_REJECTED,\r
+ SCM_CONNECTED,\r
+ SCM_DISCONNECTED,\r
+ SCM_DESTROY\r
+\r
+} SCM_STATE;\r
+\r
+#endif /* SOCK_CM */\r
+\r
+typedef struct _ib_hca_transport\r
+{ \r
+#ifdef SOCK_CM\r
+ int max_inline_send;\r
+ ib_thread_state_t cr_state; /* CR thread */\r
+ DAPL_OS_THREAD thread; /* CR thread */\r
+ DAPL_OS_LOCK lock; /* CR serialization */\r
+ struct ib_llist_entry *list; /* Connection Requests */\r
+#endif\r
+ struct dapl_hca *d_hca;\r
+ DAPL_OS_WAIT_OBJECT wait_object;\r
+ DAPL_ATOMIC handle_ref_count; /* # of ia_opens on handle */\r
+ ib_cqd_handle_t ib_cqd_handle; /* cq domain handle */\r
+\r
+ /* Name service support */\r
+ void *name_service_handle;\r
+\r
+} ib_hca_transport_t;\r
+\r
+/* provider specfic fields for shared memory support */\r
+typedef uint32_t ib_shm_transport_t;\r
+\r
+#ifdef SOCK_CM\r
+\r
+/* inline send rdma threshold */\r
+#define INLINE_SEND_DEFAULT 128\r
+\r
+/* CM mappings use SOCKETS */\r
+\r
+/* destination info exchanged between dapl, define wire protocol version */\r
+#define DSCM_VER 2\r
+\r
+typedef struct _ib_qp_cm\r
+{ \r
+ ib_net16_t ver;\r
+ ib_net16_t rej;\r
+ ib_net16_t lid;\r
+ ib_net16_t port;\r
+ ib_net32_t qpn;\r
+ ib_net32_t p_size;\r
+ DAT_SOCK_ADDR6 ia_address;\r
+ GID gid;\r
+\r
+} ib_qp_cm_t;\r
+\r
+struct ib_cm_handle\r
+{ \r
+ struct ib_llist_entry entry;\r
+ DAPL_OS_LOCK lock;\r
+ SCM_STATE state;\r
+ int socket;\r
+ int l_socket; \r
+ struct dapl_hca *hca;\r
+ DAT_HANDLE sp; \r
+ DAT_HANDLE cr;\r
+ struct dapl_ep *ep;\r
+ ib_qp_cm_t dst;\r
+ unsigned char p_data[256];\r
+};\r
+\r
+DAT_RETURN dapli_init_sock_cm ( IN DAPL_HCA *hca_ptr );\r
+\r
+#endif /* SOCK_CM */\r
+\r
+/*\r
+ * Prototype\r
+ */\r
+\r
+extern ib_api_status_t \r
+dapls_modify_qp_state_to_error (\r
+ ib_qp_handle_t qp_handle );\r
+\r
+extern ib_api_status_t \r
+dapls_modify_qp_state_to_reset (\r
+ ib_qp_handle_t);\r
+\r
+extern ib_api_status_t \r
+dapls_modify_qp_state_to_init ( \r
+ ib_qp_handle_t, DAT_EP_ATTR *, dapl_ibal_port_t *);\r
+\r
+extern ib_api_status_t \r
+dapls_modify_qp_state_to_rtr (\r
+ ib_qp_handle_t, ib_net32_t, ib_lid_t, dapl_ibal_port_t *);\r
+\r
+extern ib_api_status_t \r
+dapls_modify_qp_state_to_rts (\r
+ ib_qp_handle_t);\r
+\r
+extern void\r
+dapli_ibal_ca_async_error_callback(\r
+ IN ib_async_event_rec_t* p_err_rec );\r
+\r
+extern dapl_ibal_port_t *\r
+dapli_ibal_get_port (\r
+ IN dapl_ibal_ca_t *p_ca,\r
+ IN uint8_t port_num);\r
+\r
+extern int32_t dapls_ib_init (void);\r
+extern int32_t dapls_ib_release (void);\r
+\r
+extern dapl_ibal_evd_cb_t *\r
+dapli_find_evd_cb_by_context(\r
+ IN void *context,\r
+ IN dapl_ibal_ca_t *ca);\r
+\r
+extern IB_HCA_NAME\r
+dapl_ib_convert_name(IN char *name);\r
+\r
+STATIC _INLINE_ int32_t\r
+dapli_ibal_convert_privileges (IN DAT_MEM_PRIV_FLAGS privileges )\r
+{\r
+ int32_t value = DAT_MEM_PRIV_NONE_FLAG;\r
+\r
+ /*\r
+ * if (DAT_MEM_PRIV_LOCAL_READ_FLAG & privileges)\r
+ * do nothing\r
+ */\r
+ if (DAT_MEM_PRIV_LOCAL_WRITE_FLAG & privileges)\r
+ value |= IB_ACCESS_LOCAL_WRITE;\r
+\r
+ if (DAT_MEM_PRIV_REMOTE_WRITE_FLAG & privileges)\r
+ value |= IB_ACCESS_REMOTE_WRITE;\r
+\r
+ if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges)\r
+ value |= IB_ACCESS_REMOTE_READ;\r
+\r
+#ifdef DAT_EXTENSIONS\r
+ if (DAT_IB_MEM_PRIV_REMOTE_ATOMIC & privileges) \r
+ value |= IB_ACCESS_REMOTE_ATOMIC;\r
+#endif\r
+\r
+#ifdef DAPL_DBG\r
+ if (value == DAT_MEM_PRIV_NONE_FLAG)\r
+ {\r
+ dapl_dbg_log(DAPL_DBG_TYPE_ERR,"%s() Unknown DAT_MEM_PRIV_ 0x%x\n",\r
+ __FUNCTION__,privileges);\r
+ }\r
+#endif\r
+ return value;\r
+}\r
+\r
+#define dapl_rmr_convert_privileges(p) dapli_ibal_convert_privileges(p)\r
+#define dapl_lmr_convert_privileges(p) dapli_ibal_convert_privileges(p)\r
+\r
+#endif /* _DAPL_IBAL_UTIL_H_ */\r
-/*
- * Copyright (c) 2007 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.
- *
- * $Id$
- */
-
-
-#include <oib_ver.h>
-
-#define VER_FILETYPE VFT_DLL
-#define VER_FILESUBTYPE VFT2_UNKNOWN
-
-#if DBG
-#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (IBAL) (Debug)"
-#define VER_INTERNALNAME_STR "dapl2d.dll"
-#define VER_ORIGINALFILENAME_STR "dapl2d.dll"
-#else
-#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (IBAL)"
-#define VER_INTERNALNAME_STR "dapl2.dll"
-#define VER_ORIGINALFILENAME_STR "dapl2.dll"
-#endif
-
-#include <common.ver>
+/*\r
+ * Copyright (c) 2007 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#include <oib_ver.h>\r
+\r
+#define VER_FILETYPE VFT_DLL\r
+#define VER_FILESUBTYPE VFT2_UNKNOWN\r
+\r
+#if DBG\r
+#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (IBAL) (Debug)"\r
+#define VER_INTERNALNAME_STR "dapl2d.dll"\r
+#define VER_ORIGINALFILENAME_STR "dapl2d.dll"\r
+#else\r
+#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (IBAL)"\r
+#define VER_INTERNALNAME_STR "dapl2.dll"\r
+#define VER_ORIGINALFILENAME_STR "dapl2.dll"\r
+#endif\r
+\r
+#include <common.ver>\r
-/*
- * Copyright (c) 2002-2005, Network Appliance, 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
- * in the file LICENSE.txt in the root directory. The license is also
- * 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 in the file
- * LICENSE2.txt in the root directory. The license is also 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 in the file LICENSE3.txt in the root directory. The
- * license is also 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.h
- *
- * PURPOSE: defines common data structures for the DAPL reference implemenation
- *
- * Description: This file describes the working data structures used within
- * DAPL RI.
- *
- *
- * $Id: dapl.h 1317 2005-04-25 17:29:42Z jlentini $
- **********************************************************************/
-
-#ifndef _DAPL_H_
-#define _DAPL_H_
-
-#if defined(__KERNEL__)
-#include <dat2/kdat.h>
-#else
-#include <dat2/udat.h>
-#endif /* defined(__KERNEL__) */
-#include <dat2/dat_registry.h>
-#include "dapl_osd.h"
-#include "dapl_debug.h"
-
-
-
-/*********************************************************************
- * *
- * Enumerations *
- * *
- *********************************************************************/
-
-typedef enum dapl_magic
-{
- /* magic number values for verification & debug */
- DAPL_MAGIC_IA = 0xCafeF00d,
- DAPL_MAGIC_EVD = 0xFeedFace,
- DAPL_MAGIC_EP = 0xDeadBabe,
- DAPL_MAGIC_LMR = 0xBeefCafe,
- DAPL_MAGIC_RMR = 0xABadCafe,
- DAPL_MAGIC_PZ = 0xDeafBeef,
- DAPL_MAGIC_PSP = 0xBeadeD0c,
- DAPL_MAGIC_RSP = 0xFab4Feed,
- DAPL_MAGIC_SRQ = 0xC001Babe,
- DAPL_MAGIC_CR = 0xBe12Cee1,
- DAPL_MAGIC_CR_DESTROYED = 0xB12bDead,
- DAPL_MAGIC_CNO = 0xDeadF00d,
- DAPL_MAGIC_INVALID = 0xFFFFFFFF
-} DAPL_MAGIC;
-
-typedef enum dapl_evd_state
-{
- DAPL_EVD_STATE_TERMINAL,
- DAPL_EVD_STATE_INITIAL,
- DAPL_EVD_STATE_OPEN,
- DAPL_EVD_STATE_WAITED,
- DAPL_EVD_STATE_DEAD = 0xDEAD
-} DAPL_EVD_STATE;
-
-typedef enum dapl_evd_completion
-{
- DAPL_EVD_STATE_INIT,
- DAPL_EVD_STATE_SOLICITED_WAIT,
- DAPL_EVD_STATE_THRESHOLD,
- DAPL_EVD_STATE_UNSIGNALLED
-} DAPL_EVD_COMPLETION;
-
-typedef enum dapl_cno_state
-{
- DAPL_CNO_STATE_UNTRIGGERED,
- DAPL_CNO_STATE_TRIGGERED,
- DAPL_CNO_STATE_DEAD = 0xDeadFeed,
-} DAPL_CNO_STATE;
-
-typedef enum dapl_qp_state
-{
- DAPL_QP_STATE_UNCONNECTED,
- DAPL_QP_STATE_RESERVED,
- DAPL_QP_STATE_PASSIVE_CONNECTION_PENDING,
- DAPL_QP_STATE_ACTIVE_CONNECTION_PENDING,
- DAPL_QP_STATE_TENTATIVE_CONNECTION_PENDING,
- DAPL_QP_STATE_CONNECTED,
- DAPL_QP_STATE_DISCONNECT_PENDING,
- DAPL_QP_STATE_ERROR,
- DAPL_QP_STATE_NOT_REUSABLE,
- DAPL_QP_STATE_FREE
-} DAPL_QP_STATE;
-
-
-/*********************************************************************
- * *
- * Constants *
- * *
- *********************************************************************/
-
-/*
- * number of HCAs allowed
- */
-#define DAPL_MAX_HCA_COUNT 4
-
-/*
- * Configures the RMR bind evd restriction
- */
-
-#define DAPL_RMR_BIND_EVD_RESTRICTION DAT_RMR_EVD_SAME_AS_REQUEST_EVD
-
-/*
- * special qp_state indicating the EP does not have a QP attached yet
- */
-#define DAPL_QP_STATE_UNATTACHED 0xFFF0
-
-#define DAPL_MAX_PRIVATE_DATA_SIZE 256
-
-/*********************************************************************
- * *
- * Macros *
- * *
- *********************************************************************/
-
-#if defined (sun) || defined(__sun) || defined(_sun_) || defined (__solaris__)
-#define DAPL_BAD_PTR(a) ((unsigned long)(a) & 3)
-#elif defined(__linux__)
-#define DAPL_BAD_PTR(a) ((unsigned long)(a) & 3)
-#elif defined(_WIN64)
-#define DAPL_BAD_PTR(a) ((unsigned long)((DAT_UINT64)(a)) & 3)
-#elif defined(_WIN32)
-#define DAPL_BAD_PTR(a) ((unsigned long)((DAT_UINT64)(a)) & 3)
-#endif
-
-/*
- * Simple macro to verify a handle is bad. Conditions:
- * - pointer is NULL
- * - pointer is not word aligned
- * - pointer's magic number is wrong
- */
-
-#define DAPL_BAD_HANDLE(h, magicNum) ( \
- ((h) == NULL) || \
- DAPL_BAD_PTR(h) || \
- (((DAPL_HEADER *)(h))->magic != (magicNum)))
-
-#define DAPL_MIN(a, b) ((a < b) ? (a) : (b))
-#define DAPL_MAX(a, b) ((a > b) ? (a) : (b))
-
-#if NDEBUG > 0
-#define DEBUG_IS_BAD_HANDLE(h, magicNum) (DAPL_BAD_HANDLE(h, magicNum))
-#else
-#define DEBUG_IS_BAD_HANDLE(h, magicNum) (0)
-#endif
-
-#define DAT_ERROR(Type, SubType) ((DAT_RETURN)(DAT_CLASS_ERROR | Type | SubType))
-
-/*********************************************************************
- * *
- * Typedefs *
- * *
- *********************************************************************/
-
-typedef struct dapl_llist_entry DAPL_LLIST_ENTRY;
-typedef DAPL_LLIST_ENTRY * DAPL_LLIST_HEAD;
-typedef struct dapl_ring_buffer DAPL_RING_BUFFER;
-typedef struct dapl_cookie_buffer DAPL_COOKIE_BUFFER;
-
-typedef struct dapl_hash_table DAPL_HASH_TABLE;
-typedef struct dapl_hash_table * DAPL_HASH_TABLEP;
-typedef DAT_UINT64 DAPL_HASH_KEY;
-typedef void * DAPL_HASH_DATA;
-
-typedef struct dapl_hca DAPL_HCA;
-
-typedef struct dapl_header DAPL_HEADER;
-
-typedef struct dapl_ia DAPL_IA;
-typedef struct dapl_cno DAPL_CNO;
-typedef struct dapl_evd DAPL_EVD;
-typedef struct dapl_ep DAPL_EP;
-typedef struct dapl_srq DAPL_SRQ;
-typedef struct dapl_pz DAPL_PZ;
-typedef struct dapl_lmr DAPL_LMR;
-typedef struct dapl_rmr DAPL_RMR;
-typedef struct dapl_sp DAPL_SP;
-typedef struct dapl_cr DAPL_CR;
-
-typedef struct dapl_cookie DAPL_COOKIE;
-typedef struct dapl_dto_cookie DAPL_DTO_COOKIE;
-typedef struct dapl_rmr_cookie DAPL_RMR_COOKIE;
-
-typedef struct dapl_private DAPL_PRIVATE;
-
-
-
-/*********************************************************************
- * *
- * Structures *
- * *
- *********************************************************************/
-
-struct dapl_llist_entry
-{
- struct dapl_llist_entry *flink;
- struct dapl_llist_entry *blink;
- void *data;
- DAPL_LLIST_HEAD *list_head; /* for consistency checking */
-};
-
-struct dapl_ring_buffer
-{
- void **base; /* base of element array */
- DAT_COUNT lim; /* mask, number of entries - 1 */
- DAPL_ATOMIC head; /* head pointer index */
- DAPL_ATOMIC tail; /* tail pointer index */
-};
-
-struct dapl_cookie_buffer
-{
- DAPL_COOKIE *pool;
- DAT_COUNT pool_size;
- DAPL_ATOMIC head;
- DAPL_ATOMIC tail;
-};
-
-#ifdef IBAPI
-#include "dapl_ibapi_util.h"
-#elif VAPI
-#include "dapl_vapi_util.h"
-#elif __OPENIB__
-#include "dapl_openib_util.h"
-#include "dapl_openib_cm.h"
-#elif DUMMY
-#include "dapl_dummy_util.h"
-#elif OPENIB
-#include "dapl_ib_util.h"
-#else /* windows - IBAL and/or IBAL+Sock_CM */
-#include "dapl_ibal_util.h"
-#endif
-
-struct dapl_hca
-{
- DAPL_OS_LOCK lock;
- DAPL_LLIST_HEAD ia_list_head; /* list of all open IAs */
- DAPL_ATOMIC handle_ref_count; /* count of ia_opens on handle */
- DAPL_EVD *async_evd;
- DAPL_EVD *async_error_evd;
- DAT_SOCK_ADDR6 hca_address; /* local address of HCA*/
- char *name; /* provider name */
- ib_hca_handle_t ib_hca_handle;
- unsigned long port_num; /* physical port number */
- ib_hca_transport_t ib_trans; /* Values specific transport API */
- /* Memory Subsystem Support */
- DAPL_HASH_TABLE *lmr_hash_table;
- /* Limits & useful HCA attributes */
- DAT_IA_ATTR ia_attr;
-};
-
-/* DAPL Objects always have the following header */
-struct dapl_header
-{
- DAT_PROVIDER *provider; /* required by DAT - must be first */
- DAPL_MAGIC magic; /* magic number for verification */
- DAT_HANDLE_TYPE handle_type; /* struct type */
- DAPL_IA *owner_ia; /* ia which owns this stuct */
- DAPL_LLIST_ENTRY ia_list_entry; /* link entry on ia struct */
- DAT_CONTEXT user_context; /* user context - opaque to DAPL */
- DAPL_OS_LOCK lock; /* lock - in header for easier macros */
-};
-
-/* DAPL_IA maps to DAT_IA_HANDLE */
-struct dapl_ia
-{
- DAPL_HEADER header;
- DAPL_HCA *hca_ptr;
- DAPL_EVD *async_error_evd;
- DAT_BOOLEAN cleanup_async_error_evd;
-
- DAPL_LLIST_ENTRY hca_ia_list_entry; /* HCAs list of IAs */
- DAPL_LLIST_HEAD ep_list_head; /* EP queue */
- DAPL_LLIST_HEAD lmr_list_head; /* LMR queue */
- DAPL_LLIST_HEAD rmr_list_head; /* RMR queue */
- DAPL_LLIST_HEAD pz_list_head; /* PZ queue */
- DAPL_LLIST_HEAD evd_list_head; /* EVD queue */
- DAPL_LLIST_HEAD cno_list_head; /* CNO queue */
- DAPL_LLIST_HEAD psp_list_head; /* PSP queue */
- DAPL_LLIST_HEAD rsp_list_head; /* RSP queue */
- DAPL_LLIST_HEAD srq_list_head; /* SRQ queue */
-#ifdef DAPL_COUNTERS
- void *cntrs;
-#endif
-};
-
-/* DAPL_CNO maps to DAT_CNO_HANDLE */
-struct dapl_cno
-{
- DAPL_HEADER header;
-
- /* A CNO cannot be freed while it is referenced elsewhere. */
- DAPL_ATOMIC cno_ref_count;
- DAPL_CNO_STATE cno_state;
-
- DAT_COUNT cno_waiters;
- DAPL_EVD *cno_evd_triggered;
-#if defined(__KERNEL__)
- DAT_UPCALL_OBJECT cno_upcall;
- DAT_UPCALL_POLICY cno_upcall_policy;
-#else
- DAT_OS_WAIT_PROXY_AGENT cno_wait_agent;
-#endif /* defined(__KERNEL__) */
-
- DAPL_OS_WAIT_OBJECT cno_wait_object;
-};
-
-/* DAPL_EVD maps to DAT_EVD_HANDLE */
-struct dapl_evd
-{
- DAPL_HEADER header;
-
- DAPL_EVD_STATE evd_state;
- DAT_EVD_FLAGS evd_flags;
- DAT_BOOLEAN evd_enabled; /* For attached CNO. */
- DAT_BOOLEAN evd_waitable; /* EVD state. */
-
- /* Derived from evd_flags; see dapls_evd_internal_create. */
- DAT_BOOLEAN evd_producer_locking_needed;
-
- /* Every EVD has a CQ unless it is a SOFTWARE_EVENT only EVD */
- ib_cq_handle_t ib_cq_handle;
-
- /* An Event Dispatcher cannot be freed while
- * it is referenced elsewhere.
- */
- DAPL_ATOMIC evd_ref_count;
-
- /* Set if there has been a catastrophic overflow */
- DAT_BOOLEAN catastrophic_overflow;
-
- /* the actual events */
- DAT_COUNT qlen;
- DAT_EVENT *events;
- DAPL_RING_BUFFER free_event_queue;
- DAPL_RING_BUFFER pending_event_queue;
-
- /* CQ Completions are not placed into 'deferred_events'
- ** rather they are simply left on the Completion Queue
- ** and the fact that there was a notification is flagged.
- */
- DAT_BOOLEAN cq_notified;
- DAPL_OS_TICKS cq_notified_when;
-
- DAT_COUNT cno_active_count;
- DAPL_CNO *cno_ptr;
-
- DAPL_OS_WAIT_OBJECT wait_object;
-
- DAT_COUNT threshold;
- DAPL_EVD_COMPLETION completion_type;
-
-#ifdef DAPL_COUNTERS
- void *cntrs;
-#endif
-};
-
-/* DAPL_PRIVATE used to pass private data in a connection */
-struct dapl_private
-{
-#ifdef IBHOSTS_NAMING
- DAT_SOCK_ADDR6 hca_address; /* local address of HCA*/
-#endif /* IBHOSTS_NAMING */
- unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE];
-};
-
-/* uDAPL timer entry, used to queue timeouts */
-struct dapl_timer_entry
-{
- DAPL_LLIST_ENTRY list_entry; /* link entry on ia struct */
- DAPL_OS_TIMEVAL expires;
- void (*function) (uintptr_t);
- void *data;
-};
-
-#ifdef DAPL_DBG_IO_TRC
-
-#define DBG_IO_TRC_QLEN 32 /* length of trace buffer */
-#define DBG_IO_TRC_IOV 3 /* iov elements we keep track of */
-
-struct io_buf_track
-{
- Ib_send_op_type op_type;
- DAPL_COOKIE *cookie;
- DAT_LMR_TRIPLET iov[DBG_IO_TRC_IOV];
- DAT_RMR_TRIPLET remote_iov;
- unsigned int done; /* count to track completion ordering */
- int status;
- void *wqe;
-};
-
-#endif /* DAPL_DBG_IO_TRC */
-
-/* DAPL_EP maps to DAT_EP_HANDLE */
-struct dapl_ep
-{
- DAPL_HEADER header;
- /* What the DAT Consumer asked for */
- DAT_EP_PARAM param;
-
- /* The RC Queue Pair (IBM OS API) */
- ib_qp_handle_t qp_handle;
- unsigned int qpn; /* qp number */
- ib_qp_state_t qp_state;
-
- /* communications manager handle (IBM OS API) */
- dp_ib_cm_handle_t cm_handle;
-
- /* store the remote IA address here, reference from the param
- * struct which only has a pointer, no storage
- */
- DAT_SOCK_ADDR6 remote_ia_address;
-
- /* For passive connections we maintain a back pointer to the CR */
- void * cr_ptr;
-
- /* pointer to connection timer, if set */
- struct dapl_timer_entry *cxn_timer;
-
- /* private data container */
- DAPL_PRIVATE private;
-
- /* DTO data */
- DAPL_ATOMIC req_count;
- DAPL_ATOMIC recv_count;
-
- DAPL_COOKIE_BUFFER req_buffer;
- DAPL_COOKIE_BUFFER recv_buffer;
-
-#ifdef DAPL_DBG_IO_TRC
- int ibt_dumped;
- struct io_buf_track *ibt_base;
- DAPL_RING_BUFFER ibt_queue;
-#endif /* DAPL_DBG_IO_TRC */
-#if defined(_WIN32) || defined(_WIN64)
- DAT_BOOLEAN recv_discreq;
- DAT_BOOLEAN sent_discreq;
- dp_ib_cm_handle_t ibal_cm_handle;
-#endif
-#ifdef DAPL_COUNTERS
- void *cntrs;
-#endif
-};
-
-/* DAPL_SRQ maps to DAT_SRQ_HANDLE */
-struct dapl_srq
-{
- DAPL_HEADER header;
- DAT_SRQ_PARAM param;
- DAPL_ATOMIC srq_ref_count;
- DAPL_COOKIE_BUFFER recv_buffer;
- DAPL_ATOMIC recv_count;
-};
-
-/* DAPL_PZ maps to DAT_PZ_HANDLE */
-struct dapl_pz
-{
- DAPL_HEADER header;
- ib_pd_handle_t pd_handle;
- DAPL_ATOMIC pz_ref_count;
-};
-
-/* DAPL_LMR maps to DAT_LMR_HANDLE */
-struct dapl_lmr
-{
- DAPL_HEADER header;
- DAT_LMR_PARAM param;
- ib_mr_handle_t mr_handle;
- DAPL_ATOMIC lmr_ref_count;
-#if !defined(__KDAPL__)
- char shmid[DAT_LMR_COOKIE_SIZE]; /* shared memory ID */
- ib_shm_transport_t ib_trans; /* provider specific data */
-#endif /* !__KDAPL__ */
-};
-
-/* DAPL_RMR maps to DAT_RMR_HANDLE */
-struct dapl_rmr
-{
- DAPL_HEADER header;
- DAT_RMR_PARAM param;
- DAPL_EP *ep;
- DAPL_PZ *pz;
- DAPL_LMR *lmr;
- ib_mw_handle_t mw_handle;
-};
-
-/* SP types, indicating the state and queue */
-typedef enum dapl_sp_state
-{
- DAPL_SP_STATE_FREE,
- DAPL_SP_STATE_PSP_LISTENING,
- DAPL_SP_STATE_PSP_PENDING,
- DAPL_SP_STATE_RSP_LISTENING,
- DAPL_SP_STATE_RSP_PENDING
-} DAPL_SP_STATE;
-
-/* DAPL_SP maps to DAT_PSP_HANDLE and DAT_RSP_HANDLE */
-struct dapl_sp
-{
- DAPL_HEADER header;
- DAPL_SP_STATE state; /* type and queue of the SP */
-
- /* PSP/RSP PARAM fields */
- DAT_CONN_QUAL conn_qual;
- DAT_EVD_HANDLE evd_handle;
- DAT_PSP_FLAGS psp_flags;
- DAT_EP_HANDLE ep_handle;
-
- /* maintenence fields */
- DAT_BOOLEAN listening; /* PSP is registered & active */
- ib_cm_srvc_handle_t cm_srvc_handle; /* Used by Mellanox CM */
- DAPL_LLIST_HEAD cr_list_head; /* CR pending queue */
- DAT_COUNT cr_list_count; /* count of CRs on queue */
-#if defined(_VENDOR_IBAL_)
- DAPL_OS_WAIT_OBJECT wait_object; /* cancel & destroy. */
-#endif
-};
-
-/* DAPL_CR maps to DAT_CR_HANDLE */
-struct dapl_cr
-{
- DAPL_HEADER header;
-
- /* for convenience the data is kept as a DAT_CR_PARAM.
- * however, the "local_endpoint" field is always NULL
- * so this wastes a pointer. This is probably ok to
- * simplify code, espedially dat_cr_query.
- */
- DAT_CR_PARAM param;
- /* IB specific fields */
- dp_ib_cm_handle_t ib_cm_handle;
-
- DAT_SOCK_ADDR6 remote_ia_address;
- /* Assuming that the maximum private data size is small.
- * If it gets large, use of a pointer may be appropriate.
- */
- unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE];
- /*
- * Need to be able to associate the CR back to the PSP for
- * dapl_cr_reject.
- */
- DAPL_SP *sp_ptr;
-};
-
-typedef enum dapl_dto_type
-{
- DAPL_DTO_TYPE_SEND,
- DAPL_DTO_TYPE_RECV,
- DAPL_DTO_TYPE_RDMA_WRITE,
- DAPL_DTO_TYPE_RDMA_READ,
-#ifdef DAT_EXTENSIONS
- DAPL_DTO_TYPE_EXTENSION,
-#endif
-} DAPL_DTO_TYPE;
-
-typedef enum dapl_cookie_type
-{
- DAPL_COOKIE_TYPE_NULL,
- DAPL_COOKIE_TYPE_DTO,
- DAPL_COOKIE_TYPE_RMR,
-} DAPL_COOKIE_TYPE;
-
-/* DAPL_DTO_COOKIE used as context for DTO WQEs */
-struct dapl_dto_cookie
-{
- DAPL_DTO_TYPE type;
- DAT_DTO_COOKIE cookie;
- DAT_COUNT size; /* used for SEND and RDMA write */
-};
-
-/* DAPL_RMR_COOKIE used as context for bind WQEs */
-struct dapl_rmr_cookie
-{
- DAPL_RMR *rmr;
- DAT_RMR_COOKIE cookie;
-};
-
-/* DAPL_COOKIE used as context for WQEs */
-struct dapl_cookie
-{
- DAPL_COOKIE_TYPE type; /* Must be first, to define struct. */
- DAPL_EP *ep;
- DAT_COUNT index;
- union
- {
- DAPL_DTO_COOKIE dto;
- DAPL_RMR_COOKIE rmr;
- } val;
-};
-
-/*
- * Private Data operations. Used to obtain the size of the private
- * data from the provider layer.
- */
-typedef enum dapl_private_data_op
-{
- DAPL_PDATA_CONN_REQ = 0, /* connect request */
- DAPL_PDATA_CONN_REP = 1, /* connect reply */
- DAPL_PDATA_CONN_REJ = 2, /* connect reject */
- DAPL_PDATA_CONN_DREQ = 3, /* disconnect request */
- DAPL_PDATA_CONN_DREP = 4, /* disconnect reply */
-} DAPL_PDATA_OP;
-
-
-/*
- * Generic HCA name field
- */
-#define DAPL_HCA_NAME_MAX_LEN 260
-typedef char DAPL_HCA_NAME[DAPL_HCA_NAME_MAX_LEN+1];
-
-#ifdef IBHOSTS_NAMING
-
-/*
- * Simple mapping table to match IP addresses to GIDs. Loaded
- * by dapl_init.
- */
-typedef struct _dapl_gid_map_table
-{
- uint32_t ip_address;
- ib_gid_t gid;
-} DAPL_GID_MAP;
-
-#endif /* IBHOSTS_NAMING */
-
-/*
- * IBTA defined reason for reject message: See IBTA 1.1 specification,
- * 12.6.7.2 REJECTION REASON section.
- */
-#define IB_CM_REJ_REASON_CONSUMER_REJ 0x001C
-
-
-#if defined(DAPL_DBG_IO_TRC)
-/*********************************************************************
- * *
- * Debug I/O tracing support prototypes *
- * *
- *********************************************************************/
-/*
- * I/O tracing support
- */
-void dapls_io_trc_alloc (
- DAPL_EP *ep_ptr);
-
-void dapls_io_trc_update_completion (
- DAPL_EP *ep_ptr,
- DAPL_COOKIE *cookie,
- ib_uint32_t ib_status );
-
-void dapls_io_trc_dump (
- DAPL_EP *ep_ptr,
- ib_work_completion_t *cqe_ptr,
- ib_uint32_t ib_status);
-
-#else /* DAPL_DBG_IO_TRC */
-
-#define dapls_io_trc_alloc(a)
-#define dapls_io_trc_update_completion(a, b, c)
-#define dapls_io_trc_dump(a, b, c)
-
-#endif /* DAPL_DBG_IO_TRC */
-
-
-/*********************************************************************
- * *
- * Function Prototypes *
- * *
- *********************************************************************/
-
-typedef void (*DAPL_CONNECTION_STATE_HANDLER) (
- IN DAPL_EP *,
- IN ib_cm_events_t,
- IN const void *,
- OUT DAT_EVENT *);
-
-/*
- * DAT Mandated functions
- */
-
-extern DAT_RETURN DAT_API dapl_ia_open (
- IN const DAT_NAME_PTR, /* name */
- IN DAT_COUNT, /* asynch_evd_qlen */
- INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */
- OUT DAT_IA_HANDLE *); /* ia_handle */
-
-extern DAT_RETURN DAT_API dapl_ia_close (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_CLOSE_FLAGS ); /* ia_flags */
-
-
-extern DAT_RETURN DAT_API dapl_ia_query (
- IN DAT_IA_HANDLE, /* ia handle */
- OUT DAT_EVD_HANDLE *, /* async_evd_handle */
- IN DAT_IA_ATTR_MASK, /* ia_params_mask */
- OUT DAT_IA_ATTR *, /* ia_params */
- IN DAT_PROVIDER_ATTR_MASK, /* provider_params_mask */
- OUT DAT_PROVIDER_ATTR * ); /* provider_params */
-
-
-/* helper functions */
-
-extern DAT_RETURN DAT_API dapl_set_consumer_context (
- IN DAT_HANDLE, /* dat handle */
- IN DAT_CONTEXT); /* context */
-
-extern DAT_RETURN DAT_API dapl_get_consumer_context (
- IN DAT_HANDLE, /* dat handle */
- OUT DAT_CONTEXT * ); /* context */
-
-extern DAT_RETURN DAT_API dapl_get_handle_type (
- IN DAT_HANDLE,
- OUT DAT_HANDLE_TYPE * );
-
-/* CNO functions */
-
-#if !defined(__KERNEL__)
-extern DAT_RETURN DAT_API dapl_cno_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_OS_WAIT_PROXY_AGENT, /* agent */
- OUT DAT_CNO_HANDLE *); /* cno_handle */
-
-extern DAT_RETURN DAT_API dapl_cno_modify_agent (
- IN DAT_CNO_HANDLE, /* cno_handle */
- IN DAT_OS_WAIT_PROXY_AGENT); /* agent */
-
-extern DAT_RETURN DAT_API dapl_cno_query (
- IN DAT_CNO_HANDLE, /* cno_handle */
- IN DAT_CNO_PARAM_MASK, /* cno_param_mask */
- OUT DAT_CNO_PARAM * ); /* cno_param */
-
-extern DAT_RETURN DAT_API dapl_cno_free (
- IN DAT_CNO_HANDLE); /* cno_handle */
-
-extern DAT_RETURN DAT_API dapl_cno_wait (
- IN DAT_CNO_HANDLE, /* cno_handle */
- IN DAT_TIMEOUT, /* timeout */
- OUT DAT_EVD_HANDLE *); /* evd_handle */
-
-extern DAT_RETURN DAT_API dapl_cno_fd_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- OUT DAT_FD *, /* file_descriptor */
- OUT DAT_CNO_HANDLE *); /* cno_handle */
-
-extern DAT_RETURN DAT_API dapl_cno_trigger (
- IN DAT_CNO_HANDLE, /* cno_handle */
- OUT DAT_EVD_HANDLE *); /* evd_handle */
-
-#endif /* !defined(__KERNEL__) */
-
-/* CR Functions */
-
-extern DAT_RETURN DAT_API dapl_cr_query (
- IN DAT_CR_HANDLE, /* cr_handle */
- IN DAT_CR_PARAM_MASK, /* cr_args_mask */
- OUT DAT_CR_PARAM * ); /* cwr_args */
-
-extern DAT_RETURN DAT_API dapl_cr_accept (
- IN DAT_CR_HANDLE, /* cr_handle */
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_COUNT, /* private_data_size */
- IN const DAT_PVOID ); /* private_data */
-
-extern DAT_RETURN DAT_API dapl_cr_reject (
- IN DAT_CR_HANDLE, /* cr_handle */
- IN DAT_COUNT, /* private_data_size */
- IN const DAT_PVOID ); /* private_data */
-
-extern DAT_RETURN DAT_API dapl_cr_handoff (
- IN DAT_CR_HANDLE, /* cr_handle */
- IN DAT_CONN_QUAL); /* handoff */
-
-/* EVD Functions */
-
-#if defined(__KERNEL__)
-extern DAT_RETURN DAT_API dapl_ia_memtype_hint (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_MEM_TYPE, /* mem_type */
- IN DAT_VLEN, /* length */
- IN DAT_MEM_OPT, /* mem_optimization */
- OUT DAT_VLEN *, /* suggested_length */
- OUT DAT_VADDR *); /* suggested_alignment */
-
-extern DAT_RETURN DAT_API dapl_evd_kcreate (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_COUNT, /* evd_min_qlen */
- IN DAT_UPCALL_POLICY, /* upcall_policy */
- IN const DAT_UPCALL_OBJECT *, /* upcall */
- IN DAT_EVD_FLAGS, /* evd_flags */
- OUT DAT_EVD_HANDLE * ); /* evd_handle */
-
-extern DAT_RETURN DAT_API dapl_evd_kquery (
- IN DAT_EVD_HANDLE, /* evd_handle */
- IN DAT_EVD_PARAM_MASK, /* evd_args_mask */
- OUT DAT_EVD_PARAM * ); /* evd_args */
-
-#else
-extern DAT_RETURN DAT_API dapl_evd_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_COUNT, /* evd_min_qlen */
- IN DAT_CNO_HANDLE, /* cno_handle */
- IN DAT_EVD_FLAGS, /* evd_flags */
- OUT DAT_EVD_HANDLE * ); /* evd_handle */
-
-extern DAT_RETURN DAT_API dapl_evd_query (
- IN DAT_EVD_HANDLE, /* evd_handle */
- IN DAT_EVD_PARAM_MASK, /* evd_args_mask */
- OUT DAT_EVD_PARAM * ); /* evd_args */
-#endif /* defined(__KERNEL__) */
-
-#if defined(__KERNEL__)
-extern DAT_RETURN DAT_API dapl_evd_modify_upcall (
- IN DAT_EVD_HANDLE, /* evd_handle */
- IN DAT_UPCALL_POLICY, /* upcall_policy */
- IN const DAT_UPCALL_OBJECT * ); /* upcall */
-
-#else
-
-extern DAT_RETURN DAT_API dapl_evd_modify_cno (
- IN DAT_EVD_HANDLE, /* evd_handle */
- IN DAT_CNO_HANDLE); /* cno_handle */
-#endif
-
-extern DAT_RETURN DAT_API dapl_evd_enable (
- IN DAT_EVD_HANDLE); /* evd_handle */
-
-extern DAT_RETURN DAT_API dapl_evd_disable (
- IN DAT_EVD_HANDLE); /* evd_handle */
-
-#if !defined(__KERNEL__)
-extern DAT_RETURN DAT_API dapl_evd_wait (
- IN DAT_EVD_HANDLE, /* evd_handle */
- IN DAT_TIMEOUT, /* timeout */
- IN DAT_COUNT, /* threshold */
- OUT DAT_EVENT *, /* event */
- OUT DAT_COUNT *); /* nmore */
-#endif /* !defined(__KERNEL__) */
-
-extern DAT_RETURN DAT_API dapl_evd_resize (
- IN DAT_EVD_HANDLE, /* evd_handle */
- IN DAT_COUNT ); /* evd_qlen */
-
-extern DAT_RETURN DAT_API dapl_evd_post_se (
- DAT_EVD_HANDLE, /* evd_handle */
- const DAT_EVENT * ); /* event */
-
-extern DAT_RETURN DAT_API dapl_evd_dequeue (
- IN DAT_EVD_HANDLE, /* evd_handle */
- OUT DAT_EVENT * ); /* event */
-
-extern DAT_RETURN DAT_API dapl_evd_free (
- IN DAT_EVD_HANDLE );
-
-extern DAT_RETURN DAT_API
-dapl_evd_set_unwaitable (
- IN DAT_EVD_HANDLE evd_handle );
-
-extern DAT_RETURN DAT_API
-dapl_evd_clear_unwaitable (
- IN DAT_EVD_HANDLE evd_handle );
-
-/* EP functions */
-
-extern DAT_RETURN DAT_API dapl_ep_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_PZ_HANDLE, /* pz_handle */
- IN DAT_EVD_HANDLE, /* in_dto_completion_evd_handle */
- IN DAT_EVD_HANDLE, /* out_dto_completion_evd_handle */
- IN DAT_EVD_HANDLE, /* connect_evd_handle */
- IN const DAT_EP_ATTR *, /* ep_parameters */
- OUT DAT_EP_HANDLE * ); /* ep_handle */
-
-extern DAT_RETURN DAT_API dapl_ep_query (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_EP_PARAM_MASK, /* ep_args_mask */
- OUT DAT_EP_PARAM * ); /* ep_args */
-
-extern DAT_RETURN DAT_API dapl_ep_modify (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_EP_PARAM_MASK, /* ep_args_mask */
- IN const DAT_EP_PARAM * ); /* ep_args */
-
-extern DAT_RETURN DAT_API dapl_ep_connect (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */
- IN DAT_CONN_QUAL, /* remote_conn_qual */
- IN DAT_TIMEOUT, /* timeout */
- IN DAT_COUNT, /* private_data_size */
- IN const DAT_PVOID, /* private_data */
- IN DAT_QOS, /* quality_of_service */
- IN DAT_CONNECT_FLAGS ); /* connect_flags */
-
-extern DAT_RETURN DAT_API dapl_ep_common_connect (
- IN DAT_EP_HANDLE ep, /* ep_handle */
- IN DAT_IA_ADDRESS_PTR remote_addr, /* remote_ia_address */
- IN DAT_TIMEOUT timeout, /* timeout */
- IN DAT_COUNT pdata_size, /* private_data_size */
- IN const DAT_PVOID pdata ); /* private_data */
-
-extern DAT_RETURN DAT_API dapl_ep_dup_connect (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_EP_HANDLE, /* ep_dup_handle */
- IN DAT_TIMEOUT, /* timeout*/
- IN DAT_COUNT, /* private_data_size */
- IN const DAT_PVOID, /* private_data */
- IN DAT_QOS); /* quality_of_service */
-
-extern DAT_RETURN DAT_API dapl_ep_disconnect (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_CLOSE_FLAGS ); /* close_flags */
-
-extern DAT_RETURN DAT_API dapl_ep_post_send (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_COUNT, /* num_segments */
- IN DAT_LMR_TRIPLET *, /* local_iov */
- IN DAT_DTO_COOKIE, /* user_cookie */
- IN DAT_COMPLETION_FLAGS ); /* completion_flags */
-
-extern DAT_RETURN DAT_API dapl_ep_post_recv (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_COUNT, /* num_segments */
- IN DAT_LMR_TRIPLET *, /* local_iov */
- IN DAT_DTO_COOKIE, /* user_cookie */
- IN DAT_COMPLETION_FLAGS ); /* completion_flags */
-
-extern DAT_RETURN DAT_API dapl_ep_post_rdma_read (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_COUNT, /* num_segments */
- IN DAT_LMR_TRIPLET *, /* local_iov */
- IN DAT_DTO_COOKIE, /* user_cookie */
- IN const DAT_RMR_TRIPLET *, /* remote_iov */
- IN DAT_COMPLETION_FLAGS ); /* completion_flags */
-
-extern DAT_RETURN DAT_API dapl_ep_post_rdma_read_to_rmr (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN const DAT_RMR_TRIPLET *,/* local_iov */
- IN DAT_DTO_COOKIE, /* user_cookie */
- IN const DAT_RMR_TRIPLET *,/* remote_iov */
- IN DAT_COMPLETION_FLAGS); /* completion_flags */
-
-extern DAT_RETURN DAT_API dapl_ep_post_rdma_write (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_COUNT, /* num_segments */
- IN DAT_LMR_TRIPLET *, /* local_iov */
- IN DAT_DTO_COOKIE, /* user_cookie */
- IN const DAT_RMR_TRIPLET *, /* remote_iov */
- IN DAT_COMPLETION_FLAGS ); /* completion_flags */
-
-extern DAT_RETURN DAT_API dapl_ep_post_send_with_invalidate (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_COUNT, /* num_segments */
- IN DAT_LMR_TRIPLET *, /* local_iov */
- IN DAT_DTO_COOKIE, /* user_cookie */
- IN DAT_COMPLETION_FLAGS, /* completion_flags */
- IN DAT_BOOLEAN, /* invalidate_flag */
- IN DAT_RMR_CONTEXT); /* RMR context */
-
-extern DAT_RETURN DAT_API dapl_ep_get_status (
- IN DAT_EP_HANDLE, /* ep_handle */
- OUT DAT_EP_STATE *, /* ep_state */
- OUT DAT_BOOLEAN *, /* in_dto_idle */
- OUT DAT_BOOLEAN * ); /* out_dto_idle */
-
-extern DAT_RETURN DAT_API dapl_ep_free (
- IN DAT_EP_HANDLE); /* ep_handle */
-
-extern DAT_RETURN DAT_API dapl_ep_reset (
- IN DAT_EP_HANDLE); /* ep_handle */
-
-extern DAT_RETURN DAT_API dapl_ep_create_with_srq (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_PZ_HANDLE, /* pz_handle */
- IN DAT_EVD_HANDLE, /* recv_evd_handle */
- IN DAT_EVD_HANDLE, /* request_evd_handle */
- IN DAT_EVD_HANDLE, /* connect_evd_handle */
- IN DAT_SRQ_HANDLE, /* srq_handle */
- IN const DAT_EP_ATTR *, /* ep_attributes */
- OUT DAT_EP_HANDLE *); /* ep_handle */
-
-extern DAT_RETURN DAT_API dapl_ep_recv_query (
- IN DAT_EP_HANDLE, /* ep_handle */
- OUT DAT_COUNT *, /* nbufs_allocated */
- OUT DAT_COUNT *); /* bufs_alloc_span */
-
-extern DAT_RETURN DAT_API dapl_ep_set_watermark (
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_COUNT, /* soft_high_watermark */
- IN DAT_COUNT); /* hard_high_watermark */
-
-/* LMR functions */
-
-#if defined(__KERNEL__)
-extern DAT_RETURN DAT_API dapl_lmr_kcreate (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_MEM_TYPE, /* mem_type */
- IN DAT_REGION_DESCRIPTION, /* region_description */
- IN DAT_VLEN, /* length */
- IN DAT_PZ_HANDLE, /* pz_handle */
- IN DAT_MEM_PRIV_FLAGS, /* privileges */
- IN DAT_VA_TYPE, /* va_type */
- IN DAT_MEM_OPT, /* optimization */
- OUT DAT_LMR_HANDLE *, /* lmr_handle */
- OUT DAT_LMR_CONTEXT *, /* lmr_context */
- OUT DAT_RMR_CONTEXT *, /* rmr_context */
- OUT DAT_VLEN *, /* registered_length */
- OUT DAT_VADDR * ); /* registered_address */
-#else
-extern DAT_RETURN DAT_API dapl_lmr_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_MEM_TYPE, /* mem_type */
- IN DAT_REGION_DESCRIPTION, /* region_description */
- IN DAT_VLEN, /* length */
- IN DAT_PZ_HANDLE, /* pz_handle */
- IN DAT_MEM_PRIV_FLAGS, /* privileges */
- IN DAT_VA_TYPE, /* va_type */
- OUT DAT_LMR_HANDLE *, /* lmr_handle */
- OUT DAT_LMR_CONTEXT *, /* lmr_context */
- OUT DAT_RMR_CONTEXT *, /* rmr_context */
- OUT DAT_VLEN *, /* registered_length */
- OUT DAT_VADDR * ); /* registered_address */
-#endif /* defined(__KERNEL__) */
-
-extern DAT_RETURN DAT_API dapl_lmr_query (
- IN DAT_LMR_HANDLE,
- IN DAT_LMR_PARAM_MASK,
- OUT DAT_LMR_PARAM *);
-
-extern DAT_RETURN DAT_API dapl_lmr_free (
- IN DAT_LMR_HANDLE);
-
-extern DAT_RETURN DAT_API dapl_lmr_sync_rdma_read (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN const DAT_LMR_TRIPLET *, /* local_segments */
- IN DAT_VLEN); /* num_segments */
-
-extern DAT_RETURN DAT_API dapl_lmr_sync_rdma_write (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN const DAT_LMR_TRIPLET *, /* local_segments */
- IN DAT_VLEN); /* num_segments */
-
-/* RMR Functions */
-
-extern DAT_RETURN DAT_API dapl_rmr_create (
- IN DAT_PZ_HANDLE, /* pz_handle */
- OUT DAT_RMR_HANDLE *); /* rmr_handle */
-
-extern DAT_RETURN DAT_API dapl_rmr_create_for_ep (
- IN DAT_PZ_HANDLE pz_handle, /* pz_handle */
- OUT DAT_RMR_HANDLE *rmr_handle); /* rmr_handle */
-
-extern DAT_RETURN DAT_API dapl_rmr_query (
- IN DAT_RMR_HANDLE, /* rmr_handle */
- IN DAT_RMR_PARAM_MASK, /* rmr_args_mask */
- OUT DAT_RMR_PARAM *); /* rmr_args */
-
-extern DAT_RETURN DAT_API dapl_rmr_bind (
- IN DAT_RMR_HANDLE, /* rmr_handle */
- IN DAT_LMR_HANDLE, /* lmr_handle */
- IN const DAT_LMR_TRIPLET *, /* lmr_triplet */
- IN DAT_MEM_PRIV_FLAGS, /* mem_priv */
- IN DAT_VA_TYPE, /* va_type */
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_RMR_COOKIE, /* user_cookie */
- IN DAT_COMPLETION_FLAGS, /* completion_flags */
- INOUT DAT_RMR_CONTEXT * ); /* context */
-
-extern DAT_RETURN DAT_API dapl_rmr_free (
- IN DAT_RMR_HANDLE);
-
-/* PSP Functions */
-
-extern DAT_RETURN DAT_API dapl_psp_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_CONN_QUAL, /* conn_qual */
- IN DAT_EVD_HANDLE, /* evd_handle */
- IN DAT_PSP_FLAGS, /* psp_flags */
- OUT DAT_PSP_HANDLE * ); /* psp_handle */
-
-extern DAT_RETURN DAT_API dapl_psp_create_any (
- IN DAT_IA_HANDLE, /* ia_handle */
- OUT DAT_CONN_QUAL *, /* conn_qual */
- IN DAT_EVD_HANDLE, /* evd_handle */
- IN DAT_PSP_FLAGS, /* psp_flags */
- OUT DAT_PSP_HANDLE *); /* psp_handle */
-
-extern DAT_RETURN DAT_API dapl_psp_query (
- IN DAT_PSP_HANDLE,
- IN DAT_PSP_PARAM_MASK,
- OUT DAT_PSP_PARAM * );
-
-extern DAT_RETURN DAT_API dapl_psp_free (
- IN DAT_PSP_HANDLE ); /* psp_handle */
-
-/* RSP Functions */
-
-extern DAT_RETURN DAT_API dapl_rsp_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_CONN_QUAL, /* conn_qual */
- IN DAT_EP_HANDLE, /* ep_handle */
- IN DAT_EVD_HANDLE, /* evd_handle */
- OUT DAT_RSP_HANDLE * ); /* rsp_handle */
-
-extern DAT_RETURN DAT_API dapl_rsp_query (
- IN DAT_RSP_HANDLE,
- IN DAT_RSP_PARAM_MASK,
- OUT DAT_RSP_PARAM * );
-
-extern DAT_RETURN DAT_API dapl_rsp_free (
- IN DAT_RSP_HANDLE ); /* rsp_handle */
-
-/* PZ Functions */
-
-extern DAT_RETURN DAT_API dapl_pz_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- OUT DAT_PZ_HANDLE * ); /* pz_handle */
-
-extern DAT_RETURN DAT_API dapl_pz_query (
- IN DAT_PZ_HANDLE, /* pz_handle */
- IN DAT_PZ_PARAM_MASK, /* pz_args_mask */
- OUT DAT_PZ_PARAM * ); /* pz_args */
-
-extern DAT_RETURN DAT_API dapl_pz_free (
- IN DAT_PZ_HANDLE ); /* pz_handle */
-
-/* SRQ functions */
-
-extern DAT_RETURN DAT_API dapl_srq_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_PZ_HANDLE, /* pz_handle */
- IN DAT_SRQ_ATTR *, /* srq_attr */
- OUT DAT_SRQ_HANDLE *); /* srq_handle */
-
-extern DAT_RETURN DAT_API dapl_srq_free (
- IN DAT_SRQ_HANDLE); /* srq_handle */
-
-extern DAT_RETURN DAT_API dapl_srq_post_recv (
- IN DAT_SRQ_HANDLE, /* srq_handle */
- IN DAT_COUNT, /* num_segments */
- IN DAT_LMR_TRIPLET *, /* local_iov */
- IN DAT_DTO_COOKIE); /* user_cookie */
-
-extern DAT_RETURN DAT_API dapl_srq_query (
- IN DAT_SRQ_HANDLE, /* srq_handle */
- IN DAT_SRQ_PARAM_MASK, /* srq_param_mask */
- OUT DAT_SRQ_PARAM *); /* srq_param */
-
-extern DAT_RETURN DAT_API dapl_srq_resize (
- IN DAT_SRQ_HANDLE, /* srq_handle */
- IN DAT_COUNT); /* srq_max_recv_dto */
-
-extern DAT_RETURN DAT_API dapl_srq_set_lw (
- IN DAT_SRQ_HANDLE, /* srq_handle */
- IN DAT_COUNT); /* low_watermark */
-
-/* CSP functions */
-extern DAT_RETURN DAT_API dapl_csp_create (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN DAT_COMM *, /* communicator */
- IN DAT_IA_ADDRESS_PTR, /* address */
- IN DAT_EVD_HANDLE, /* evd_handle */
- OUT DAT_CSP_HANDLE *); /* csp_handle */
-
-extern DAT_RETURN DAT_API dapl_csp_query (
- IN DAT_CSP_HANDLE, /* csp_handle */
- IN DAT_CSP_PARAM_MASK, /* csp_param_mask */
- OUT DAT_CSP_PARAM *); /* csp_param */
-
-extern DAT_RETURN DAT_API dapl_csp_free (
- IN DAT_CSP_HANDLE); /* csp_handle */
-
-/* HA functions */
-DAT_RETURN DAT_API dapl_ia_ha (
- IN DAT_IA_HANDLE, /* ia_handle */
- IN const DAT_NAME_PTR, /* provider */
- OUT DAT_BOOLEAN *); /* answer */
-
-#ifdef DAT_EXTENSIONS
-#include <stdarg.h>
-extern DAT_RETURN DAT_API dapl_extensions (
- IN DAT_HANDLE, /* handle */
- IN DAT_EXTENDED_OP, /* extended op */
- IN va_list); /* argument list */
-#endif
-
-/*
- * DAPL internal utility function prototpyes
- */
-
-extern void dapl_llist_init_head (
- DAPL_LLIST_HEAD * head);
-
-extern void dapl_llist_init_entry (
- DAPL_LLIST_ENTRY * entry);
-
-extern DAT_BOOLEAN dapl_llist_is_empty (
- DAPL_LLIST_HEAD * head);
-
-extern void dapl_llist_add_head (
- DAPL_LLIST_HEAD * head,
- DAPL_LLIST_ENTRY * entry,
- void * data);
-
-extern void dapl_llist_add_tail (
- DAPL_LLIST_HEAD * head,
- DAPL_LLIST_ENTRY * entry,
- void * data);
-
-extern void dapl_llist_add_entry (
- DAPL_LLIST_HEAD * head,
- DAPL_LLIST_ENTRY * entry,
- DAPL_LLIST_ENTRY * new_entry,
- void * data);
-
-extern void * dapl_llist_remove_head (
- DAPL_LLIST_HEAD * head);
-
-extern void * dapl_llist_remove_tail (
- DAPL_LLIST_HEAD * head);
-
-extern void * dapl_llist_remove_entry (
- DAPL_LLIST_HEAD * head,
- DAPL_LLIST_ENTRY * entry);
-
-extern void * dapl_llist_peek_head (
- DAPL_LLIST_HEAD * head);
-
-extern void * dapl_llist_next_entry (
- IN DAPL_LLIST_HEAD *head,
- IN DAPL_LLIST_ENTRY *cur_ent);
-
-extern void dapl_llist_debug_print_list (
- DAPL_LLIST_HEAD * head);
-
-
-#endif
+/*\r
+ * Copyright (c) 2002-2005, Network Appliance, 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
+ * in the file LICENSE.txt in the root directory. The license is also\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 in the file\r
+ * LICENSE2.txt in the root directory. The license is also available from\r
+ * 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 in the file LICENSE3.txt in the root directory. The \r
+ * license is also 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.h\r
+ *\r
+ * PURPOSE: defines common data structures for the DAPL reference implemenation\r
+ *\r
+ * Description: This file describes the working data structures used within\r
+ * DAPL RI.\r
+ *\r
+ *\r
+ * $Id: dapl.h 1317 2005-04-25 17:29:42Z jlentini $\r
+ **********************************************************************/\r
+\r
+#ifndef _DAPL_H_\r
+#define _DAPL_H_\r
+\r
+#if defined(__KERNEL__)\r
+#include <dat2/kdat.h>\r
+#else\r
+#include <dat2/udat.h>\r
+#endif /* defined(__KERNEL__) */\r
+#include <dat2/dat_registry.h>\r
+#include "dapl_osd.h"\r
+#include "dapl_debug.h"\r
+\r
+\r
+\r
+/*********************************************************************\r
+ * *\r
+ * Enumerations *\r
+ * *\r
+ *********************************************************************/\r
+\r
+typedef enum dapl_magic\r
+{\r
+ /* magic number values for verification & debug */\r
+ DAPL_MAGIC_IA = 0xCafeF00d,\r
+ DAPL_MAGIC_EVD = 0xFeedFace,\r
+ DAPL_MAGIC_EP = 0xDeadBabe,\r
+ DAPL_MAGIC_LMR = 0xBeefCafe,\r
+ DAPL_MAGIC_RMR = 0xABadCafe,\r
+ DAPL_MAGIC_PZ = 0xDeafBeef,\r
+ DAPL_MAGIC_PSP = 0xBeadeD0c,\r
+ DAPL_MAGIC_RSP = 0xFab4Feed,\r
+ DAPL_MAGIC_SRQ = 0xC001Babe,\r
+ DAPL_MAGIC_CR = 0xBe12Cee1,\r
+ DAPL_MAGIC_CR_DESTROYED = 0xB12bDead,\r
+ DAPL_MAGIC_CNO = 0xDeadF00d,\r
+ DAPL_MAGIC_INVALID = 0xFFFFFFFF\r
+} DAPL_MAGIC;\r
+\r
+typedef enum dapl_evd_state\r
+{\r
+ DAPL_EVD_STATE_TERMINAL,\r
+ DAPL_EVD_STATE_INITIAL,\r
+ DAPL_EVD_STATE_OPEN,\r
+ DAPL_EVD_STATE_WAITED,\r
+ DAPL_EVD_STATE_DEAD = 0xDEAD\r
+} DAPL_EVD_STATE;\r
+\r
+typedef enum dapl_evd_completion\r
+{\r
+ DAPL_EVD_STATE_INIT,\r
+ DAPL_EVD_STATE_SOLICITED_WAIT,\r
+ DAPL_EVD_STATE_THRESHOLD,\r
+ DAPL_EVD_STATE_UNSIGNALLED\r
+} DAPL_EVD_COMPLETION;\r
+\r
+typedef enum dapl_cno_state\r
+{\r
+ DAPL_CNO_STATE_UNTRIGGERED,\r
+ DAPL_CNO_STATE_TRIGGERED,\r
+ DAPL_CNO_STATE_DEAD = 0xDeadFeed,\r
+} DAPL_CNO_STATE;\r
+\r
+typedef enum dapl_qp_state\r
+{\r
+ DAPL_QP_STATE_UNCONNECTED,\r
+ DAPL_QP_STATE_RESERVED,\r
+ DAPL_QP_STATE_PASSIVE_CONNECTION_PENDING,\r
+ DAPL_QP_STATE_ACTIVE_CONNECTION_PENDING,\r
+ DAPL_QP_STATE_TENTATIVE_CONNECTION_PENDING,\r
+ DAPL_QP_STATE_CONNECTED,\r
+ DAPL_QP_STATE_DISCONNECT_PENDING,\r
+ DAPL_QP_STATE_ERROR,\r
+ DAPL_QP_STATE_NOT_REUSABLE,\r
+ DAPL_QP_STATE_FREE\r
+} DAPL_QP_STATE;\r
+\r
+\r
+/*********************************************************************\r
+ * *\r
+ * Constants *\r
+ * *\r
+ *********************************************************************/\r
+\r
+/*\r
+ * number of HCAs allowed\r
+ */\r
+#define DAPL_MAX_HCA_COUNT 4\r
+\r
+/*\r
+ * Configures the RMR bind evd restriction\r
+ */\r
+\r
+#define DAPL_RMR_BIND_EVD_RESTRICTION DAT_RMR_EVD_SAME_AS_REQUEST_EVD\r
+\r
+/*\r
+ * special qp_state indicating the EP does not have a QP attached yet\r
+ */\r
+#define DAPL_QP_STATE_UNATTACHED 0xFFF0\r
+\r
+#define DAPL_MAX_PRIVATE_DATA_SIZE 256\r
+\r
+/*********************************************************************\r
+ * *\r
+ * Macros *\r
+ * *\r
+ *********************************************************************/\r
+\r
+#if defined (sun) || defined(__sun) || defined(_sun_) || defined (__solaris__) \r
+#define DAPL_BAD_PTR(a) ((unsigned long)(a) & 3)\r
+#elif defined(__linux__)\r
+#define DAPL_BAD_PTR(a) ((unsigned long)(a) & 3)\r
+#elif defined(_WIN64)\r
+#define DAPL_BAD_PTR(a) ((unsigned long)((DAT_UINT64)(a)) & 3)\r
+#elif defined(_WIN32)\r
+#define DAPL_BAD_PTR(a) ((unsigned long)((DAT_UINT64)(a)) & 3)\r
+#endif\r
+\r
+/*\r
+ * Simple macro to verify a handle is bad. Conditions:\r
+ * - pointer is NULL\r
+ * - pointer is not word aligned\r
+ * - pointer's magic number is wrong\r
+ */\r
+\r
+#define DAPL_BAD_HANDLE(h, magicNum) ( \\r
+ ((h) == NULL) || \\r
+ DAPL_BAD_PTR(h) || \\r
+ (((DAPL_HEADER *)(h))->magic != (magicNum)))\r
+\r
+#define DAPL_MIN(a, b) ((a < b) ? (a) : (b))\r
+#define DAPL_MAX(a, b) ((a > b) ? (a) : (b))\r
+\r
+#if NDEBUG > 0\r
+#define DEBUG_IS_BAD_HANDLE(h, magicNum) (DAPL_BAD_HANDLE(h, magicNum))\r
+#else\r
+#define DEBUG_IS_BAD_HANDLE(h, magicNum) (0)\r
+#endif\r
+\r
+#define DAT_ERROR(Type, SubType) ((DAT_RETURN)(DAT_CLASS_ERROR | Type | SubType))\r
+\r
+/*********************************************************************\r
+ * *\r
+ * Typedefs *\r
+ * *\r
+ *********************************************************************/\r
+\r
+typedef struct dapl_llist_entry DAPL_LLIST_ENTRY;\r
+typedef DAPL_LLIST_ENTRY * DAPL_LLIST_HEAD;\r
+typedef struct dapl_ring_buffer DAPL_RING_BUFFER;\r
+typedef struct dapl_cookie_buffer DAPL_COOKIE_BUFFER;\r
+\r
+typedef struct dapl_hash_table DAPL_HASH_TABLE;\r
+typedef struct dapl_hash_table * DAPL_HASH_TABLEP;\r
+typedef DAT_UINT64 DAPL_HASH_KEY;\r
+typedef void * DAPL_HASH_DATA;\r
+\r
+typedef struct dapl_hca DAPL_HCA;\r
+\r
+typedef struct dapl_header DAPL_HEADER;\r
+\r
+typedef struct dapl_ia DAPL_IA;\r
+typedef struct dapl_cno DAPL_CNO;\r
+typedef struct dapl_evd DAPL_EVD;\r
+typedef struct dapl_ep DAPL_EP;\r
+typedef struct dapl_srq DAPL_SRQ;\r
+typedef struct dapl_pz DAPL_PZ;\r
+typedef struct dapl_lmr DAPL_LMR;\r
+typedef struct dapl_rmr DAPL_RMR;\r
+typedef struct dapl_sp DAPL_SP;\r
+typedef struct dapl_cr DAPL_CR;\r
+\r
+typedef struct dapl_cookie DAPL_COOKIE;\r
+typedef struct dapl_dto_cookie DAPL_DTO_COOKIE;\r
+typedef struct dapl_rmr_cookie DAPL_RMR_COOKIE;\r
+\r
+typedef struct dapl_private DAPL_PRIVATE;\r
+\r
+\r
+\r
+/*********************************************************************\r
+ * *\r
+ * Structures *\r
+ * *\r
+ *********************************************************************/\r
+\r
+struct dapl_llist_entry\r
+{\r
+ struct dapl_llist_entry *flink;\r
+ struct dapl_llist_entry *blink;\r
+ void *data;\r
+ DAPL_LLIST_HEAD *list_head; /* for consistency checking */\r
+};\r
+\r
+struct dapl_ring_buffer\r
+{\r
+ void **base; /* base of element array */\r
+ DAT_COUNT lim; /* mask, number of entries - 1 */\r
+ DAPL_ATOMIC head; /* head pointer index */\r
+ DAPL_ATOMIC tail; /* tail pointer index */\r
+};\r
+\r
+struct dapl_cookie_buffer\r
+{\r
+ DAPL_COOKIE *pool;\r
+ DAT_COUNT pool_size;\r
+ DAPL_ATOMIC head;\r
+ DAPL_ATOMIC tail;\r
+};\r
+\r
+#ifdef IBAPI\r
+#include "dapl_ibapi_util.h"\r
+#elif VAPI\r
+#include "dapl_vapi_util.h"\r
+#elif __OPENIB__\r
+#include "dapl_openib_util.h"\r
+#include "dapl_openib_cm.h"\r
+#elif DUMMY\r
+#include "dapl_dummy_util.h"\r
+#elif OPENIB\r
+#include "dapl_ib_util.h"\r
+#else /* windows - IBAL and/or IBAL+Sock_CM */\r
+#include "dapl_ibal_util.h"\r
+#endif\r
+\r
+struct dapl_hca\r
+{\r
+ DAPL_OS_LOCK lock;\r
+ DAPL_LLIST_HEAD ia_list_head; /* list of all open IAs */\r
+ DAPL_ATOMIC handle_ref_count; /* count of ia_opens on handle */\r
+ DAPL_EVD *async_evd;\r
+ DAPL_EVD *async_error_evd;\r
+ DAT_SOCK_ADDR6 hca_address; /* local address of HCA*/\r
+ char *name; /* provider name */\r
+ ib_hca_handle_t ib_hca_handle;\r
+ unsigned long port_num; /* physical port number */\r
+ ib_hca_transport_t ib_trans; /* Values specific transport API */\r
+ /* Memory Subsystem Support */\r
+ DAPL_HASH_TABLE *lmr_hash_table;\r
+ /* Limits & useful HCA attributes */\r
+ DAT_IA_ATTR ia_attr;\r
+};\r
+\r
+/* DAPL Objects always have the following header */\r
+struct dapl_header\r
+{\r
+ DAT_PROVIDER *provider; /* required by DAT - must be first */\r
+ DAPL_MAGIC magic; /* magic number for verification */\r
+ DAT_HANDLE_TYPE handle_type; /* struct type */\r
+ DAPL_IA *owner_ia; /* ia which owns this stuct */\r
+ DAPL_LLIST_ENTRY ia_list_entry; /* link entry on ia struct */\r
+ DAT_CONTEXT user_context; /* user context - opaque to DAPL */\r
+ DAPL_OS_LOCK lock; /* lock - in header for easier macros */\r
+};\r
+\r
+/* DAPL_IA maps to DAT_IA_HANDLE */\r
+struct dapl_ia\r
+{\r
+ DAPL_HEADER header;\r
+ DAPL_HCA *hca_ptr;\r
+ DAPL_EVD *async_error_evd;\r
+ DAT_BOOLEAN cleanup_async_error_evd;\r
+\r
+ DAPL_LLIST_ENTRY hca_ia_list_entry; /* HCAs list of IAs */\r
+ DAPL_LLIST_HEAD ep_list_head; /* EP queue */\r
+ DAPL_LLIST_HEAD lmr_list_head; /* LMR queue */\r
+ DAPL_LLIST_HEAD rmr_list_head; /* RMR queue */\r
+ DAPL_LLIST_HEAD pz_list_head; /* PZ queue */\r
+ DAPL_LLIST_HEAD evd_list_head; /* EVD queue */\r
+ DAPL_LLIST_HEAD cno_list_head; /* CNO queue */\r
+ DAPL_LLIST_HEAD psp_list_head; /* PSP queue */\r
+ DAPL_LLIST_HEAD rsp_list_head; /* RSP queue */\r
+ DAPL_LLIST_HEAD srq_list_head; /* SRQ queue */\r
+#ifdef DAPL_COUNTERS\r
+ void *cntrs;\r
+#endif\r
+};\r
+\r
+/* DAPL_CNO maps to DAT_CNO_HANDLE */\r
+struct dapl_cno\r
+{\r
+ DAPL_HEADER header;\r
+\r
+ /* A CNO cannot be freed while it is referenced elsewhere. */\r
+ DAPL_ATOMIC cno_ref_count;\r
+ DAPL_CNO_STATE cno_state;\r
+\r
+ DAT_COUNT cno_waiters;\r
+ DAPL_EVD *cno_evd_triggered;\r
+#if defined(__KERNEL__)\r
+ DAT_UPCALL_OBJECT cno_upcall;\r
+ DAT_UPCALL_POLICY cno_upcall_policy;\r
+#else\r
+ DAT_OS_WAIT_PROXY_AGENT cno_wait_agent;\r
+#endif /* defined(__KERNEL__) */\r
+\r
+ DAPL_OS_WAIT_OBJECT cno_wait_object;\r
+};\r
+\r
+/* DAPL_EVD maps to DAT_EVD_HANDLE */\r
+struct dapl_evd\r
+{\r
+ DAPL_HEADER header;\r
+\r
+ DAPL_EVD_STATE evd_state;\r
+ DAT_EVD_FLAGS evd_flags;\r
+ DAT_BOOLEAN evd_enabled; /* For attached CNO. */\r
+ DAT_BOOLEAN evd_waitable; /* EVD state. */\r
+\r
+ /* Derived from evd_flags; see dapls_evd_internal_create. */\r
+ DAT_BOOLEAN evd_producer_locking_needed;\r
+\r
+ /* Every EVD has a CQ unless it is a SOFTWARE_EVENT only EVD */\r
+ ib_cq_handle_t ib_cq_handle;\r
+\r
+ /* An Event Dispatcher cannot be freed while\r
+ * it is referenced elsewhere.\r
+ */\r
+ DAPL_ATOMIC evd_ref_count;\r
+\r
+ /* Set if there has been a catastrophic overflow */\r
+ DAT_BOOLEAN catastrophic_overflow;\r
+\r
+ /* the actual events */\r
+ DAT_COUNT qlen;\r
+ DAT_EVENT *events;\r
+ DAPL_RING_BUFFER free_event_queue;\r
+ DAPL_RING_BUFFER pending_event_queue;\r
+\r
+ /* CQ Completions are not placed into 'deferred_events'\r
+ ** rather they are simply left on the Completion Queue\r
+ ** and the fact that there was a notification is flagged.\r
+ */\r
+ DAT_BOOLEAN cq_notified;\r
+ DAPL_OS_TICKS cq_notified_when;\r
+\r
+ DAT_COUNT cno_active_count;\r
+ DAPL_CNO *cno_ptr;\r
+\r
+ DAPL_OS_WAIT_OBJECT wait_object;\r
+\r
+ DAT_COUNT threshold;\r
+ DAPL_EVD_COMPLETION completion_type;\r
+\r
+#ifdef DAPL_COUNTERS\r
+ void *cntrs;\r
+#endif\r
+};\r
+\r
+/* DAPL_PRIVATE used to pass private data in a connection */\r
+struct dapl_private\r
+{\r
+#ifdef IBHOSTS_NAMING\r
+ DAT_SOCK_ADDR6 hca_address; /* local address of HCA*/\r
+#endif /* IBHOSTS_NAMING */\r
+ unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE];\r
+};\r
+\r
+/* uDAPL timer entry, used to queue timeouts */\r
+struct dapl_timer_entry\r
+{\r
+ DAPL_LLIST_ENTRY list_entry; /* link entry on ia struct */\r
+ DAPL_OS_TIMEVAL expires;\r
+ void (*function) (uintptr_t);\r
+ void *data;\r
+};\r
+\r
+#ifdef DAPL_DBG_IO_TRC\r
+\r
+#define DBG_IO_TRC_QLEN 32 /* length of trace buffer */\r
+#define DBG_IO_TRC_IOV 3 /* iov elements we keep track of */\r
+\r
+struct io_buf_track\r
+{\r
+ Ib_send_op_type op_type;\r
+ DAPL_COOKIE *cookie;\r
+ DAT_LMR_TRIPLET iov[DBG_IO_TRC_IOV];\r
+ DAT_RMR_TRIPLET remote_iov;\r
+ unsigned int done; /* count to track completion ordering */\r
+ int status;\r
+ void *wqe;\r
+};\r
+\r
+#endif /* DAPL_DBG_IO_TRC */\r
+\r
+/* DAPL_EP maps to DAT_EP_HANDLE */\r
+struct dapl_ep\r
+{\r
+ DAPL_HEADER header;\r
+ /* What the DAT Consumer asked for */\r
+ DAT_EP_PARAM param;\r
+\r
+ /* The RC Queue Pair (IBM OS API) */\r
+ ib_qp_handle_t qp_handle;\r
+ unsigned int qpn; /* qp number */\r
+ ib_qp_state_t qp_state;\r
+\r
+ /* communications manager handle (IBM OS API) */\r
+ // dp_ib_cm_handle_t cm_handle;\r
+\r
+ /* Add support for multiple CM object ownership */\r
+ DAPL_LLIST_HEAD cm_list_head; \r
+\r
+ /* store the remote IA address here, reference from the param\r
+ * struct which only has a pointer, no storage\r
+ */\r
+ DAT_SOCK_ADDR6 remote_ia_address;\r
+\r
+ /* For passive connections we maintain a back pointer to the CR */\r
+ void * cr_ptr;\r
+\r
+ /* pointer to connection timer, if set */\r
+ struct dapl_timer_entry *cxn_timer;\r
+\r
+ /* private data container */\r
+ DAPL_PRIVATE private;\r
+\r
+ /* DTO data */\r
+ DAPL_ATOMIC req_count;\r
+ DAPL_ATOMIC recv_count;\r
+\r
+ DAPL_COOKIE_BUFFER req_buffer;\r
+ DAPL_COOKIE_BUFFER recv_buffer;\r
+\r
+#ifdef DAPL_DBG_IO_TRC\r
+ int ibt_dumped;\r
+ struct io_buf_track *ibt_base;\r
+ DAPL_RING_BUFFER ibt_queue;\r
+#endif /* DAPL_DBG_IO_TRC */\r
+#if defined(_WIN32) || defined(_WIN64)\r
+ DAT_BOOLEAN recv_discreq;\r
+ DAT_BOOLEAN sent_discreq;\r
+#endif\r
+#ifdef DAPL_COUNTERS\r
+ void *cntrs;\r
+#endif\r
+};\r
+\r
+/* DAPL_SRQ maps to DAT_SRQ_HANDLE */\r
+struct dapl_srq\r
+{\r
+ DAPL_HEADER header;\r
+ DAT_SRQ_PARAM param;\r
+ DAPL_ATOMIC srq_ref_count;\r
+ DAPL_COOKIE_BUFFER recv_buffer;\r
+ DAPL_ATOMIC recv_count;\r
+};\r
+\r
+/* DAPL_PZ maps to DAT_PZ_HANDLE */\r
+struct dapl_pz\r
+{\r
+ DAPL_HEADER header;\r
+ ib_pd_handle_t pd_handle;\r
+ DAPL_ATOMIC pz_ref_count;\r
+};\r
+\r
+/* DAPL_LMR maps to DAT_LMR_HANDLE */\r
+struct dapl_lmr\r
+{\r
+ DAPL_HEADER header;\r
+ DAT_LMR_PARAM param;\r
+ ib_mr_handle_t mr_handle;\r
+ DAPL_ATOMIC lmr_ref_count;\r
+#if !defined(__KDAPL__)\r
+ char shmid[DAT_LMR_COOKIE_SIZE]; /* shared memory ID */\r
+ ib_shm_transport_t ib_trans; /* provider specific data */\r
+#endif /* !__KDAPL__ */\r
+};\r
+\r
+/* DAPL_RMR maps to DAT_RMR_HANDLE */\r
+struct dapl_rmr\r
+{\r
+ DAPL_HEADER header;\r
+ DAT_RMR_PARAM param;\r
+ DAPL_EP *ep;\r
+ DAPL_PZ *pz;\r
+ DAPL_LMR *lmr;\r
+ ib_mw_handle_t mw_handle;\r
+};\r
+\r
+/* SP types, indicating the state and queue */\r
+typedef enum dapl_sp_state\r
+{\r
+ DAPL_SP_STATE_FREE,\r
+ DAPL_SP_STATE_PSP_LISTENING,\r
+ DAPL_SP_STATE_PSP_PENDING,\r
+ DAPL_SP_STATE_RSP_LISTENING,\r
+ DAPL_SP_STATE_RSP_PENDING\r
+} DAPL_SP_STATE;\r
+\r
+/* DAPL_SP maps to DAT_PSP_HANDLE and DAT_RSP_HANDLE */\r
+struct dapl_sp\r
+{\r
+ DAPL_HEADER header;\r
+ DAPL_SP_STATE state; /* type and queue of the SP */\r
+\r
+ /* PSP/RSP PARAM fields */\r
+ DAT_CONN_QUAL conn_qual;\r
+ DAT_EVD_HANDLE evd_handle;\r
+ DAT_PSP_FLAGS psp_flags;\r
+ DAT_EP_HANDLE ep_handle;\r
+\r
+ /* maintenence fields */\r
+ DAT_BOOLEAN listening; /* PSP is registered & active */\r
+ ib_cm_srvc_handle_t cm_srvc_handle; /* Used by Mellanox CM */\r
+ DAPL_LLIST_HEAD cr_list_head; /* CR pending queue */\r
+ DAT_COUNT cr_list_count; /* count of CRs on queue */\r
+#if defined(_VENDOR_IBAL_)\r
+ DAPL_OS_WAIT_OBJECT wait_object; /* cancel & destroy. */\r
+#endif\r
+};\r
+\r
+/* DAPL_CR maps to DAT_CR_HANDLE */\r
+struct dapl_cr\r
+{\r
+ DAPL_HEADER header;\r
+\r
+ /* for convenience the data is kept as a DAT_CR_PARAM.\r
+ * however, the "local_endpoint" field is always NULL\r
+ * so this wastes a pointer. This is probably ok to\r
+ * simplify code, espedially dat_cr_query.\r
+ */\r
+ DAT_CR_PARAM param;\r
+ /* IB specific fields */\r
+ dp_ib_cm_handle_t ib_cm_handle;\r
+\r
+ DAT_SOCK_ADDR6 remote_ia_address;\r
+ /* Assuming that the maximum private data size is small.\r
+ * If it gets large, use of a pointer may be appropriate.\r
+ */\r
+ unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE];\r
+ /*\r
+ * Need to be able to associate the CR back to the PSP for\r
+ * dapl_cr_reject.\r
+ */\r
+ DAPL_SP *sp_ptr;\r
+};\r
+\r
+typedef enum dapl_dto_type\r
+{\r
+ DAPL_DTO_TYPE_SEND,\r
+ DAPL_DTO_TYPE_RECV,\r
+ DAPL_DTO_TYPE_RDMA_WRITE,\r
+ DAPL_DTO_TYPE_RDMA_READ,\r
+#ifdef DAT_EXTENSIONS\r
+ DAPL_DTO_TYPE_EXTENSION,\r
+#endif\r
+} DAPL_DTO_TYPE;\r
+\r
+typedef enum dapl_cookie_type\r
+{\r
+ DAPL_COOKIE_TYPE_NULL,\r
+ DAPL_COOKIE_TYPE_DTO,\r
+ DAPL_COOKIE_TYPE_RMR,\r
+} DAPL_COOKIE_TYPE;\r
+\r
+/* DAPL_DTO_COOKIE used as context for DTO WQEs */\r
+struct dapl_dto_cookie\r
+{\r
+ DAPL_DTO_TYPE type;\r
+ DAT_DTO_COOKIE cookie;\r
+ DAT_COUNT size; /* used for SEND and RDMA write */\r
+};\r
+\r
+/* DAPL_RMR_COOKIE used as context for bind WQEs */\r
+struct dapl_rmr_cookie\r
+{\r
+ DAPL_RMR *rmr;\r
+ DAT_RMR_COOKIE cookie;\r
+};\r
+\r
+/* DAPL_COOKIE used as context for WQEs */\r
+struct dapl_cookie\r
+{\r
+ DAPL_COOKIE_TYPE type; /* Must be first, to define struct. */\r
+ DAPL_EP *ep;\r
+ DAT_COUNT index;\r
+ union\r
+ {\r
+ DAPL_DTO_COOKIE dto;\r
+ DAPL_RMR_COOKIE rmr;\r
+ } val;\r
+};\r
+\r
+/*\r
+ * Private Data operations. Used to obtain the size of the private\r
+ * data from the provider layer.\r
+ */\r
+typedef enum dapl_private_data_op\r
+{\r
+ DAPL_PDATA_CONN_REQ = 0, /* connect request */\r
+ DAPL_PDATA_CONN_REP = 1, /* connect reply */\r
+ DAPL_PDATA_CONN_REJ = 2, /* connect reject */\r
+ DAPL_PDATA_CONN_DREQ = 3, /* disconnect request */\r
+ DAPL_PDATA_CONN_DREP = 4, /* disconnect reply */\r
+} DAPL_PDATA_OP;\r
+\r
+\r
+/*\r
+ * Generic HCA name field\r
+ */\r
+#define DAPL_HCA_NAME_MAX_LEN 260\r
+typedef char DAPL_HCA_NAME[DAPL_HCA_NAME_MAX_LEN+1];\r
+\r
+#ifdef IBHOSTS_NAMING\r
+\r
+/*\r
+ * Simple mapping table to match IP addresses to GIDs. Loaded\r
+ * by dapl_init.\r
+ */\r
+typedef struct _dapl_gid_map_table\r
+{\r
+ uint32_t ip_address;\r
+ ib_gid_t gid;\r
+} DAPL_GID_MAP;\r
+\r
+#endif /* IBHOSTS_NAMING */\r
+\r
+/*\r
+ * IBTA defined reason for reject message: See IBTA 1.1 specification,\r
+ * 12.6.7.2 REJECTION REASON section.\r
+ */\r
+#define IB_CM_REJ_REASON_CONSUMER_REJ 0x001C\r
+\r
+\r
+#if defined(DAPL_DBG_IO_TRC)\r
+/*********************************************************************\r
+ * *\r
+ * Debug I/O tracing support prototypes *\r
+ * *\r
+ *********************************************************************/\r
+/*\r
+ * I/O tracing support\r
+ */\r
+void dapls_io_trc_alloc (\r
+ DAPL_EP *ep_ptr);\r
+\r
+void dapls_io_trc_update_completion (\r
+ DAPL_EP *ep_ptr,\r
+ DAPL_COOKIE *cookie,\r
+ ib_uint32_t ib_status );\r
+\r
+void dapls_io_trc_dump (\r
+ DAPL_EP *ep_ptr,\r
+ ib_work_completion_t *cqe_ptr,\r
+ ib_uint32_t ib_status);\r
+\r
+#else /* DAPL_DBG_IO_TRC */\r
+\r
+#define dapls_io_trc_alloc(a)\r
+#define dapls_io_trc_update_completion(a, b, c)\r
+#define dapls_io_trc_dump(a, b, c)\r
+\r
+#endif /* DAPL_DBG_IO_TRC */\r
+\r
+\r
+/*********************************************************************\r
+ * *\r
+ * Function Prototypes *\r
+ * *\r
+ *********************************************************************/\r
+\r
+typedef void (*DAPL_CONNECTION_STATE_HANDLER) (\r
+ IN DAPL_EP *,\r
+ IN ib_cm_events_t,\r
+ IN const void *,\r
+ OUT DAT_EVENT *);\r
+\r
+/*\r
+ * DAT Mandated functions\r
+ */\r
+\r
+extern DAT_RETURN DAT_API dapl_ia_open (\r
+ IN const DAT_NAME_PTR, /* name */\r
+ IN DAT_COUNT, /* asynch_evd_qlen */\r
+ INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */\r
+ OUT DAT_IA_HANDLE *); /* ia_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_ia_close (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_CLOSE_FLAGS ); /* ia_flags */\r
+\r
+\r
+extern DAT_RETURN DAT_API dapl_ia_query (\r
+ IN DAT_IA_HANDLE, /* ia handle */\r
+ OUT DAT_EVD_HANDLE *, /* async_evd_handle */\r
+ IN DAT_IA_ATTR_MASK, /* ia_params_mask */\r
+ OUT DAT_IA_ATTR *, /* ia_params */\r
+ IN DAT_PROVIDER_ATTR_MASK, /* provider_params_mask */\r
+ OUT DAT_PROVIDER_ATTR * ); /* provider_params */\r
+\r
+\r
+/* helper functions */\r
+\r
+extern DAT_RETURN DAT_API dapl_set_consumer_context (\r
+ IN DAT_HANDLE, /* dat handle */\r
+ IN DAT_CONTEXT); /* context */\r
+\r
+extern DAT_RETURN DAT_API dapl_get_consumer_context (\r
+ IN DAT_HANDLE, /* dat handle */\r
+ OUT DAT_CONTEXT * ); /* context */\r
+\r
+extern DAT_RETURN DAT_API dapl_get_handle_type (\r
+ IN DAT_HANDLE,\r
+ OUT DAT_HANDLE_TYPE * );\r
+\r
+/* CNO functions */\r
+\r
+#if !defined(__KERNEL__)\r
+extern DAT_RETURN DAT_API dapl_cno_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_OS_WAIT_PROXY_AGENT, /* agent */\r
+ OUT DAT_CNO_HANDLE *); /* cno_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_cno_modify_agent (\r
+ IN DAT_CNO_HANDLE, /* cno_handle */\r
+ IN DAT_OS_WAIT_PROXY_AGENT); /* agent */\r
+\r
+extern DAT_RETURN DAT_API dapl_cno_query (\r
+ IN DAT_CNO_HANDLE, /* cno_handle */\r
+ IN DAT_CNO_PARAM_MASK, /* cno_param_mask */\r
+ OUT DAT_CNO_PARAM * ); /* cno_param */\r
+\r
+extern DAT_RETURN DAT_API dapl_cno_free (\r
+ IN DAT_CNO_HANDLE); /* cno_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_cno_wait (\r
+ IN DAT_CNO_HANDLE, /* cno_handle */\r
+ IN DAT_TIMEOUT, /* timeout */\r
+ OUT DAT_EVD_HANDLE *); /* evd_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_cno_fd_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ OUT DAT_FD *, /* file_descriptor */\r
+ OUT DAT_CNO_HANDLE *); /* cno_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_cno_trigger (\r
+ IN DAT_CNO_HANDLE, /* cno_handle */\r
+ OUT DAT_EVD_HANDLE *); /* evd_handle */\r
+\r
+#endif /* !defined(__KERNEL__) */\r
+\r
+/* CR Functions */\r
+\r
+extern DAT_RETURN DAT_API dapl_cr_query (\r
+ IN DAT_CR_HANDLE, /* cr_handle */\r
+ IN DAT_CR_PARAM_MASK, /* cr_args_mask */\r
+ OUT DAT_CR_PARAM * ); /* cwr_args */\r
+\r
+extern DAT_RETURN DAT_API dapl_cr_accept (\r
+ IN DAT_CR_HANDLE, /* cr_handle */\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_COUNT, /* private_data_size */\r
+ IN const DAT_PVOID ); /* private_data */\r
+\r
+extern DAT_RETURN DAT_API dapl_cr_reject (\r
+ IN DAT_CR_HANDLE, /* cr_handle */\r
+ IN DAT_COUNT, /* private_data_size */\r
+ IN const DAT_PVOID ); /* private_data */\r
+\r
+extern DAT_RETURN DAT_API dapl_cr_handoff (\r
+ IN DAT_CR_HANDLE, /* cr_handle */\r
+ IN DAT_CONN_QUAL); /* handoff */\r
+\r
+/* EVD Functions */\r
+\r
+#if defined(__KERNEL__)\r
+extern DAT_RETURN DAT_API dapl_ia_memtype_hint (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_MEM_TYPE, /* mem_type */\r
+ IN DAT_VLEN, /* length */\r
+ IN DAT_MEM_OPT, /* mem_optimization */\r
+ OUT DAT_VLEN *, /* suggested_length */\r
+ OUT DAT_VADDR *); /* suggested_alignment */\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_kcreate (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_COUNT, /* evd_min_qlen */\r
+ IN DAT_UPCALL_POLICY, /* upcall_policy */\r
+ IN const DAT_UPCALL_OBJECT *, /* upcall */\r
+ IN DAT_EVD_FLAGS, /* evd_flags */\r
+ OUT DAT_EVD_HANDLE * ); /* evd_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_kquery (\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ IN DAT_EVD_PARAM_MASK, /* evd_args_mask */\r
+ OUT DAT_EVD_PARAM * ); /* evd_args */\r
+\r
+#else\r
+extern DAT_RETURN DAT_API dapl_evd_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_COUNT, /* evd_min_qlen */\r
+ IN DAT_CNO_HANDLE, /* cno_handle */\r
+ IN DAT_EVD_FLAGS, /* evd_flags */\r
+ OUT DAT_EVD_HANDLE * ); /* evd_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_query (\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ IN DAT_EVD_PARAM_MASK, /* evd_args_mask */\r
+ OUT DAT_EVD_PARAM * ); /* evd_args */\r
+#endif /* defined(__KERNEL__) */\r
+\r
+#if defined(__KERNEL__)\r
+extern DAT_RETURN DAT_API dapl_evd_modify_upcall (\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ IN DAT_UPCALL_POLICY, /* upcall_policy */\r
+ IN const DAT_UPCALL_OBJECT * ); /* upcall */\r
+\r
+#else\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_modify_cno (\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ IN DAT_CNO_HANDLE); /* cno_handle */\r
+#endif\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_enable (\r
+ IN DAT_EVD_HANDLE); /* evd_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_disable (\r
+ IN DAT_EVD_HANDLE); /* evd_handle */\r
+\r
+#if !defined(__KERNEL__)\r
+extern DAT_RETURN DAT_API dapl_evd_wait (\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ IN DAT_TIMEOUT, /* timeout */\r
+ IN DAT_COUNT, /* threshold */\r
+ OUT DAT_EVENT *, /* event */\r
+ OUT DAT_COUNT *); /* nmore */\r
+#endif /* !defined(__KERNEL__) */\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_resize (\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ IN DAT_COUNT ); /* evd_qlen */\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_post_se (\r
+ DAT_EVD_HANDLE, /* evd_handle */\r
+ const DAT_EVENT * ); /* event */\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_dequeue (\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ OUT DAT_EVENT * ); /* event */\r
+\r
+extern DAT_RETURN DAT_API dapl_evd_free (\r
+ IN DAT_EVD_HANDLE );\r
+\r
+extern DAT_RETURN DAT_API\r
+dapl_evd_set_unwaitable (\r
+ IN DAT_EVD_HANDLE evd_handle );\r
+\r
+extern DAT_RETURN DAT_API\r
+dapl_evd_clear_unwaitable (\r
+ IN DAT_EVD_HANDLE evd_handle );\r
+\r
+/* EP functions */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_PZ_HANDLE, /* pz_handle */\r
+ IN DAT_EVD_HANDLE, /* in_dto_completion_evd_handle */\r
+ IN DAT_EVD_HANDLE, /* out_dto_completion_evd_handle */\r
+ IN DAT_EVD_HANDLE, /* connect_evd_handle */\r
+ IN const DAT_EP_ATTR *, /* ep_parameters */\r
+ OUT DAT_EP_HANDLE * ); /* ep_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_query (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_EP_PARAM_MASK, /* ep_args_mask */\r
+ OUT DAT_EP_PARAM * ); /* ep_args */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_modify (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_EP_PARAM_MASK, /* ep_args_mask */\r
+ IN const DAT_EP_PARAM * ); /* ep_args */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_connect (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */\r
+ IN DAT_CONN_QUAL, /* remote_conn_qual */\r
+ IN DAT_TIMEOUT, /* timeout */\r
+ IN DAT_COUNT, /* private_data_size */\r
+ IN const DAT_PVOID, /* private_data */\r
+ IN DAT_QOS, /* quality_of_service */\r
+ IN DAT_CONNECT_FLAGS ); /* connect_flags */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_common_connect (\r
+ IN DAT_EP_HANDLE ep, /* ep_handle */\r
+ IN DAT_IA_ADDRESS_PTR remote_addr, /* remote_ia_address */\r
+ IN DAT_TIMEOUT timeout, /* timeout */\r
+ IN DAT_COUNT pdata_size, /* private_data_size */\r
+ IN const DAT_PVOID pdata ); /* private_data */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_dup_connect (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_EP_HANDLE, /* ep_dup_handle */\r
+ IN DAT_TIMEOUT, /* timeout*/\r
+ IN DAT_COUNT, /* private_data_size */\r
+ IN const DAT_PVOID, /* private_data */\r
+ IN DAT_QOS); /* quality_of_service */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_disconnect (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_CLOSE_FLAGS ); /* close_flags */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_post_send (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_COUNT, /* num_segments */\r
+ IN DAT_LMR_TRIPLET *, /* local_iov */\r
+ IN DAT_DTO_COOKIE, /* user_cookie */\r
+ IN DAT_COMPLETION_FLAGS ); /* completion_flags */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_post_recv (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_COUNT, /* num_segments */\r
+ IN DAT_LMR_TRIPLET *, /* local_iov */\r
+ IN DAT_DTO_COOKIE, /* user_cookie */\r
+ IN DAT_COMPLETION_FLAGS ); /* completion_flags */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_post_rdma_read (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_COUNT, /* num_segments */\r
+ IN DAT_LMR_TRIPLET *, /* local_iov */\r
+ IN DAT_DTO_COOKIE, /* user_cookie */\r
+ IN const DAT_RMR_TRIPLET *, /* remote_iov */\r
+ IN DAT_COMPLETION_FLAGS ); /* completion_flags */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_post_rdma_read_to_rmr (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN const DAT_RMR_TRIPLET *,/* local_iov */\r
+ IN DAT_DTO_COOKIE, /* user_cookie */\r
+ IN const DAT_RMR_TRIPLET *,/* remote_iov */\r
+ IN DAT_COMPLETION_FLAGS); /* completion_flags */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_post_rdma_write (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_COUNT, /* num_segments */\r
+ IN DAT_LMR_TRIPLET *, /* local_iov */\r
+ IN DAT_DTO_COOKIE, /* user_cookie */\r
+ IN const DAT_RMR_TRIPLET *, /* remote_iov */\r
+ IN DAT_COMPLETION_FLAGS ); /* completion_flags */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_post_send_with_invalidate (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_COUNT, /* num_segments */\r
+ IN DAT_LMR_TRIPLET *, /* local_iov */\r
+ IN DAT_DTO_COOKIE, /* user_cookie */\r
+ IN DAT_COMPLETION_FLAGS, /* completion_flags */\r
+ IN DAT_BOOLEAN, /* invalidate_flag */\r
+ IN DAT_RMR_CONTEXT); /* RMR context */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_get_status (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ OUT DAT_EP_STATE *, /* ep_state */\r
+ OUT DAT_BOOLEAN *, /* in_dto_idle */\r
+ OUT DAT_BOOLEAN * ); /* out_dto_idle */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_free (\r
+ IN DAT_EP_HANDLE); /* ep_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_reset (\r
+ IN DAT_EP_HANDLE); /* ep_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_create_with_srq (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_PZ_HANDLE, /* pz_handle */\r
+ IN DAT_EVD_HANDLE, /* recv_evd_handle */\r
+ IN DAT_EVD_HANDLE, /* request_evd_handle */\r
+ IN DAT_EVD_HANDLE, /* connect_evd_handle */\r
+ IN DAT_SRQ_HANDLE, /* srq_handle */\r
+ IN const DAT_EP_ATTR *, /* ep_attributes */\r
+ OUT DAT_EP_HANDLE *); /* ep_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_recv_query (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ OUT DAT_COUNT *, /* nbufs_allocated */\r
+ OUT DAT_COUNT *); /* bufs_alloc_span */\r
+\r
+extern DAT_RETURN DAT_API dapl_ep_set_watermark (\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_COUNT, /* soft_high_watermark */\r
+ IN DAT_COUNT); /* hard_high_watermark */\r
+\r
+/* LMR functions */\r
+\r
+#if defined(__KERNEL__)\r
+extern DAT_RETURN DAT_API dapl_lmr_kcreate (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_MEM_TYPE, /* mem_type */\r
+ IN DAT_REGION_DESCRIPTION, /* region_description */\r
+ IN DAT_VLEN, /* length */\r
+ IN DAT_PZ_HANDLE, /* pz_handle */\r
+ IN DAT_MEM_PRIV_FLAGS, /* privileges */\r
+ IN DAT_VA_TYPE, /* va_type */\r
+ IN DAT_MEM_OPT, /* optimization */\r
+ OUT DAT_LMR_HANDLE *, /* lmr_handle */\r
+ OUT DAT_LMR_CONTEXT *, /* lmr_context */\r
+ OUT DAT_RMR_CONTEXT *, /* rmr_context */\r
+ OUT DAT_VLEN *, /* registered_length */\r
+ OUT DAT_VADDR * ); /* registered_address */\r
+#else\r
+extern DAT_RETURN DAT_API dapl_lmr_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_MEM_TYPE, /* mem_type */\r
+ IN DAT_REGION_DESCRIPTION, /* region_description */\r
+ IN DAT_VLEN, /* length */\r
+ IN DAT_PZ_HANDLE, /* pz_handle */\r
+ IN DAT_MEM_PRIV_FLAGS, /* privileges */\r
+ IN DAT_VA_TYPE, /* va_type */\r
+ OUT DAT_LMR_HANDLE *, /* lmr_handle */\r
+ OUT DAT_LMR_CONTEXT *, /* lmr_context */\r
+ OUT DAT_RMR_CONTEXT *, /* rmr_context */\r
+ OUT DAT_VLEN *, /* registered_length */\r
+ OUT DAT_VADDR * ); /* registered_address */\r
+#endif /* defined(__KERNEL__) */\r
+\r
+extern DAT_RETURN DAT_API dapl_lmr_query (\r
+ IN DAT_LMR_HANDLE,\r
+ IN DAT_LMR_PARAM_MASK,\r
+ OUT DAT_LMR_PARAM *);\r
+\r
+extern DAT_RETURN DAT_API dapl_lmr_free (\r
+ IN DAT_LMR_HANDLE);\r
+\r
+extern DAT_RETURN DAT_API dapl_lmr_sync_rdma_read (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN const DAT_LMR_TRIPLET *, /* local_segments */\r
+ IN DAT_VLEN); /* num_segments */\r
+\r
+extern DAT_RETURN DAT_API dapl_lmr_sync_rdma_write (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN const DAT_LMR_TRIPLET *, /* local_segments */\r
+ IN DAT_VLEN); /* num_segments */\r
+\r
+/* RMR Functions */\r
+\r
+extern DAT_RETURN DAT_API dapl_rmr_create (\r
+ IN DAT_PZ_HANDLE, /* pz_handle */\r
+ OUT DAT_RMR_HANDLE *); /* rmr_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_rmr_create_for_ep (\r
+ IN DAT_PZ_HANDLE pz_handle, /* pz_handle */\r
+ OUT DAT_RMR_HANDLE *rmr_handle); /* rmr_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_rmr_query (\r
+ IN DAT_RMR_HANDLE, /* rmr_handle */\r
+ IN DAT_RMR_PARAM_MASK, /* rmr_args_mask */\r
+ OUT DAT_RMR_PARAM *); /* rmr_args */\r
+\r
+extern DAT_RETURN DAT_API dapl_rmr_bind (\r
+ IN DAT_RMR_HANDLE, /* rmr_handle */\r
+ IN DAT_LMR_HANDLE, /* lmr_handle */\r
+ IN const DAT_LMR_TRIPLET *, /* lmr_triplet */\r
+ IN DAT_MEM_PRIV_FLAGS, /* mem_priv */\r
+ IN DAT_VA_TYPE, /* va_type */\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_RMR_COOKIE, /* user_cookie */\r
+ IN DAT_COMPLETION_FLAGS, /* completion_flags */\r
+ INOUT DAT_RMR_CONTEXT * ); /* context */\r
+\r
+extern DAT_RETURN DAT_API dapl_rmr_free (\r
+ IN DAT_RMR_HANDLE);\r
+\r
+/* PSP Functions */\r
+\r
+extern DAT_RETURN DAT_API dapl_psp_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_CONN_QUAL, /* conn_qual */\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ IN DAT_PSP_FLAGS, /* psp_flags */\r
+ OUT DAT_PSP_HANDLE * ); /* psp_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_psp_create_any (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ OUT DAT_CONN_QUAL *, /* conn_qual */\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ IN DAT_PSP_FLAGS, /* psp_flags */\r
+ OUT DAT_PSP_HANDLE *); /* psp_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_psp_query (\r
+ IN DAT_PSP_HANDLE,\r
+ IN DAT_PSP_PARAM_MASK,\r
+ OUT DAT_PSP_PARAM * );\r
+\r
+extern DAT_RETURN DAT_API dapl_psp_free (\r
+ IN DAT_PSP_HANDLE ); /* psp_handle */\r
+\r
+/* RSP Functions */\r
+\r
+extern DAT_RETURN DAT_API dapl_rsp_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_CONN_QUAL, /* conn_qual */\r
+ IN DAT_EP_HANDLE, /* ep_handle */\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ OUT DAT_RSP_HANDLE * ); /* rsp_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_rsp_query (\r
+ IN DAT_RSP_HANDLE,\r
+ IN DAT_RSP_PARAM_MASK,\r
+ OUT DAT_RSP_PARAM * );\r
+\r
+extern DAT_RETURN DAT_API dapl_rsp_free (\r
+ IN DAT_RSP_HANDLE ); /* rsp_handle */\r
+\r
+/* PZ Functions */\r
+\r
+extern DAT_RETURN DAT_API dapl_pz_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ OUT DAT_PZ_HANDLE * ); /* pz_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_pz_query (\r
+ IN DAT_PZ_HANDLE, /* pz_handle */\r
+ IN DAT_PZ_PARAM_MASK, /* pz_args_mask */\r
+ OUT DAT_PZ_PARAM * ); /* pz_args */\r
+\r
+extern DAT_RETURN DAT_API dapl_pz_free (\r
+ IN DAT_PZ_HANDLE ); /* pz_handle */\r
+\r
+/* SRQ functions */\r
+\r
+extern DAT_RETURN DAT_API dapl_srq_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_PZ_HANDLE, /* pz_handle */\r
+ IN DAT_SRQ_ATTR *, /* srq_attr */\r
+ OUT DAT_SRQ_HANDLE *); /* srq_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_srq_free (\r
+ IN DAT_SRQ_HANDLE); /* srq_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_srq_post_recv (\r
+ IN DAT_SRQ_HANDLE, /* srq_handle */\r
+ IN DAT_COUNT, /* num_segments */\r
+ IN DAT_LMR_TRIPLET *, /* local_iov */\r
+ IN DAT_DTO_COOKIE); /* user_cookie */\r
+\r
+extern DAT_RETURN DAT_API dapl_srq_query (\r
+ IN DAT_SRQ_HANDLE, /* srq_handle */\r
+ IN DAT_SRQ_PARAM_MASK, /* srq_param_mask */\r
+ OUT DAT_SRQ_PARAM *); /* srq_param */\r
+\r
+extern DAT_RETURN DAT_API dapl_srq_resize (\r
+ IN DAT_SRQ_HANDLE, /* srq_handle */\r
+ IN DAT_COUNT); /* srq_max_recv_dto */\r
+\r
+extern DAT_RETURN DAT_API dapl_srq_set_lw (\r
+ IN DAT_SRQ_HANDLE, /* srq_handle */\r
+ IN DAT_COUNT); /* low_watermark */\r
+\r
+/* CSP functions */\r
+extern DAT_RETURN DAT_API dapl_csp_create (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN DAT_COMM *, /* communicator */\r
+ IN DAT_IA_ADDRESS_PTR, /* address */\r
+ IN DAT_EVD_HANDLE, /* evd_handle */\r
+ OUT DAT_CSP_HANDLE *); /* csp_handle */\r
+\r
+extern DAT_RETURN DAT_API dapl_csp_query (\r
+ IN DAT_CSP_HANDLE, /* csp_handle */\r
+ IN DAT_CSP_PARAM_MASK, /* csp_param_mask */\r
+ OUT DAT_CSP_PARAM *); /* csp_param */\r
+\r
+extern DAT_RETURN DAT_API dapl_csp_free (\r
+ IN DAT_CSP_HANDLE); /* csp_handle */\r
+\r
+/* HA functions */\r
+DAT_RETURN DAT_API dapl_ia_ha (\r
+ IN DAT_IA_HANDLE, /* ia_handle */\r
+ IN const DAT_NAME_PTR, /* provider */\r
+ OUT DAT_BOOLEAN *); /* answer */\r
+\r
+#ifdef DAT_EXTENSIONS\r
+#include <stdarg.h>\r
+extern DAT_RETURN DAT_API dapl_extensions (\r
+ IN DAT_HANDLE, /* handle */\r
+ IN DAT_EXTENDED_OP, /* extended op */\r
+ IN va_list); /* argument list */\r
+#endif\r
+\r
+/*\r
+ * DAPL internal utility function prototpyes\r
+ */\r
+\r
+extern void dapl_llist_init_head (\r
+ DAPL_LLIST_HEAD * head);\r
+\r
+extern void dapl_llist_init_entry (\r
+ DAPL_LLIST_ENTRY * entry);\r
+\r
+extern DAT_BOOLEAN dapl_llist_is_empty (\r
+ DAPL_LLIST_HEAD * head);\r
+\r
+extern void dapl_llist_add_head (\r
+ DAPL_LLIST_HEAD * head,\r
+ DAPL_LLIST_ENTRY * entry,\r
+ void * data);\r
+\r
+extern void dapl_llist_add_tail (\r
+ DAPL_LLIST_HEAD * head,\r
+ DAPL_LLIST_ENTRY * entry,\r
+ void * data);\r
+\r
+extern void dapl_llist_add_entry (\r
+ DAPL_LLIST_HEAD * head,\r
+ DAPL_LLIST_ENTRY * entry,\r
+ DAPL_LLIST_ENTRY * new_entry,\r
+ void * data);\r
+\r
+extern void * dapl_llist_remove_head (\r
+ DAPL_LLIST_HEAD * head);\r
+\r
+extern void * dapl_llist_remove_tail (\r
+ DAPL_LLIST_HEAD * head);\r
+\r
+extern void * dapl_llist_remove_entry (\r
+ DAPL_LLIST_HEAD * head,\r
+ DAPL_LLIST_ENTRY * entry);\r
+\r
+extern void * dapl_llist_peek_head (\r
+ DAPL_LLIST_HEAD * head);\r
+\r
+extern void * dapl_llist_next_entry (\r
+ IN DAPL_LLIST_HEAD *head,\r
+ IN DAPL_LLIST_ENTRY *cur_ent);\r
+\r
+extern void dapl_llist_debug_print_list (\r
+ DAPL_LLIST_HEAD * head);\r
+\r
+\r
+#endif\r
-/*\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, 0, 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, 0, 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_lock_destroy(&conn->lock);\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_lock_destroy(&conn->lock);\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
+/*
+ * 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_ep_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, 0, 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, 0, 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);
+ dapls_cm_acquire(conn);
+
+ /* create CM_ID, bind to local device, create QP */
+ if (rdma_create_id(g_cm_events, &cm_id, (void *)conn, RDMA_PS_TCP)) {
+ dapls_cm_release(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) {
+ dapl_ep_link_cm(ep, conn);
+ conn->ep = ep;
+ conn->hca = ((DAPL_IA *)ep->param.ia_handle)->hca_ptr;
+ }
+
+ return conn;
+}
+
+static void dapli_cm_dealloc(dp_ib_cm_handle_t conn) {
+
+ dapl_os_assert(!conn->ref_count);
+ dapl_os_lock_destroy(&conn->lock);
+ dapl_os_free(conn, sizeof(*conn));
+}
+
+void dapls_cm_acquire(dp_ib_cm_handle_t conn)
+{
+ dapl_os_lock(&conn->lock);
+ conn->ref_count++;
+ dapl_os_unlock(&conn->lock);
+}
+
+void dapls_cm_release(dp_ib_cm_handle_t conn)
+{
+ dapl_os_lock(&conn->lock);
+ conn->ref_count--;\r
+ if (conn->ref_count) {\r
+ dapl_os_unlock(&conn->lock);\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,\r
- event->param.conn.private_data_len, 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
+ if (conn->cm_id) {
+ if (conn->cm_id->qp)
+ rdma_destroy_qp(conn->cm_id);
+ rdma_destroy_id(conn->cm_id);
}\r
-\r
dapl_os_unlock(&conn->lock);\r
- if (conn_recv)\r
- dapls_cr_callback(conn_recv, ib_cm_event, pdata,\r
- event->param.conn.private_data_len, 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_lock_destroy(&conn->lock);\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_lock_destroy(&conn->lock);\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
- /* 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
-int dapls_ib_private_data_size(\r
- IN DAPL_HCA *hca_ptr)\r
-{\r
- return RDMA_MAX_PRIVATE_DATA;\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, 0, 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, 0, 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, 0, 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
+ dapli_cm_dealloc(conn);\r
+}
+
+/* BLOCKING: called from dapl_ep_free, EP link will be last ref */
+void dapls_cm_free(dp_ib_cm_handle_t conn)
+{
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " cm_free: cm %p ep %p refs=%d\n",
+ conn, conn->ep, conn->ref_count);
+
+ dapls_cm_release(conn); /* release alloc ref */
+
+ /* Destroy cm_id, wait until EP is last ref */
+ dapl_os_lock(&conn->lock);
+ if (conn->cm_id) {
+ if (conn->cm_id->qp)
+ rdma_destroy_qp(conn->cm_id);
+ rdma_destroy_id(conn->cm_id);
+ conn->cm_id = NULL;
+ }
+
+ /* EP linking is last reference */
+ while (conn->ref_count != 1) {
+ dapl_os_unlock(&conn->lock);
+ dapl_os_sleep_usec(10000);
+ dapl_os_lock(&conn->lock);
+ }
+ dapl_os_unlock(&conn->lock);
+
+ /* unlink, dequeue from EP. Final ref so release will destroy */
+ dapl_ep_unlink_cm(conn->ep, 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);
+ dapls_cm_acquire(new_conn);
+ 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;
+
+ /* 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,
+ event->param.conn.private_data_len, 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,
+ event->param.conn.private_data_len, 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 = dapl_get_cm_from_ep(ep_ptr);
+ int ret;
+
+ dapl_os_assert(conn != NULL);
+
+ 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, "rdma_resolve_addr");
+ }
+ 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)
+{
+ struct dapl_cm_id *conn = dapl_get_cm_from_ep(ep_ptr);
+
+ 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 == NULL) || (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 */
+}
+
+/*
+ * 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);
+ dapls_cm_acquire(conn);
+
+ /* create CM_ID, bind to local device, create QP */
+ if (rdma_create_id
+ (g_cm_events, &conn->cm_id, (void *)conn, RDMA_PS_TCP)) {
+ dapls_cm_release(conn);
+ return (dapl_convert_errno(errno, "rdma_create_id"));
+ }
+
+ /* 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) ||
+ (errno == EADDRNOTAVAIL))
+ dat_status = DAT_CONN_QUAL_IN_USE;
+ else
+ dat_status =
+ dapl_convert_errno(errno, "rdma_bind_addr");
+ 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) ||
+ (errno == EADDRNOTAVAIL))
+ dat_status = DAT_CONN_QUAL_IN_USE;
+ else
+ dat_status =
+ dapl_convert_errno(errno, "rdma_listen");
+ goto bail;
+ }
+
+ /* success */
+ return DAT_SUCCESS;
+
+bail:
+ dapls_cm_release(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 conn %p)\n",
+ ia_ptr, sp_ptr, conn);
+
+ if (conn != IB_INVALID_HANDLE) {
+ sp_ptr->cm_srvc_handle = NULL;
+ dapls_cm_release(conn);
+ }
+ 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;
+ struct dapl_cm_id *ep_conn = dapl_get_cm_from_ep(ep_ptr);
+ 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_conn->cm_id->verbs == cr_conn->cm_id->verbs &&
+ ep_conn->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_conn->cm_id->qp;
+
+ /* remove old CM to EP linking, destroy CM object */
+ dapl_ep_unlink_cm(ep_ptr, ep_conn);
+ ep_conn->cm_id->qp = NULL;
+ ep_conn->ep = NULL;
+ dapls_cm_release(ep_conn);
+
+ /* add new CM to EP linking, qp_handle unchanged */
+ dapl_ep_link_cm(ep_ptr, cr_conn);
+ cr_conn->ep = ep_ptr;
+ } else {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " dapl_cma_accept: ERR dev(%p!=%p) or"
+ " port mismatch(%d!=%d)\n",
+ ep_conn->cm_id->verbs, cr_conn->cm_id->verbs,
+ ntohs(ep_conn->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_rdma_accept: ERR %d %s\n",
+ ret, strerror(errno));
+ dat_status = dapl_convert_errno(errno, "accept");
+
+ /* remove new cr_conn EP to CM linking */
+ dapl_ep_unlink_cm(ep_ptr, cr_conn);
+ goto bail;
+ }
+
+ /* 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);
+
+ /* no EP linking, ok to destroy */
+ dapls_cm_release(cr_conn);
+ 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);
+ }
+
+ /* 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);
+
+ /* no EP linking, ok to destroy */
+ dapls_cm_release(cm_handle);
+ 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 conn;
+ 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)
+ conn = dapl_get_cm_from_ep((DAPL_EP *) dat_handle);
+ else if (header->magic == DAPL_MAGIC_CR)
+ conn = ((DAPL_CR *) dat_handle)->ib_cm_handle;
+ else
+ return DAT_INVALID_HANDLE;
+
+ /* get remote IP address from cm_id route */
+ ipaddr = &conn->cm_id->route.addr;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " remote_addr: conn %p id %p SRC %x DST %x PORT %d\n",
+ conn, 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_os_memcpy(raddr, &ipaddr->dst_addr, sizeof(DAT_SOCK_ADDR));
+ return DAT_SUCCESS;
+}
+
+/*
+ * dapls_ib_private_data_size
+ *
+ * Return the size of max private data
+ *
+ * Input:
+ * hca_ptr hca pointer, needed for transport type
+ *
+ * Output:
+ * None
+ *
+ * Returns:
+ * maximum private data rdma_cm will supply from transport.
+ *
+ */
+int dapls_ib_private_data_size(IN DAPL_HCA * hca_ptr)
+{
+ return RDMA_MAX_PRIVATE_DATA;
+}
+
+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;
+
+ dapls_cm_acquire(conn);
+
+ 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);
+
+ 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, 0, 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, 0, conn->ep);
+ }
+ break;
+
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ dapl_evd_connection_callback(conn,
+ IB_CME_LOCAL_FAILURE,
+ NULL, 0, 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);
+ dapls_cm_release(conn);
+ }
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * End:
+ */
#define _OPENIB_CMA_
#include <infiniband/verbs.h>
-#include <rdma/rdma_cma.h>
#include "openib_osd.h"
#include "dapl_ib_common.h"
#define IB_ROUTE_RETRY_COUNT 15 /* 60 sec total */
#define IB_MAX_AT_RETRY 3
-/* CMA private data areas */
+/* CMA private data areas, use CMA max with known transport definitions */
#define CMA_PDATA_HDR 36
-#define IB_MAX_REQ_PDATA_SIZE (92-CMA_PDATA_HDR)
-#define IB_MAX_REP_PDATA_SIZE (196-CMA_PDATA_HDR)
-#define IB_MAX_REJ_PDATA_SIZE (148-CMA_PDATA_HDR)
-#define IB_MAX_DREQ_PDATA_SIZE (220-CMA_PDATA_HDR)
-#define IB_MAX_DREP_PDATA_SIZE (224-CMA_PDATA_HDR)
-#define IWARP_MAX_PDATA_SIZE (512-CMA_PDATA_HDR)
+#define IB_MAX_REQ_PDATA_SIZE DAPL_MIN((92-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA)
+#define IB_MAX_REP_PDATA_SIZE DAPL_MIN((196-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA)
+#define IB_MAX_REJ_PDATA_SIZE DAPL_MIN((148-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA)
+#define IB_MAX_DREQ_PDATA_SIZE DAPL_MIN((220-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA)
+#define IB_MAX_DREP_PDATA_SIZE DAPL_MIN((224-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA)
+#define IWARP_MAX_PDATA_SIZE DAPL_MIN((512-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA)
+/* DAPL CM objects MUST include list_entry, ref_count, event for EP linking */
struct dapl_cm_id {
+ struct dapl_llist_entry list_entry;
+ struct dapl_llist_entry local_entry;
+ DAPL_OS_WAIT_OBJECT event;
DAPL_OS_LOCK lock;
- int refs;
+ int ref_count;
int arp_retries;
int arp_timeout;
int route_retries;
int route_timeout;
- int in_callback;
struct rdma_cm_id *cm_id;
struct dapl_hca *hca;
struct dapl_sp *sp;
void dapli_async_event_cb(struct _ib_hca_transport *tp);
void dapli_cq_event_cb(struct _ib_hca_transport *tp);
dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep);
-void dapls_ib_cm_free(dp_ib_cm_handle_t cm, DAPL_EP *ep);
+void dapls_cm_acquire(dp_ib_cm_handle_t cm);
+void dapls_cm_release(dp_ib_cm_handle_t cm);
+void dapls_cm_free(dp_ib_cm_handle_t cm_ptr);
+#ifdef DAPL_COUNTERS
STATIC _INLINE_ void dapls_print_cm_list(IN DAPL_IA * ia_ptr)
{
return;
}
+#endif
#endif /* _DAPL_IB_UTIL_H_ */
-/*\r
- * Copyright (c) 2005-2008 Intel Corporation. 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_util.c\r
- *\r
- * PURPOSE: OFED provider - init, open, close, utilities, work thread\r
- *\r
- * $Id:$\r
- *\r
- **********************************************************************/\r
-\r
-#ifdef RCSID\r
-static const char rcsid[] = "$Id: $";\r
-#endif\r
-\r
-#include "openib_osd.h"\r
-#include "dapl.h"\r
-#include "dapl_adapter_util.h"\r
-#include "dapl_ib_util.h"\r
-#include "dapl_osd.h"\r
-\r
-#include <stdlib.h>\r
-\r
-struct rdma_event_channel *g_cm_events = NULL;\r
-ib_thread_state_t g_ib_thread_state = 0;\r
-DAPL_OS_THREAD g_ib_thread;\r
-DAPL_OS_LOCK g_hca_lock;\r
-struct dapl_llist_entry *g_hca_list;\r
-\r
-#if defined(_WIN64) || defined(_WIN32)\r
-#include "..\..\..\..\..\etc\user\comp_channel.cpp"\r
-#include <rdma\winverbs.h>\r
-\r
-static COMP_SET ufds;\r
-\r
-static int getipaddr_netdev(char *name, char *addr, int addr_len)\r
-{\r
- IWVProvider *prov;\r
- WV_DEVICE_ADDRESS devaddr;\r
- struct addrinfo *res, *ai;\r
- HRESULT hr;\r
- int index;\r
-\r
- if (strncmp(name, "rdma_dev", 8)) {\r
- return EINVAL;\r
- }\r
-\r
- index = atoi(name + 8);\r
-\r
- hr = WvGetObject(&IID_IWVProvider, (LPVOID *) &prov);\r
- if (FAILED(hr)) {\r
- return hr;\r
- }\r
-\r
- hr = getaddrinfo("..localmachine", NULL, NULL, &res);\r
- if (hr) {\r
- goto release;\r
- }\r
-\r
- for (ai = res; ai; ai = ai->ai_next) {\r
- hr = prov->lpVtbl->TranslateAddress(prov, ai->ai_addr, &devaddr);\r
- if (SUCCEEDED(hr) && (ai->ai_addrlen <= addr_len) && (index-- == 0)) {\r
- memcpy(addr, ai->ai_addr, ai->ai_addrlen);\r
- goto free;\r
- }\r
- }\r
- hr = ENODEV;\r
-\r
-free:\r
- freeaddrinfo(res);\r
-release:\r
- prov->lpVtbl->Release(prov);\r
- return hr;\r
-}\r
-\r
-static int dapls_os_init(void)\r
-{\r
- return CompSetInit(&ufds);\r
-}\r
-\r
-static void dapls_os_release(void)\r
-{\r
- CompSetCleanup(&ufds);\r
-}\r
-\r
-static int dapls_config_cm_channel(struct rdma_event_channel *channel)\r
-{\r
- channel->channel.Milliseconds = 0;\r
- return 0;\r
-}\r
-\r
-static int dapls_config_verbs(struct ibv_context *verbs)\r
-{\r
- verbs->channel.Milliseconds = 0;\r
- return 0;\r
-}\r
-\r
-static int dapls_config_comp_channel(struct ibv_comp_channel *channel)\r
-{\r
- channel->comp_channel.Milliseconds = 0;\r
- return 0;\r
-}\r
-\r
-static int dapls_thread_signal(void)\r
-{\r
- CompSetCancel(&ufds);\r
- return 0;\r
-}\r
-#else // _WIN64 || WIN32\r
-int g_ib_pipe[2];\r
-\r
-static int dapls_os_init(void)\r
-{\r
- /* create pipe for waking up work thread */\r
- return pipe(g_ib_pipe);\r
-}\r
-\r
-static void dapls_os_release(void)\r
-{\r
- /* close pipe? */\r
-}\r
-\r
-/* Get IP address using network device name */\r
-static int getipaddr_netdev(char *name, char *addr, int addr_len)\r
-{\r
- struct ifreq ifr;\r
- int skfd, ret, len;\r
-\r
- /* Fill in the structure */\r
- snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name);\r
- ifr.ifr_hwaddr.sa_family = ARPHRD_INFINIBAND;\r
-\r
- /* Create a socket fd */\r
- skfd = socket(PF_INET, SOCK_STREAM, 0);\r
- ret = ioctl(skfd, SIOCGIFADDR, &ifr);\r
- if (ret)\r
- goto bail;\r
-\r
- switch (ifr.ifr_addr.sa_family) {\r
-#ifdef AF_INET6\r
- case AF_INET6:\r
- len = sizeof(struct sockaddr_in6);\r
- break;\r
-#endif\r
- case AF_INET:\r
- default:\r
- len = sizeof(struct sockaddr);\r
- break;\r
- }\r
-\r
- if (len <= addr_len)\r
- memcpy(addr, &ifr.ifr_addr, len);\r
- else\r
- ret = EINVAL;\r
-\r
- bail:\r
- close(skfd);\r
- return ret;\r
-}\r
-\r
-static int dapls_config_fd(int fd)\r
-{\r
- int opts;\r
-\r
- opts = fcntl(fd, F_GETFL);\r
- if (opts < 0 || fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " dapls_config_fd: fcntl on fd %d ERR %d %s\n",\r
- fd, opts, strerror(errno));\r
- return errno;\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static int dapls_config_cm_channel(struct rdma_event_channel *channel)\r
-{\r
- return dapls_config_fd(channel->fd);\r
-}\r
-\r
-static int dapls_config_verbs(struct ibv_context *verbs)\r
-{\r
- return dapls_config_fd(verbs->async_fd);\r
-}\r
-\r
-static int dapls_config_comp_channel(struct ibv_comp_channel *channel)\r
-{\r
- return dapls_config_fd(channel->fd);\r
-}\r
-\r
-static int dapls_thread_signal(void)\r
-{\r
- return write(g_ib_pipe[1], "w", sizeof "w");\r
-}\r
-#endif\r
-\r
-/* Get IP address using network name, address, or device name */\r
-static int getipaddr(char *name, char *addr, int len)\r
-{\r
- struct addrinfo *res;\r
-\r
- /* assume netdev for first attempt, then network and address type */\r
- if (getipaddr_netdev(name, addr, len)) {\r
- if (getaddrinfo(name, NULL, NULL, &res)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: getaddr_netdev ERROR:"\r
- " %s. Is %s configured?\n",\r
- strerror(errno), name);\r
- return 1;\r
- } else {\r
- if (len >= res->ai_addrlen)\r
- memcpy(addr, res->ai_addr, res->ai_addrlen);\r
- else {\r
- freeaddrinfo(res);\r
- return 1;\r
- }\r
- freeaddrinfo(res);\r
- }\r
- }\r
-\r
- dapl_dbg_log(\r
- DAPL_DBG_TYPE_UTIL,\r
- " getipaddr: family %d port %d addr %d.%d.%d.%d\n",\r
- ((struct sockaddr_in *)addr)->sin_family,\r
- ((struct sockaddr_in *)addr)->sin_port,\r
- ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 0 & 0xff,\r
- ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 8 & 0xff,\r
- ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 16 & 0xff,\r
- ((struct sockaddr_in *)addr)->sin_addr.\r
- s_addr >> 24 & 0xff);\r
-\r
- return 0;\r
-}\r
-\r
-/*\r
- * dapls_ib_init, dapls_ib_release\r
- *\r
- * Initialize Verb related items for device open\r
- *\r
- * Input:\r
- * none\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Returns:\r
- * 0 success, -1 error\r
- *\r
- */\r
-int32_t dapls_ib_init(void)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " dapl_ib_init: \n");\r
-\r
- /* initialize hca_list lock */\r
- dapl_os_lock_init(&g_hca_lock);\r
-\r
- /* initialize hca list for CQ events */\r
- dapl_llist_init_head(&g_hca_list);\r
-\r
- if (dapls_os_init())\r
- return 1;\r
-\r
- return 0;\r
-}\r
-\r
-int32_t dapls_ib_release(void)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " dapl_ib_release: \n");\r
- dapli_ib_thread_destroy();\r
- if (g_cm_events != NULL)\r
- rdma_destroy_event_channel(g_cm_events);\r
- dapls_os_release();\r
- return 0;\r
-}\r
-\r
-/*\r
- * dapls_ib_open_hca\r
- *\r
- * Open HCA\r
- *\r
- * Input:\r
- * *hca_name pointer to provider device name\r
- * *ib_hca_handle_p pointer to provide HCA handle\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Return:\r
- * DAT_SUCCESS\r
- * dapl_convert_errno\r
- *\r
- */\r
-DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr)\r
-{\r
- struct rdma_cm_id *cm_id = NULL;\r
- union ibv_gid *gid;\r
- int ret;\r
- DAT_RETURN dat_status;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " open_hca: %s - %p\n", hca_name, hca_ptr);\r
-\r
- /* Setup the global cm event channel */\r
- dapl_os_lock(&g_hca_lock);\r
- if (g_cm_events == NULL) {\r
- g_cm_events = rdma_create_event_channel();\r
- if (g_cm_events == NULL) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: ERR - RDMA channel %s\n",\r
- strerror(errno));\r
- dapl_os_unlock(&g_hca_lock);\r
- return DAT_INTERNAL_ERROR;\r
- }\r
- }\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " open_hca: RDMA channel created (%p)\n", g_cm_events);\r
-\r
- /* HCA name will be hostname or IP address */\r
- if (getipaddr((char *)hca_name,\r
- (char *)&hca_ptr->hca_address, \r
- sizeof(DAT_SOCK_ADDR6)))\r
- return DAT_INVALID_ADDRESS;\r
-\r
- /* cm_id will bind local device/GID based on IP address */\r
- if (rdma_create_id(g_cm_events, &cm_id, \r
- (void *)hca_ptr, RDMA_PS_TCP)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: rdma_create ERR %s\n", strerror(errno));\r
- return DAT_INTERNAL_ERROR;\r
- }\r
- ret = rdma_bind_addr(cm_id, (struct sockaddr *)&hca_ptr->hca_address);\r
- if ((ret) || (cm_id->verbs == NULL)) {\r
- rdma_destroy_id(cm_id);\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: rdma_bind ERR %s."\r
- " Is %s configured?\n", strerror(errno), hca_name);\r
- rdma_destroy_id(cm_id);\r
- return DAT_INVALID_ADDRESS;\r
- }\r
-\r
- /* keep reference to IB device and cm_id */\r
- hca_ptr->ib_trans.cm_id = cm_id;\r
- hca_ptr->ib_hca_handle = cm_id->verbs;\r
- dapls_config_verbs(cm_id->verbs);\r
- hca_ptr->port_num = cm_id->port_num;\r
- hca_ptr->ib_trans.ib_dev = cm_id->verbs->device;\r
- hca_ptr->ib_trans.ib_ctx = cm_id->verbs;\r
- gid = &cm_id->route.addr.addr.ibaddr.sgid;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " open_hca: ctx=%p port=%d GID subnet %016llx"\r
- " id %016llx\n", cm_id->verbs, cm_id->port_num,\r
- (unsigned long long)ntohll(gid->global.subnet_prefix),\r
- (unsigned long long)ntohll(gid->global.interface_id));\r
-\r
- /* support for EVD's with CNO's: one channel via thread */\r
- hca_ptr->ib_trans.ib_cq =\r
- ibv_create_comp_channel(hca_ptr->ib_hca_handle);\r
- if (hca_ptr->ib_trans.ib_cq == NULL) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: ibv_create_comp_channel ERR %s\n",\r
- strerror(errno));\r
- rdma_destroy_id(cm_id);\r
- return DAT_INTERNAL_ERROR;\r
- }\r
- if (dapls_config_comp_channel(hca_ptr->ib_trans.ib_cq)) {\r
- rdma_destroy_id(cm_id);\r
- return DAT_INTERNAL_ERROR;\r
- }\r
-\r
- /* set inline max with env or default, get local lid and gid 0 */\r
- if (hca_ptr->ib_hca_handle->device->transport_type\r
- == IBV_TRANSPORT_IWARP)\r
- hca_ptr->ib_trans.max_inline_send =\r
- dapl_os_get_env_val("DAPL_MAX_INLINE",\r
- INLINE_SEND_IWARP_DEFAULT);\r
- else\r
- hca_ptr->ib_trans.max_inline_send =\r
- dapl_os_get_env_val("DAPL_MAX_INLINE",\r
- INLINE_SEND_IB_DEFAULT);\r
-\r
- /* set CM timer defaults */\r
- hca_ptr->ib_trans.max_cm_timeout =\r
- dapl_os_get_env_val("DAPL_MAX_CM_RESPONSE_TIME",\r
- IB_CM_RESPONSE_TIMEOUT);\r
- hca_ptr->ib_trans.max_cm_retries =\r
- dapl_os_get_env_val("DAPL_MAX_CM_RETRIES", IB_CM_RETRIES);\r
- \r
- /* set default IB MTU */\r
- hca_ptr->ib_trans.mtu = dapl_ib_mtu(2048);\r
-\r
- dat_status = dapli_ib_thread_init();\r
- if (dat_status != DAT_SUCCESS)\r
- return dat_status;\r
- /* \r
- * Put new hca_transport on list for async and CQ event processing \r
- * Wakeup work thread to add to polling list\r
- */\r
- dapl_llist_init_entry((DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry);\r
- dapl_os_lock(&g_hca_lock);\r
- dapl_llist_add_tail(&g_hca_list,\r
- (DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry,\r
- &hca_ptr->ib_trans.entry);\r
- if (dapls_thread_signal() == -1)\r
- dapl_log(DAPL_DBG_TYPE_UTIL,\r
- " open_hca: thread wakeup error = %s\n",\r
- strerror(errno));\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " open_hca: %s, %s %d.%d.%d.%d INLINE_MAX=%d\n", hca_name,\r
- ((struct sockaddr_in *)\r
- &hca_ptr->hca_address)->sin_family == AF_INET ?\r
- "AF_INET" : "AF_INET6", \r
- ((struct sockaddr_in *)\r
- &hca_ptr->hca_address)->sin_addr.s_addr >> 0 & 0xff, \r
- ((struct sockaddr_in *)\r
- &hca_ptr->hca_address)->sin_addr.s_addr >> 8 & 0xff, \r
- ((struct sockaddr_in *)\r
- &hca_ptr->hca_address)->sin_addr.s_addr >> 16 & 0xff, \r
- ((struct sockaddr_in *)\r
- &hca_ptr->hca_address)->sin_addr.s_addr >> 24 & 0xff, \r
- hca_ptr->ib_trans.max_inline_send);\r
-\r
- return DAT_SUCCESS;\r
-}\r
-\r
-/*\r
- * dapls_ib_close_hca\r
- *\r
- * Open HCA\r
- *\r
- * Input:\r
- * DAPL_HCA provide CA handle\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Return:\r
- * DAT_SUCCESS\r
- * dapl_convert_errno \r
- *\r
- */\r
-DAT_RETURN dapls_ib_close_hca(IN DAPL_HCA * hca_ptr)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " close_hca: %p->%p\n",\r
- hca_ptr, hca_ptr->ib_hca_handle);\r
-\r
- dapl_os_lock(&g_hca_lock);\r
- if (g_ib_thread_state != IB_THREAD_RUN) {\r
- dapl_os_unlock(&g_hca_lock);\r
- goto bail;\r
- }\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- /* \r
- * Remove hca from async event processing list\r
- * Wakeup work thread to remove from polling list\r
- */\r
- hca_ptr->ib_trans.destroy = 1;\r
- if (dapls_thread_signal() == -1)\r
- dapl_log(DAPL_DBG_TYPE_UTIL,\r
- " destroy: thread wakeup error = %s\n",\r
- strerror(errno));\r
-\r
- /* wait for thread to remove HCA references */\r
- while (hca_ptr->ib_trans.destroy != 2) {\r
- if (dapls_thread_signal() == -1)\r
- dapl_log(DAPL_DBG_TYPE_UTIL,\r
- " destroy: thread wakeup error = %s\n",\r
- strerror(errno));\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_destroy: wait on hca %p destroy\n");\r
- dapl_os_sleep_usec(1000);\r
- }\r
-bail:\r
- if (hca_ptr->ib_trans.ib_cq)\r
- ibv_destroy_comp_channel(hca_ptr->ib_trans.ib_cq);\r
-\r
- if (hca_ptr->ib_trans.ib_cq_empty) {\r
- struct ibv_comp_channel *channel;\r
- channel = hca_ptr->ib_trans.ib_cq_empty->channel;\r
- ibv_destroy_cq(hca_ptr->ib_trans.ib_cq_empty);\r
- ibv_destroy_comp_channel(channel);\r
- }\r
-\r
- if (hca_ptr->ib_hca_handle != IB_INVALID_HANDLE) {\r
- if (rdma_destroy_id(hca_ptr->ib_trans.cm_id))\r
- return (dapl_convert_errno(errno, "ib_close_device"));\r
- hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;\r
- }\r
-\r
- return (DAT_SUCCESS);\r
-}\r
-\r
-\r
-DAT_RETURN dapli_ib_thread_init(void)\r
-{\r
- DAT_RETURN dat_status;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_init(%d)\n", dapl_os_getpid());\r
-\r
- dapl_os_lock(&g_hca_lock);\r
- if (g_ib_thread_state != IB_THREAD_INIT) {\r
- dapl_os_unlock(&g_hca_lock);\r
- return DAT_SUCCESS;\r
- }\r
-\r
- /* uCMA events non-blocking */\r
- if (dapls_config_cm_channel(g_cm_events)) {\r
- dapl_os_unlock(&g_hca_lock);\r
- return (dapl_convert_errno(errno, "create_thread ERR: cm_fd"));\r
- }\r
-\r
- g_ib_thread_state = IB_THREAD_CREATE;\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- /* create thread to process inbound connect request */\r
- dat_status = dapl_os_thread_create(dapli_thread, NULL, &g_ib_thread);\r
- if (dat_status != DAT_SUCCESS)\r
- return (dapl_convert_errno(errno,\r
- "create_thread ERR:"\r
- " check resource limits"));\r
-\r
- /* wait for thread to start */\r
- dapl_os_lock(&g_hca_lock);\r
- while (g_ib_thread_state != IB_THREAD_RUN) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_init: waiting for ib_thread\n");\r
- dapl_os_unlock(&g_hca_lock);\r
- dapl_os_sleep_usec(1000);\r
- dapl_os_lock(&g_hca_lock);\r
- }\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_init(%d) exit\n", dapl_os_getpid());\r
-\r
- return DAT_SUCCESS;\r
-}\r
-\r
-void dapli_ib_thread_destroy(void)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_destroy(%d)\n", dapl_os_getpid());\r
- /* \r
- * wait for async thread to terminate. \r
- * pthread_join would be the correct method\r
- * but some applications have some issues\r
- */\r
-\r
- /* destroy ib_thread, wait for termination, if not already */\r
- dapl_os_lock(&g_hca_lock);\r
- if (g_ib_thread_state != IB_THREAD_RUN)\r
- goto bail;\r
-\r
- g_ib_thread_state = IB_THREAD_CANCEL;\r
- while ((g_ib_thread_state != IB_THREAD_EXIT)) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_destroy: waiting for ib_thread\n");\r
- if (dapls_thread_signal() == -1)\r
- dapl_log(DAPL_DBG_TYPE_UTIL,\r
- " destroy: thread wakeup error = %s\n",\r
- strerror(errno));\r
- dapl_os_unlock(&g_hca_lock);\r
- dapl_os_sleep_usec(2000);\r
- dapl_os_lock(&g_hca_lock);\r
- }\r
-bail:\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_destroy(%d) exit\n", dapl_os_getpid());\r
-}\r
-\r
-#if defined(_WIN64) || defined(_WIN32)\r
-/* work thread for uAT, uCM, CQ, and async events */\r
-void dapli_thread(void *arg)\r
-{\r
- struct _ib_hca_transport *hca;\r
- struct _ib_hca_transport *uhca[8];\r
- COMP_CHANNEL *channel;\r
- int ret, idx, cnt;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d,0x%x): ENTER: \n",\r
- dapl_os_getpid(), g_ib_thread);\r
-\r
- dapl_os_lock(&g_hca_lock);\r
- for (g_ib_thread_state = IB_THREAD_RUN;\r
- g_ib_thread_state == IB_THREAD_RUN; \r
- dapl_os_lock(&g_hca_lock)) {\r
-\r
- CompSetZero(&ufds);\r
- CompSetAdd(&g_cm_events->channel, &ufds);\r
-\r
- idx = 0;\r
- hca = dapl_llist_is_empty(&g_hca_list) ? NULL :\r
- dapl_llist_peek_head(&g_hca_list);\r
-\r
- while (hca) {\r
- CompSetAdd(&hca->ib_ctx->channel, &ufds);\r
- CompSetAdd(&hca->ib_cq->comp_channel, &ufds);\r
- uhca[idx++] = hca;\r
- hca = dapl_llist_next_entry(&g_hca_list,\r
- (DAPL_LLIST_ENTRY *)\r
- &hca->entry);\r
- }\r
- cnt = idx;\r
-\r
- dapl_os_unlock(&g_hca_lock);\r
- ret = CompSetPoll(&ufds, INFINITE);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread(%d) poll_event 0x%x\n",\r
- dapl_os_getpid(), ret);\r
-\r
- dapli_cma_event_cb();\r
-\r
- /* check and process ASYNC events, per device */\r
- for (idx = 0; idx < cnt; idx++) {\r
- if (uhca[idx]->destroy == 1) {\r
- dapl_os_lock(&g_hca_lock);\r
- dapl_llist_remove_entry(&g_hca_list,\r
- (DAPL_LLIST_ENTRY *)\r
- &uhca[idx]->entry);\r
- dapl_os_unlock(&g_hca_lock);\r
- uhca[idx]->destroy = 2;\r
- } else {\r
- dapli_cq_event_cb(uhca[idx]);\r
- dapli_async_event_cb(uhca[idx]);\r
- }\r
- }\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d) EXIT\n",\r
- dapl_os_getpid());\r
- g_ib_thread_state = IB_THREAD_EXIT;\r
- dapl_os_unlock(&g_hca_lock);\r
-}\r
-#else // _WIN64 || WIN32\r
-\r
-/* work thread for uAT, uCM, CQ, and async events */\r
-void dapli_thread(void *arg)\r
-{\r
- struct pollfd ufds[__FD_SETSIZE];\r
- struct _ib_hca_transport *uhca[__FD_SETSIZE] = { NULL };\r
- struct _ib_hca_transport *hca;\r
- int ret, idx, fds;\r
- char rbuf[2];\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
- " ib_thread(%d,0x%x): ENTER: pipe %d ucma %d\n",\r
- dapl_os_getpid(), g_ib_thread, g_ib_pipe[0],\r
- g_cm_events->fd);\r
-\r
- /* Poll across pipe, CM, AT never changes */\r
- dapl_os_lock(&g_hca_lock);\r
- g_ib_thread_state = IB_THREAD_RUN;\r
-\r
- ufds[0].fd = g_ib_pipe[0]; /* pipe */\r
- ufds[0].events = POLLIN;\r
- ufds[1].fd = g_cm_events->fd; /* uCMA */\r
- ufds[1].events = POLLIN;\r
-\r
- while (g_ib_thread_state == IB_THREAD_RUN) {\r
-\r
- /* build ufds after pipe and uCMA events */\r
- ufds[0].revents = 0;\r
- ufds[1].revents = 0;\r
- idx = 1;\r
-\r
- /* Walk HCA list and setup async and CQ events */\r
- if (!dapl_llist_is_empty(&g_hca_list))\r
- hca = dapl_llist_peek_head(&g_hca_list);\r
- else\r
- hca = NULL;\r
-\r
- while (hca) {\r
-\r
- /* uASYNC events */\r
- ufds[++idx].fd = hca->ib_ctx->async_fd;\r
- ufds[idx].events = POLLIN;\r
- ufds[idx].revents = 0;\r
- uhca[idx] = hca;\r
-\r
- /* CQ events are non-direct with CNO's */\r
- ufds[++idx].fd = hca->ib_cq->fd;\r
- ufds[idx].events = POLLIN;\r
- ufds[idx].revents = 0;\r
- uhca[idx] = hca;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
- " ib_thread(%d) poll_fd: hca[%d]=%p,"\r
- " async=%d pipe=%d cm=%d \n",\r
- dapl_os_getpid(), hca, ufds[idx - 1].fd,\r
- ufds[0].fd, ufds[1].fd);\r
-\r
- hca = dapl_llist_next_entry(&g_hca_list,\r
- (DAPL_LLIST_ENTRY *)\r
- &hca->entry);\r
- }\r
-\r
- /* unlock, and setup poll */\r
- fds = idx + 1;\r
- dapl_os_unlock(&g_hca_lock);\r
- ret = poll(ufds, fds, -1);\r
- if (ret <= 0) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
- " ib_thread(%d): ERR %s poll\n",\r
- dapl_os_getpid(), strerror(errno));\r
- dapl_os_lock(&g_hca_lock);\r
- continue;\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
- " ib_thread(%d) poll_event: "\r
- " async=0x%x pipe=0x%x cm=0x%x \n",\r
- dapl_os_getpid(), ufds[idx].revents,\r
- ufds[0].revents, ufds[1].revents);\r
-\r
- /* uCMA events */\r
- if (ufds[1].revents == POLLIN)\r
- dapli_cma_event_cb();\r
-\r
- /* check and process CQ and ASYNC events, per device */\r
- for (idx = 2; idx < fds; idx++) {\r
- if (ufds[idx].revents == POLLIN) {\r
- dapli_cq_event_cb(uhca[idx]);\r
- dapli_async_event_cb(uhca[idx]);\r
- }\r
- }\r
-\r
- /* check and process user events, PIPE */\r
- if (ufds[0].revents == POLLIN) {\r
- if (read(g_ib_pipe[0], rbuf, 2) == -1)\r
- dapl_log(DAPL_DBG_TYPE_THREAD,\r
- " cr_thread: pipe rd err= %s\n",\r
- strerror(errno));\r
-\r
- /* cleanup any device on list marked for destroy */\r
- for (idx = 3; idx < fds; idx++) {\r
- if (uhca[idx] && uhca[idx]->destroy == 1) {\r
- dapl_os_lock(&g_hca_lock);\r
- dapl_llist_remove_entry(\r
- &g_hca_list,\r
- (DAPL_LLIST_ENTRY*)\r
- &uhca[idx]->entry);\r
- dapl_os_unlock(&g_hca_lock);\r
- uhca[idx]->destroy = 2;\r
- }\r
- }\r
- }\r
- dapl_os_lock(&g_hca_lock);\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " ib_thread(%d) EXIT\n",\r
- dapl_os_getpid());\r
- g_ib_thread_state = IB_THREAD_EXIT;\r
- dapl_os_unlock(&g_hca_lock);\r
-}\r
-#endif\r
+/*
+ * Copyright (c) 2005-2008 Intel Corporation. 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_util.c
+ *
+ * PURPOSE: OFED provider - init, open, close, utilities, work thread
+ *
+ * $Id:$
+ *
+ **********************************************************************/
+
+#ifdef RCSID
+static const char rcsid[] = "$Id: $";
+#endif
+
+#include "openib_osd.h"
+#include "dapl.h"
+#include "dapl_adapter_util.h"
+#include "dapl_ib_util.h"
+#include "dapl_osd.h"
+
+#include <stdlib.h>
+
+struct rdma_event_channel *g_cm_events = NULL;
+ib_thread_state_t g_ib_thread_state = 0;
+DAPL_OS_THREAD g_ib_thread;
+DAPL_OS_LOCK g_hca_lock;
+struct dapl_llist_entry *g_hca_list;
+
+#if defined(_WIN64) || defined(_WIN32)
+#include "..\..\..\..\..\etc\user\comp_channel.cpp"
+#include <rdma\winverbs.h>
+
+static COMP_SET ufds;
+
+static int getipaddr_netdev(char *name, char *addr, int addr_len)
+{
+ IWVProvider *prov;
+ WV_DEVICE_ADDRESS devaddr;
+ struct addrinfo *res, *ai;
+ HRESULT hr;
+ int index;
+
+ if (strncmp(name, "rdma_dev", 8)) {
+ return EINVAL;
+ }
+
+ index = atoi(name + 8);
+
+ hr = WvGetObject(&IID_IWVProvider, (LPVOID *) &prov);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ hr = getaddrinfo("..localmachine", NULL, NULL, &res);
+ if (hr) {
+ goto release;
+ }
+
+ for (ai = res; ai; ai = ai->ai_next) {
+ hr = prov->lpVtbl->TranslateAddress(prov, ai->ai_addr, &devaddr);
+ if (SUCCEEDED(hr) && (ai->ai_addrlen <= addr_len) && (index-- == 0)) {
+ memcpy(addr, ai->ai_addr, ai->ai_addrlen);
+ goto free;
+ }
+ }
+ hr = ENODEV;
+
+free:
+ freeaddrinfo(res);
+release:
+ prov->lpVtbl->Release(prov);
+ return hr;
+}
+
+static int dapls_os_init(void)
+{
+ return CompSetInit(&ufds);
+}
+
+static void dapls_os_release(void)
+{
+ CompSetCleanup(&ufds);
+}
+
+static int dapls_config_cm_channel(struct rdma_event_channel *channel)
+{
+ channel->channel.Milliseconds = 0;
+ return 0;
+}
+
+static int dapls_config_verbs(struct ibv_context *verbs)
+{
+ verbs->channel.Milliseconds = 0;
+ return 0;
+}
+
+static int dapls_config_comp_channel(struct ibv_comp_channel *channel)
+{
+ channel->comp_channel.Milliseconds = 0;
+ return 0;
+}
+
+static int dapls_thread_signal(void)
+{
+ CompSetCancel(&ufds);
+ return 0;
+}
+#else // _WIN64 || WIN32
+int g_ib_pipe[2];
+
+static int dapls_os_init(void)
+{
+ /* create pipe for waking up work thread */
+ return pipe(g_ib_pipe);
+}
+
+static void dapls_os_release(void)
+{
+ /* close pipe? */
+}
+
+/* Get IP address using network device name */
+static int getipaddr_netdev(char *name, char *addr, int addr_len)
+{
+ struct ifreq ifr;
+ int skfd, ret, len;
+
+ /* Fill in the structure */
+ snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name);
+ ifr.ifr_hwaddr.sa_family = ARPHRD_INFINIBAND;
+
+ /* Create a socket fd */
+ skfd = socket(PF_INET, SOCK_STREAM, 0);
+ ret = ioctl(skfd, SIOCGIFADDR, &ifr);
+ if (ret)
+ goto bail;
+
+ switch (ifr.ifr_addr.sa_family) {
+#ifdef AF_INET6
+ case AF_INET6:
+ len = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ case AF_INET:
+ default:
+ len = sizeof(struct sockaddr);
+ break;
+ }
+
+ if (len <= addr_len)
+ memcpy(addr, &ifr.ifr_addr, len);
+ else
+ ret = EINVAL;
+
+ bail:
+ close(skfd);
+ return ret;
+}
+
+static int dapls_config_fd(int fd)
+{
+ int opts;
+
+ opts = fcntl(fd, F_GETFL);
+ if (opts < 0 || fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " dapls_config_fd: fcntl on fd %d ERR %d %s\n",
+ fd, opts, strerror(errno));
+ return errno;
+ }
+
+ return 0;
+}
+
+static int dapls_config_cm_channel(struct rdma_event_channel *channel)
+{
+ return dapls_config_fd(channel->fd);
+}
+
+static int dapls_config_verbs(struct ibv_context *verbs)
+{
+ return dapls_config_fd(verbs->async_fd);
+}
+
+static int dapls_config_comp_channel(struct ibv_comp_channel *channel)
+{
+ return dapls_config_fd(channel->fd);
+}
+
+static int dapls_thread_signal(void)
+{
+ return write(g_ib_pipe[1], "w", sizeof "w");
+}
+#endif
+
+/* Get IP address using network name, address, or device name */
+static int getipaddr(char *name, char *addr, int len)
+{
+ struct addrinfo *res;
+
+ /* assume netdev for first attempt, then network and address type */
+ if (getipaddr_netdev(name, addr, len)) {
+ if (getaddrinfo(name, NULL, NULL, &res)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: getaddr_netdev ERROR:"
+ " %s. Is %s configured?\n",
+ strerror(errno), name);
+ return 1;
+ } else {
+ if (len >= res->ai_addrlen)
+ memcpy(addr, res->ai_addr, res->ai_addrlen);
+ else {
+ freeaddrinfo(res);
+ return 1;
+ }
+ freeaddrinfo(res);
+ }
+ }
+
+ dapl_dbg_log(
+ DAPL_DBG_TYPE_UTIL,
+ " getipaddr: family %d port %d addr %d.%d.%d.%d\n",
+ ((struct sockaddr_in *)addr)->sin_family,
+ ((struct sockaddr_in *)addr)->sin_port,
+ ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 0 & 0xff,
+ ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 8 & 0xff,
+ ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 16 & 0xff,
+ ((struct sockaddr_in *)addr)->sin_addr.
+ s_addr >> 24 & 0xff);
+
+ return 0;
+}
+
+/*
+ * dapls_ib_init, dapls_ib_release
+ *
+ * Initialize Verb related items for device open
+ *
+ * Input:
+ * none
+ *
+ * Output:
+ * none
+ *
+ * Returns:
+ * 0 success, -1 error
+ *
+ */
+int32_t dapls_ib_init(void)
+{
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " dapl_ib_init: \n");
+
+ /* initialize hca_list lock */
+ dapl_os_lock_init(&g_hca_lock);
+
+ /* initialize hca list for CQ events */
+ dapl_llist_init_head(&g_hca_list);
+
+ if (dapls_os_init())
+ return 1;
+
+ return 0;
+}
+
+int32_t dapls_ib_release(void)
+{
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " dapl_ib_release: \n");
+ dapli_ib_thread_destroy();
+ if (g_cm_events != NULL)
+ rdma_destroy_event_channel(g_cm_events);
+ dapls_os_release();
+ return 0;
+}
+
+/*
+ * dapls_ib_open_hca
+ *
+ * Open HCA
+ *
+ * Input:
+ * *hca_name pointer to provider device name
+ * *ib_hca_handle_p pointer to provide HCA handle
+ *
+ * Output:
+ * none
+ *
+ * Return:
+ * DAT_SUCCESS
+ * dapl_convert_errno
+ *
+ */
+DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr)
+{
+ struct rdma_cm_id *cm_id = NULL;
+ union ibv_gid *gid;
+ int ret;
+ DAT_RETURN dat_status;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " open_hca: %s - %p\n", hca_name, hca_ptr);
+
+ /* Setup the global cm event channel */
+ dapl_os_lock(&g_hca_lock);
+ if (g_cm_events == NULL) {
+ g_cm_events = rdma_create_event_channel();
+ if (g_cm_events == NULL) {
+ dapl_dbg_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: ERR - RDMA channel %s\n",
+ strerror(errno));
+ dapl_os_unlock(&g_hca_lock);
+ return DAT_INTERNAL_ERROR;
+ }
+ }
+ dapl_os_unlock(&g_hca_lock);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " open_hca: RDMA channel created (%p)\n", g_cm_events);
+
+ /* HCA name will be hostname or IP address */
+ if (getipaddr((char *)hca_name,
+ (char *)&hca_ptr->hca_address,
+ sizeof(DAT_SOCK_ADDR6)))
+ return DAT_INVALID_ADDRESS;
+
+ /* cm_id will bind local device/GID based on IP address */
+ if (rdma_create_id(g_cm_events, &cm_id,
+ (void *)hca_ptr, RDMA_PS_TCP)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: rdma_create ERR %s\n", strerror(errno));
+ return DAT_INTERNAL_ERROR;
+ }
+ ret = rdma_bind_addr(cm_id, (struct sockaddr *)&hca_ptr->hca_address);
+ if ((ret) || (cm_id->verbs == NULL)) {
+ rdma_destroy_id(cm_id);
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: rdma_bind ERR %s."
+ " Is %s configured?\n", strerror(errno), hca_name);
+ rdma_destroy_id(cm_id);
+ return DAT_INVALID_ADDRESS;
+ }
+
+ /* keep reference to IB device and cm_id */
+ hca_ptr->ib_trans.cm_id = cm_id;
+ hca_ptr->ib_hca_handle = cm_id->verbs;
+ dapls_config_verbs(cm_id->verbs);
+ hca_ptr->port_num = cm_id->port_num;
+ hca_ptr->ib_trans.ib_dev = cm_id->verbs->device;
+ hca_ptr->ib_trans.ib_ctx = cm_id->verbs;
+ gid = &cm_id->route.addr.addr.ibaddr.sgid;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " open_hca: ctx=%p port=%d GID subnet %016llx"
+ " id %016llx\n", cm_id->verbs, cm_id->port_num,
+ (unsigned long long)ntohll(gid->global.subnet_prefix),
+ (unsigned long long)ntohll(gid->global.interface_id));
+
+ /* support for EVD's with CNO's: one channel via thread */
+ hca_ptr->ib_trans.ib_cq =
+ ibv_create_comp_channel(hca_ptr->ib_hca_handle);
+ if (hca_ptr->ib_trans.ib_cq == NULL) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: ibv_create_comp_channel ERR %s\n",
+ strerror(errno));
+ rdma_destroy_id(cm_id);
+ return DAT_INTERNAL_ERROR;
+ }
+ if (dapls_config_comp_channel(hca_ptr->ib_trans.ib_cq)) {
+ rdma_destroy_id(cm_id);
+ return DAT_INTERNAL_ERROR;
+ }
+
+ /* set inline max with env or default, get local lid and gid 0 */
+ if (hca_ptr->ib_hca_handle->device->transport_type
+ == IBV_TRANSPORT_IWARP)
+ hca_ptr->ib_trans.max_inline_send =
+ dapl_os_get_env_val("DAPL_MAX_INLINE",
+ INLINE_SEND_IWARP_DEFAULT);
+ else
+ hca_ptr->ib_trans.max_inline_send =
+ dapl_os_get_env_val("DAPL_MAX_INLINE",
+ INLINE_SEND_IB_DEFAULT);
+
+ /* set CM timer defaults */
+ hca_ptr->ib_trans.max_cm_timeout =
+ dapl_os_get_env_val("DAPL_MAX_CM_RESPONSE_TIME",
+ IB_CM_RESPONSE_TIMEOUT);
+ hca_ptr->ib_trans.max_cm_retries =
+ dapl_os_get_env_val("DAPL_MAX_CM_RETRIES", IB_CM_RETRIES);
+
+ /* set default IB MTU */
+ hca_ptr->ib_trans.mtu = dapl_ib_mtu(2048);
+
+ dat_status = dapli_ib_thread_init();
+ if (dat_status != DAT_SUCCESS)
+ return dat_status;
+ /*
+ * Put new hca_transport on list for async and CQ event processing
+ * Wakeup work thread to add to polling list
+ */
+ dapl_llist_init_entry((DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry);
+ dapl_os_lock(&g_hca_lock);
+ dapl_llist_add_tail(&g_hca_list,
+ (DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry,
+ &hca_ptr->ib_trans.entry);
+ if (dapls_thread_signal() == -1)
+ dapl_log(DAPL_DBG_TYPE_UTIL,
+ " open_hca: thread wakeup error = %s\n",
+ strerror(errno));
+ dapl_os_unlock(&g_hca_lock);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " open_hca: %s, %s %d.%d.%d.%d INLINE_MAX=%d\n", hca_name,
+ ((struct sockaddr_in *)
+ &hca_ptr->hca_address)->sin_family == AF_INET ?
+ "AF_INET" : "AF_INET6",
+ ((struct sockaddr_in *)
+ &hca_ptr->hca_address)->sin_addr.s_addr >> 0 & 0xff,
+ ((struct sockaddr_in *)
+ &hca_ptr->hca_address)->sin_addr.s_addr >> 8 & 0xff,
+ ((struct sockaddr_in *)
+ &hca_ptr->hca_address)->sin_addr.s_addr >> 16 & 0xff,
+ ((struct sockaddr_in *)
+ &hca_ptr->hca_address)->sin_addr.s_addr >> 24 & 0xff,
+ hca_ptr->ib_trans.max_inline_send);
+
+ return DAT_SUCCESS;
+}
+
+/*
+ * dapls_ib_close_hca
+ *
+ * Open HCA
+ *
+ * Input:
+ * DAPL_HCA provide CA handle
+ *
+ * Output:
+ * none
+ *
+ * Return:
+ * DAT_SUCCESS
+ * dapl_convert_errno
+ *
+ */
+DAT_RETURN dapls_ib_close_hca(IN DAPL_HCA * hca_ptr)
+{
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " close_hca: %p->%p\n",
+ hca_ptr, hca_ptr->ib_hca_handle);
+
+ dapl_os_lock(&g_hca_lock);
+ if (g_ib_thread_state != IB_THREAD_RUN) {
+ dapl_os_unlock(&g_hca_lock);
+ goto bail;
+ }
+ dapl_os_unlock(&g_hca_lock);
+
+ /*
+ * Remove hca from async event processing list
+ * Wakeup work thread to remove from polling list
+ */
+ hca_ptr->ib_trans.destroy = 1;
+ if (dapls_thread_signal() == -1)
+ dapl_log(DAPL_DBG_TYPE_UTIL,
+ " destroy: thread wakeup error = %s\n",
+ strerror(errno));
+
+ /* wait for thread to remove HCA references */
+ while (hca_ptr->ib_trans.destroy != 2) {
+ if (dapls_thread_signal() == -1)
+ dapl_log(DAPL_DBG_TYPE_UTIL,
+ " destroy: thread wakeup error = %s\n",
+ strerror(errno));
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_destroy: wait on hca %p destroy\n");
+ dapl_os_sleep_usec(1000);
+ }
+bail:
+
+ if (hca_ptr->ib_trans.ib_cq)
+ ibv_destroy_comp_channel(hca_ptr->ib_trans.ib_cq);
+
+ if (hca_ptr->ib_trans.ib_cq_empty) {
+ struct ibv_comp_channel *channel;
+ channel = hca_ptr->ib_trans.ib_cq_empty->channel;
+ ibv_destroy_cq(hca_ptr->ib_trans.ib_cq_empty);
+ ibv_destroy_comp_channel(channel);
+ }
+
+ if (hca_ptr->ib_hca_handle != IB_INVALID_HANDLE) {
+ if (rdma_destroy_id(hca_ptr->ib_trans.cm_id))
+ return (dapl_convert_errno(errno, "ib_close_device"));
+ hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;
+ }
+
+ return (DAT_SUCCESS);
+}
+
+
+DAT_RETURN dapli_ib_thread_init(void)
+{
+ DAT_RETURN dat_status;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_init(%d)\n", dapl_os_getpid());
+
+ dapl_os_lock(&g_hca_lock);
+ if (g_ib_thread_state != IB_THREAD_INIT) {
+ dapl_os_unlock(&g_hca_lock);
+ return DAT_SUCCESS;
+ }
+
+ /* uCMA events non-blocking */
+ if (dapls_config_cm_channel(g_cm_events)) {
+ dapl_os_unlock(&g_hca_lock);
+ return (dapl_convert_errno(errno, "create_thread ERR: cm_fd"));
+ }
+
+ g_ib_thread_state = IB_THREAD_CREATE;
+ dapl_os_unlock(&g_hca_lock);
+
+ /* create thread to process inbound connect request */
+ dat_status = dapl_os_thread_create(dapli_thread, NULL, &g_ib_thread);
+ if (dat_status != DAT_SUCCESS)
+ return (dapl_convert_errno(errno,
+ "create_thread ERR:"
+ " check resource limits"));
+
+ /* wait for thread to start */
+ dapl_os_lock(&g_hca_lock);
+ while (g_ib_thread_state != IB_THREAD_RUN) {
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_init: waiting for ib_thread\n");
+ dapl_os_unlock(&g_hca_lock);
+ dapl_os_sleep_usec(1000);
+ dapl_os_lock(&g_hca_lock);
+ }
+ dapl_os_unlock(&g_hca_lock);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_init(%d) exit\n", dapl_os_getpid());
+
+ return DAT_SUCCESS;
+}
+
+void dapli_ib_thread_destroy(void)
+{
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_destroy(%d)\n", dapl_os_getpid());
+ /*
+ * wait for async thread to terminate.
+ * pthread_join would be the correct method
+ * but some applications have some issues
+ */
+
+ /* destroy ib_thread, wait for termination, if not already */
+ dapl_os_lock(&g_hca_lock);
+ if (g_ib_thread_state != IB_THREAD_RUN)
+ goto bail;
+
+ g_ib_thread_state = IB_THREAD_CANCEL;
+ while ((g_ib_thread_state != IB_THREAD_EXIT)) {
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_destroy: waiting for ib_thread\n");
+ if (dapls_thread_signal() == -1)
+ dapl_log(DAPL_DBG_TYPE_UTIL,
+ " destroy: thread wakeup error = %s\n",
+ strerror(errno));
+ dapl_os_unlock(&g_hca_lock);
+ dapl_os_sleep_usec(2000);
+ dapl_os_lock(&g_hca_lock);
+ }
+bail:
+ dapl_os_unlock(&g_hca_lock);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_destroy(%d) exit\n", dapl_os_getpid());
+}
+
+#if defined(_WIN64) || defined(_WIN32)
+/* work thread for uAT, uCM, CQ, and async events */
+void dapli_thread(void *arg)
+{
+ struct _ib_hca_transport *hca;
+ struct _ib_hca_transport *uhca[8];
+ COMP_CHANNEL *channel;
+ int ret, idx, cnt;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d,0x%x): ENTER: \n",
+ dapl_os_getpid(), g_ib_thread);
+
+ dapl_os_lock(&g_hca_lock);
+ for (g_ib_thread_state = IB_THREAD_RUN;
+ g_ib_thread_state == IB_THREAD_RUN;
+ dapl_os_lock(&g_hca_lock)) {
+
+ CompSetZero(&ufds);
+ CompSetAdd(&g_cm_events->channel, &ufds);
+
+ idx = 0;
+ hca = dapl_llist_is_empty(&g_hca_list) ? NULL :
+ dapl_llist_peek_head(&g_hca_list);
+
+ while (hca) {
+ CompSetAdd(&hca->ib_ctx->channel, &ufds);
+ CompSetAdd(&hca->ib_cq->comp_channel, &ufds);
+ uhca[idx++] = hca;
+ hca = dapl_llist_next_entry(&g_hca_list,
+ (DAPL_LLIST_ENTRY *)
+ &hca->entry);
+ }
+ cnt = idx;
+
+ dapl_os_unlock(&g_hca_lock);
+ ret = CompSetPoll(&ufds, INFINITE);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread(%d) poll_event 0x%x\n",
+ dapl_os_getpid(), ret);
+
+ dapli_cma_event_cb();
+
+ /* check and process ASYNC events, per device */
+ for (idx = 0; idx < cnt; idx++) {
+ if (uhca[idx]->destroy == 1) {
+ dapl_os_lock(&g_hca_lock);
+ dapl_llist_remove_entry(&g_hca_list,
+ (DAPL_LLIST_ENTRY *)
+ &uhca[idx]->entry);
+ dapl_os_unlock(&g_hca_lock);
+ uhca[idx]->destroy = 2;
+ } else {
+ dapli_cq_event_cb(uhca[idx]);
+ dapli_async_event_cb(uhca[idx]);
+ }
+ }
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d) EXIT\n",
+ dapl_os_getpid());
+ g_ib_thread_state = IB_THREAD_EXIT;
+ dapl_os_unlock(&g_hca_lock);
+}
+#else // _WIN64 || WIN32
+
+/* work thread for uAT, uCM, CQ, and async events */
+void dapli_thread(void *arg)
+{
+ struct pollfd ufds[__FD_SETSIZE];
+ struct _ib_hca_transport *uhca[__FD_SETSIZE] = { NULL };
+ struct _ib_hca_transport *hca;
+ int ret, idx, fds;
+ char rbuf[2];
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " ib_thread(%d,0x%x): ENTER: pipe %d ucma %d\n",
+ dapl_os_getpid(), g_ib_thread, g_ib_pipe[0],
+ g_cm_events->fd);
+
+ /* Poll across pipe, CM, AT never changes */
+ dapl_os_lock(&g_hca_lock);
+ g_ib_thread_state = IB_THREAD_RUN;
+
+ ufds[0].fd = g_ib_pipe[0]; /* pipe */
+ ufds[0].events = POLLIN;
+ ufds[1].fd = g_cm_events->fd; /* uCMA */
+ ufds[1].events = POLLIN;
+
+ while (g_ib_thread_state == IB_THREAD_RUN) {
+
+ /* build ufds after pipe and uCMA events */
+ ufds[0].revents = 0;
+ ufds[1].revents = 0;
+ idx = 1;
+
+ /* Walk HCA list and setup async and CQ events */
+ if (!dapl_llist_is_empty(&g_hca_list))
+ hca = dapl_llist_peek_head(&g_hca_list);
+ else
+ hca = NULL;
+
+ while (hca) {
+
+ /* uASYNC events */
+ ufds[++idx].fd = hca->ib_ctx->async_fd;
+ ufds[idx].events = POLLIN;
+ ufds[idx].revents = 0;
+ uhca[idx] = hca;
+
+ /* CQ events are non-direct with CNO's */
+ ufds[++idx].fd = hca->ib_cq->fd;
+ ufds[idx].events = POLLIN;
+ ufds[idx].revents = 0;
+ uhca[idx] = hca;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " ib_thread(%d) poll_fd: hca[%d]=%p,"
+ " async=%d pipe=%d cm=%d \n",
+ dapl_os_getpid(), hca, ufds[idx - 1].fd,
+ ufds[0].fd, ufds[1].fd);
+
+ hca = dapl_llist_next_entry(&g_hca_list,
+ (DAPL_LLIST_ENTRY *)
+ &hca->entry);
+ }
+
+ /* unlock, and setup poll */
+ fds = idx + 1;
+ dapl_os_unlock(&g_hca_lock);
+ ret = poll(ufds, fds, -1);
+ if (ret <= 0) {
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " ib_thread(%d): ERR %s poll\n",
+ dapl_os_getpid(), strerror(errno));
+ dapl_os_lock(&g_hca_lock);
+ continue;
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " ib_thread(%d) poll_event: "
+ " async=0x%x pipe=0x%x cm=0x%x \n",
+ dapl_os_getpid(), ufds[idx].revents,
+ ufds[0].revents, ufds[1].revents);
+
+ /* uCMA events */
+ if (ufds[1].revents == POLLIN)
+ dapli_cma_event_cb();
+
+ /* check and process CQ and ASYNC events, per device */
+ for (idx = 2; idx < fds; idx++) {
+ if (ufds[idx].revents == POLLIN) {
+ dapli_cq_event_cb(uhca[idx]);
+ dapli_async_event_cb(uhca[idx]);
+ }
+ }
+
+ /* check and process user events, PIPE */
+ if (ufds[0].revents == POLLIN) {
+ if (read(g_ib_pipe[0], rbuf, 2) == -1)
+ dapl_log(DAPL_DBG_TYPE_THREAD,
+ " cr_thread: pipe rd err= %s\n",
+ strerror(errno));
+
+ /* cleanup any device on list marked for destroy */
+ for (idx = 3; idx < fds; idx++) {
+ if (uhca[idx] && uhca[idx]->destroy == 1) {
+ dapl_os_lock(&g_hca_lock);
+ dapl_llist_remove_entry(
+ &g_hca_list,
+ (DAPL_LLIST_ENTRY*)
+ &uhca[idx]->entry);
+ dapl_os_unlock(&g_hca_lock);
+ uhca[idx]->destroy = 2;
+ }
+ }
+ }
+ dapl_os_lock(&g_hca_lock);
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " ib_thread(%d) EXIT\n",
+ dapl_os_getpid());
+ g_ib_thread_state = IB_THREAD_EXIT;
+ dapl_os_unlock(&g_hca_lock);
+}
+#endif
#ifndef OPENIB_OSD_H
#define OPENIB_OSD_H
+#include <rdma/rdma_cma.h>
+#include <rdma/rdma_cma_abi.h>
#include <byteswap.h>
#include <sys/poll.h>
+#include <rdma/rdma_cma.h>\r
#include <winsock2.h>\r
#include <ws2tcpip.h>\r
\r
DCM_REJECTING,
DCM_REJECTED,
DCM_CONNECTED,
- DCM_RELEASED,
+ DCM_RELEASE,
DCM_DISC_PENDING,
DCM_DISCONNECTED,
DCM_DESTROY,
DCM_RTU_PENDING,
- DCM_DISC_RECV
+ DCM_DISC_RECV,
+ DCM_FREE,
} DAPL_CM_STATE;
"CM_REJECTING",
"CM_REJECTED",
"CM_CONNECTED",
- "CM_RELEASED",
+ "CM_RELEASE",
"CM_DISC_PENDING",
"CM_DISCONNECTED",
"CM_DESTROY",
"CM_RTU_PENDING",
- "CM_DISC_RECV"
+ "CM_DISC_RECV",
+ "CM_FREE"
};
- return ((st < 0 || st > 15) ? "Invalid CM state?" : state[st]);
+ return ((st < 0 || st > 16) ? "Invalid CM state?" : state[st]);
}
STATIC _INLINE_ char * dapl_cm_op_str(IN int op)
access |= IBV_ACCESS_REMOTE_WRITE;
if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges)
access |= IBV_ACCESS_REMOTE_READ;
- if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges)
- access |= IBV_ACCESS_REMOTE_READ;
- if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges)
- access |= IBV_ACCESS_REMOTE_READ;
#ifdef DAT_EXTENSIONS
if (DAT_IB_MEM_PRIV_REMOTE_ATOMIC & privileges)
access |= IBV_ACCESS_REMOTE_ATOMIC;
-/*\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
-#include "dapl.h"\r
-#include "dapl_adapter_util.h"\r
-\r
-/*\r
- * dapl_ib_qp_alloc\r
- *\r
- * Alloc a QP\r
- *\r
- * Input:\r
- * *ep_ptr pointer to EP INFO\r
- * ib_hca_handle provider HCA handle\r
- * ib_pd_handle provider protection domain handle\r
- * cq_recv provider recv CQ handle\r
- * cq_send provider send CQ handle\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_qp_alloc(IN DAPL_IA * ia_ptr,\r
- IN DAPL_EP * ep_ptr, IN DAPL_EP * ep_ctx_ptr)\r
-{\r
- DAT_EP_ATTR *attr;\r
- DAPL_EVD *rcv_evd, *req_evd;\r
- ib_cq_handle_t rcv_cq, req_cq;\r
- ib_pd_handle_t ib_pd_handle;\r
- struct ibv_qp_init_attr qp_create;\r
-#ifdef _OPENIB_CMA_\r
- dp_ib_cm_handle_t conn;\r
-#endif\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " qp_alloc: ia_ptr %p ep_ptr %p ep_ctx_ptr %p\n",\r
- ia_ptr, ep_ptr, ep_ctx_ptr);\r
-\r
- attr = &ep_ptr->param.ep_attr;\r
- ib_pd_handle = ((DAPL_PZ *) ep_ptr->param.pz_handle)->pd_handle;\r
- rcv_evd = (DAPL_EVD *) ep_ptr->param.recv_evd_handle;\r
- req_evd = (DAPL_EVD *) ep_ptr->param.request_evd_handle;\r
-\r
- /* \r
- * DAT allows usage model of EP's with no EVD's but IB does not. \r
- * Create a CQ with zero entries under the covers to support and \r
- * catch any invalid posting. \r
- */\r
- if (rcv_evd != DAT_HANDLE_NULL)\r
- rcv_cq = rcv_evd->ib_cq_handle;\r
- else if (!ia_ptr->hca_ptr->ib_trans.ib_cq_empty)\r
- rcv_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty;\r
- else {\r
- struct ibv_comp_channel *channel;\r
-\r
- channel = ibv_create_comp_channel(ia_ptr->hca_ptr->ib_hca_handle);\r
- if (!channel)\r
- return (dapl_convert_errno(ENOMEM, "create_cq"));\r
- \r
- /* Call IB verbs to create CQ */\r
- rcv_cq = ibv_create_cq(ia_ptr->hca_ptr->ib_hca_handle,\r
- 0, NULL, channel, 0);\r
-\r
- if (rcv_cq == IB_INVALID_HANDLE) {\r
- ibv_destroy_comp_channel(channel);\r
- return (dapl_convert_errno(ENOMEM, "create_cq"));\r
- }\r
-\r
- ia_ptr->hca_ptr->ib_trans.ib_cq_empty = rcv_cq;\r
- }\r
- if (req_evd != DAT_HANDLE_NULL)\r
- req_cq = req_evd->ib_cq_handle;\r
- else\r
- req_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty;\r
-\r
- /* \r
- * IMPLEMENTATION NOTE:\r
- * uDAPL allows consumers to post buffers on the EP after creation\r
- * and before a connect request (outbound and inbound). This forces\r
- * a binding to a device during the hca_open call and requires the\r
- * consumer to predetermine which device to listen on or connect from.\r
- * This restriction eliminates any option of listening or connecting \r
- * over multiple devices. uDAPL should add API's to resolve addresses \r
- * and bind to the device at the approriate time (before connect \r
- * and after CR arrives). Discovery should happen at connection time \r
- * based on addressing and not on static configuration during open.\r
- */\r
-\r
-#ifdef _OPENIB_CMA_\r
- /* Allocate CM and initialize lock */\r
- if ((conn = dapls_ib_cm_create(ep_ptr)) == NULL)\r
- return (dapl_convert_errno(ENOMEM, "create_cq"));\r
-\r
- /* open identifies the local device; per DAT specification */\r
- if (rdma_bind_addr(conn->cm_id,\r
- (struct sockaddr *)&ia_ptr->hca_ptr->hca_address))\r
- return (dapl_convert_errno(EAFNOSUPPORT, "create_cq"));\r
-#endif\r
- /* Setup attributes and create qp */\r
- dapl_os_memzero((void *)&qp_create, sizeof(qp_create));\r
- qp_create.send_cq = req_cq;\r
- qp_create.cap.max_send_wr = attr->max_request_dtos;\r
- qp_create.cap.max_send_sge = attr->max_request_iov;\r
- qp_create.cap.max_inline_data =\r
- ia_ptr->hca_ptr->ib_trans.max_inline_send;\r
- qp_create.qp_type = IBV_QPT_RC;\r
- qp_create.qp_context = (void *)ep_ptr;\r
-\r
-#ifdef DAT_EXTENSIONS \r
- if (attr->service_type == DAT_IB_SERVICE_TYPE_UD) {\r
-#ifdef _OPENIB_CMA_\r
- return (DAT_NOT_IMPLEMENTED);\r
-#endif\r
- qp_create.qp_type = IBV_QPT_UD;\r
- if (attr->max_message_size >\r
- (128 << ia_ptr->hca_ptr->ib_trans.mtu)) {\r
- return (DAT_INVALID_PARAMETER | DAT_INVALID_ARG6);\r
- }\r
- }\r
-#endif\r
- \r
- /* ibv assumes rcv_cq is never NULL, set to req_cq */\r
- if (rcv_cq == NULL) {\r
- qp_create.recv_cq = req_cq;\r
- qp_create.cap.max_recv_wr = 0;\r
- qp_create.cap.max_recv_sge = 0;\r
- } else {\r
- qp_create.recv_cq = rcv_cq;\r
- qp_create.cap.max_recv_wr = attr->max_recv_dtos;\r
- qp_create.cap.max_recv_sge = attr->max_recv_iov;\r
- }\r
-\r
-#ifdef _OPENIB_CMA_\r
- if (rdma_create_qp(conn->cm_id, ib_pd_handle, &qp_create)) {\r
- dapls_ib_cm_free(conn, ep_ptr);\r
- return (dapl_convert_errno(errno, "create_qp"));\r
- }\r
- ep_ptr->qp_handle = conn->cm_id->qp;\r
- ep_ptr->cm_handle = conn;\r
- ep_ptr->qp_state = IBV_QPS_INIT;\r
-\r
- ep_ptr->param.local_port_qual = rdma_get_src_port(conn->cm_id);\r
-#else\r
- ep_ptr->qp_handle = ibv_create_qp(ib_pd_handle, &qp_create);\r
- if (!ep_ptr->qp_handle)\r
- return (dapl_convert_errno(ENOMEM, "create_qp"));\r
- \r
- /* Setup QP attributes for INIT state on the way out */\r
- if (dapls_modify_qp_state(ep_ptr->qp_handle,\r
- IBV_QPS_INIT, 0, 0, 0) != DAT_SUCCESS) {\r
- ibv_destroy_qp(ep_ptr->qp_handle);\r
- ep_ptr->qp_handle = IB_INVALID_HANDLE;\r
- return DAT_INTERNAL_ERROR;\r
- }\r
-#endif\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " qp_alloc: qpn %p sq %d,%d rq %d,%d\n",\r
- ep_ptr->qp_handle->qp_num,\r
- qp_create.cap.max_send_wr, qp_create.cap.max_send_sge,\r
- qp_create.cap.max_recv_wr, qp_create.cap.max_recv_sge);\r
-\r
- return DAT_SUCCESS;\r
-}\r
-\r
-/*\r
- * dapl_ib_qp_free\r
- *\r
- * Free a QP\r
- *\r
- * Input:\r
- * ia_handle IA handle\r
- * *ep_ptr pointer to EP INFO\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Returns:\r
- * DAT_SUCCESS\r
- * dapl_convert_errno\r
- *\r
- */\r
-DAT_RETURN dapls_ib_qp_free(IN DAPL_IA * ia_ptr, IN DAPL_EP * ep_ptr)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " qp_free: ep_ptr %p qp %p\n",\r
- ep_ptr, ep_ptr->qp_handle);\r
-\r
- if (ep_ptr->cm_handle != NULL) {\r
- dapls_ib_cm_free(ep_ptr->cm_handle, ep_ptr);\r
- }\r
- \r
- if (ep_ptr->qp_handle != NULL) {\r
- /* force error state to flush queue, then destroy */\r
- dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0,0,0);\r
-\r
- if (ibv_destroy_qp(ep_ptr->qp_handle))\r
- return (dapl_convert_errno(errno, "destroy_qp"));\r
-\r
- ep_ptr->qp_handle = NULL;\r
- }\r
-\r
-#ifdef DAT_EXTENSIONS\r
- /* UD endpoints can have many CR associations and will not\r
- * set ep->cm_handle. Call provider with cm_ptr null to incidate\r
- * UD type multi CR's for this EP. It will parse internal list\r
- * and cleanup all associations.\r
- */\r
- if (ep_ptr->param.ep_attr.service_type == DAT_IB_SERVICE_TYPE_UD) \r
- dapls_ib_cm_free(NULL, ep_ptr);\r
-#endif\r
-\r
- return DAT_SUCCESS;\r
-}\r
-\r
-/*\r
- * dapl_ib_qp_modify\r
- *\r
- * Set the QP to the parameters specified in an EP_PARAM\r
- *\r
- * The EP_PARAM structure that is provided has been\r
- * sanitized such that only non-zero values are valid.\r
- *\r
- * Input:\r
- * ib_hca_handle HCA handle\r
- * qp_handle QP handle\r
- * ep_attr Sanitized EP Params\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Returns:\r
- * DAT_SUCCESS\r
- * DAT_INSUFFICIENT_RESOURCES\r
- * DAT_INVALID_PARAMETER\r
- *\r
- */\r
-DAT_RETURN\r
-dapls_ib_qp_modify(IN DAPL_IA * ia_ptr,\r
- IN DAPL_EP * ep_ptr, IN DAT_EP_ATTR * attr)\r
-{\r
- struct ibv_qp_attr qp_attr;\r
-\r
- if (ep_ptr->qp_handle == IB_INVALID_HANDLE)\r
- return DAT_INVALID_PARAMETER;\r
-\r
- /* \r
- * EP state, qp_handle state should be an indication\r
- * of current state but the only way to be sure is with\r
- * a user mode ibv_query_qp call which is NOT available \r
- */\r
-\r
- /* move to error state if necessary */\r
- if ((ep_ptr->qp_state == IB_QP_STATE_ERROR) &&\r
- (ep_ptr->qp_handle->state != IBV_QPS_ERR)) {\r
- return (dapls_modify_qp_state(ep_ptr->qp_handle, \r
- IBV_QPS_ERR, 0, 0, 0));\r
- }\r
-\r
- /*\r
- * Check if we have the right qp_state to modify attributes\r
- */\r
- if ((ep_ptr->qp_handle->state != IBV_QPS_RTR) &&\r
- (ep_ptr->qp_handle->state != IBV_QPS_RTS))\r
- return DAT_INVALID_STATE;\r
-\r
- /* Adjust to current EP attributes */\r
- dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
- qp_attr.cap.max_send_wr = attr->max_request_dtos;\r
- qp_attr.cap.max_recv_wr = attr->max_recv_dtos;\r
- qp_attr.cap.max_send_sge = attr->max_request_iov;\r
- qp_attr.cap.max_recv_sge = attr->max_recv_iov;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- "modify_qp: qp %p sq %d,%d, rq %d,%d\n",\r
- ep_ptr->qp_handle,\r
- qp_attr.cap.max_send_wr, qp_attr.cap.max_send_sge,\r
- qp_attr.cap.max_recv_wr, qp_attr.cap.max_recv_sge);\r
-\r
- if (ibv_modify_qp(ep_ptr->qp_handle, &qp_attr, IBV_QP_CAP)) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_ERR,\r
- "modify_qp: modify ep %p qp %p failed\n",\r
- ep_ptr, ep_ptr->qp_handle);\r
- return (dapl_convert_errno(errno, "modify_qp_state"));\r
- }\r
-\r
- return DAT_SUCCESS;\r
-}\r
-\r
-/*\r
- * dapls_ib_reinit_ep\r
- *\r
- * Move the QP to INIT state again.\r
- *\r
- * Input:\r
- * ep_ptr DAPL_EP\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Returns:\r
- * void\r
- *\r
- */\r
-#if defined(_WIN32) || defined(_WIN64) || defined(_OPENIB_CMA_)\r
-void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr)\r
-{\r
- /* work around bug in low level driver - 3/24/09 */\r
- /* RTS -> RESET -> INIT -> ERROR QP transition crashes system */\r
- if (ep_ptr->qp_handle != IB_INVALID_HANDLE) {\r
- dapls_ib_qp_free(ep_ptr->header.owner_ia, ep_ptr);\r
- dapls_ib_qp_alloc(ep_ptr->header.owner_ia, ep_ptr, ep_ptr);\r
- }\r
-}\r
-#else // _WIN32 || _WIN64\r
-void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr)\r
-{\r
- if (ep_ptr->qp_handle != IB_INVALID_HANDLE &&\r
- ep_ptr->qp_handle->qp_type != IBV_QPT_UD) {\r
- /* move to RESET state and then to INIT */\r
- dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_RESET,0,0,0);\r
- dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_INIT,0,0,0);\r
- }\r
-}\r
-#endif // _WIN32 || _WIN64\r
-\r
-/* \r
- * Generic QP modify for init, reset, error, RTS, RTR\r
- * For UD, create_ah on RTR, qkey on INIT\r
- * CM msg provides QP attributes, info in network order\r
- */\r
-DAT_RETURN\r
-dapls_modify_qp_state(IN ib_qp_handle_t qp_handle,\r
- IN ib_qp_state_t qp_state, \r
- IN uint32_t qpn,\r
- IN uint16_t lid,\r
- IN ib_gid_handle_t gid)\r
-{\r
- struct ibv_qp_attr qp_attr;\r
- enum ibv_qp_attr_mask mask = IBV_QP_STATE;\r
- DAPL_EP *ep_ptr = (DAPL_EP *) qp_handle->qp_context;\r
- DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;\r
- int ret;\r
-\r
- dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
- qp_attr.qp_state = qp_state;\r
- \r
- switch (qp_state) {\r
- case IBV_QPS_RTR:\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " QPS_RTR: type %d qpn 0x%x lid 0x%x"\r
- " port %d ep %p qp_state %d \n",\r
- qp_handle->qp_type, \r
- ntohl(qpn), ntohs(lid), \r
- ia_ptr->hca_ptr->port_num,\r
- ep_ptr, ep_ptr->qp_state);\r
-\r
- mask |= IBV_QP_AV |\r
- IBV_QP_PATH_MTU |\r
- IBV_QP_DEST_QPN |\r
- IBV_QP_RQ_PSN |\r
- IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER;\r
-\r
- qp_attr.dest_qp_num = ntohl(qpn);\r
- qp_attr.rq_psn = 1;\r
- qp_attr.path_mtu = ia_ptr->hca_ptr->ib_trans.mtu;\r
- qp_attr.max_dest_rd_atomic =\r
- ep_ptr->param.ep_attr.max_rdma_read_out;\r
- qp_attr.min_rnr_timer =\r
- ia_ptr->hca_ptr->ib_trans.rnr_timer;\r
-\r
- /* address handle. RC and UD */\r
- qp_attr.ah_attr.dlid = ntohs(lid);\r
- if (ia_ptr->hca_ptr->ib_trans.global) {\r
- qp_attr.ah_attr.is_global = 1;\r
- qp_attr.ah_attr.grh.dgid.global.subnet_prefix = \r
- ntohll(gid->global.subnet_prefix);\r
- qp_attr.ah_attr.grh.dgid.global.interface_id = \r
- ntohll(gid->global.interface_id);\r
- qp_attr.ah_attr.grh.hop_limit =\r
- ia_ptr->hca_ptr->ib_trans.hop_limit;\r
- qp_attr.ah_attr.grh.traffic_class =\r
- ia_ptr->hca_ptr->ib_trans.tclass;\r
- }\r
- qp_attr.ah_attr.sl = 0;\r
- qp_attr.ah_attr.src_path_bits = 0;\r
- qp_attr.ah_attr.port_num = ia_ptr->hca_ptr->port_num;\r
-\r
- /* UD: already in RTR, RTS state */\r
- if (qp_handle->qp_type == IBV_QPT_UD) {\r
- mask = IBV_QP_STATE;\r
- if (ep_ptr->qp_state == IBV_QPS_RTR ||\r
- ep_ptr->qp_state == IBV_QPS_RTS)\r
- return DAT_SUCCESS;\r
- }\r
- break;\r
- case IBV_QPS_RTS:\r
- if (qp_handle->qp_type == IBV_QPT_RC) {\r
- mask |= IBV_QP_SQ_PSN |\r
- IBV_QP_TIMEOUT |\r
- IBV_QP_RETRY_CNT |\r
- IBV_QP_RNR_RETRY | IBV_QP_MAX_QP_RD_ATOMIC;\r
- qp_attr.timeout =\r
- ia_ptr->hca_ptr->ib_trans.ack_timer;\r
- qp_attr.retry_cnt =\r
- ia_ptr->hca_ptr->ib_trans.ack_retry;\r
- qp_attr.rnr_retry =\r
- ia_ptr->hca_ptr->ib_trans.rnr_retry;\r
- qp_attr.max_rd_atomic =\r
- ep_ptr->param.ep_attr.max_rdma_read_out;\r
- }\r
- /* RC and UD */\r
- qp_attr.qp_state = IBV_QPS_RTS;\r
- qp_attr.sq_psn = 1;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " QPS_RTS: psn %x rd_atomic %d ack %d "\r
- " retry %d rnr_retry %d ep %p qp_state %d\n",\r
- qp_attr.sq_psn, qp_attr.max_rd_atomic,\r
- qp_attr.timeout, qp_attr.retry_cnt,\r
- qp_attr.rnr_retry, ep_ptr,\r
- ep_ptr->qp_state);\r
-\r
- if (qp_handle->qp_type == IBV_QPT_UD) {\r
- /* already RTS, multi remote AH's on QP */\r
- if (ep_ptr->qp_state == IBV_QPS_RTS)\r
- return DAT_SUCCESS;\r
- else\r
- mask = IBV_QP_STATE | IBV_QP_SQ_PSN;\r
- }\r
- break;\r
- case IBV_QPS_INIT:\r
- mask |= IBV_QP_PKEY_INDEX | IBV_QP_PORT;\r
- if (qp_handle->qp_type == IBV_QPT_RC) {\r
- mask |= IBV_QP_ACCESS_FLAGS;\r
- qp_attr.qp_access_flags =\r
- IBV_ACCESS_LOCAL_WRITE |\r
- IBV_ACCESS_REMOTE_WRITE |\r
- IBV_ACCESS_REMOTE_READ |\r
- IBV_ACCESS_REMOTE_ATOMIC |\r
- IBV_ACCESS_MW_BIND;\r
- }\r
-\r
- if (qp_handle->qp_type == IBV_QPT_UD) {\r
- /* already INIT, multi remote AH's on QP */\r
- if (ep_ptr->qp_state == IBV_QPS_INIT)\r
- return DAT_SUCCESS;\r
- mask |= IBV_QP_QKEY;\r
- qp_attr.qkey = DAT_UD_QKEY;\r
- }\r
-\r
- qp_attr.pkey_index = 0;\r
- qp_attr.port_num = ia_ptr->hca_ptr->port_num;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " QPS_INIT: pi %x port %x acc %x qkey 0x%x\n",\r
- qp_attr.pkey_index, qp_attr.port_num,\r
- qp_attr.qp_access_flags, qp_attr.qkey);\r
- break;\r
- default:\r
- break;\r
- }\r
-\r
- ret = ibv_modify_qp(qp_handle, &qp_attr, mask);\r
- if (ret == 0) {\r
- ep_ptr->qp_state = qp_state;\r
- return DAT_SUCCESS;\r
- } else {\r
- return (dapl_convert_errno(errno, "modify_qp_state"));\r
- }\r
-}\r
-\r
-/* Modify UD type QP from init, rtr, rts, info network order */\r
-DAT_RETURN \r
-dapls_modify_qp_ud(IN DAPL_HCA *hca, IN ib_qp_handle_t qp)\r
-{\r
- struct ibv_qp_attr qp_attr;\r
-\r
- /* modify QP, setup and prepost buffers */\r
- dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
- qp_attr.qp_state = IBV_QPS_INIT;\r
- qp_attr.pkey_index = 0;\r
- qp_attr.port_num = hca->port_num;\r
- qp_attr.qkey = DAT_UD_QKEY;\r
- if (ibv_modify_qp(qp, &qp_attr, \r
- IBV_QP_STATE |\r
- IBV_QP_PKEY_INDEX |\r
- IBV_QP_PORT |\r
- IBV_QP_QKEY)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " modify_ud_qp INIT: ERR %s\n", strerror(errno));\r
- return (dapl_convert_errno(errno, "modify_qp"));\r
- }\r
- dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
- qp_attr.qp_state = IBV_QPS_RTR;\r
- if (ibv_modify_qp(qp, &qp_attr,IBV_QP_STATE)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR, \r
- " modify_ud_qp RTR: ERR %s\n", strerror(errno));\r
- return (dapl_convert_errno(errno, "modify_qp"));\r
- }\r
- dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
- qp_attr.qp_state = IBV_QPS_RTS;\r
- qp_attr.sq_psn = 1;\r
- if (ibv_modify_qp(qp, &qp_attr, \r
- IBV_QP_STATE | IBV_QP_SQ_PSN)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " modify_ud_qp RTS: ERR %s\n", strerror(errno));\r
- return (dapl_convert_errno(errno, "modify_qp"));\r
- }\r
- return DAT_SUCCESS;\r
-}\r
-\r
-/* Create address handle for remote QP, info in network order */\r
-ib_ah_handle_t \r
-dapls_create_ah(IN DAPL_HCA *hca,\r
- IN ib_pd_handle_t pd,\r
- IN ib_qp_handle_t qp,\r
- IN uint16_t lid,\r
- IN ib_gid_handle_t gid)\r
-{\r
- struct ibv_qp_attr qp_attr;\r
- ib_ah_handle_t ah;\r
-\r
- if (qp->qp_type != IBV_QPT_UD)\r
- return NULL;\r
-\r
- dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));\r
- qp_attr.qp_state = IBV_QP_STATE;\r
-\r
- /* address handle. RC and UD */\r
- qp_attr.ah_attr.dlid = ntohs(lid);\r
- if (gid != NULL) {\r
- dapl_log(DAPL_DBG_TYPE_CM, "dapl_create_ah: with GID\n");\r
- qp_attr.ah_attr.is_global = 1;\r
- qp_attr.ah_attr.grh.dgid.global.subnet_prefix = \r
- ntohll(gid->global.subnet_prefix);\r
- qp_attr.ah_attr.grh.dgid.global.interface_id = \r
- ntohll(gid->global.interface_id);\r
- qp_attr.ah_attr.grh.hop_limit = hca->ib_trans.hop_limit;\r
- qp_attr.ah_attr.grh.traffic_class = hca->ib_trans.tclass;\r
- }\r
- qp_attr.ah_attr.sl = 0;\r
- qp_attr.ah_attr.src_path_bits = 0;\r
- qp_attr.ah_attr.port_num = hca->port_num;\r
-\r
- dapl_log(DAPL_DBG_TYPE_CM, \r
- " dapls_create_ah: port %x lid %x pd %p ctx %p handle 0x%x\n", \r
- hca->port_num,qp_attr.ah_attr.dlid, pd, pd->context, pd->handle);\r
-\r
- /* UD: create AH for remote side */\r
- ah = ibv_create_ah(pd, &qp_attr.ah_attr);\r
- if (!ah) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " create_ah: ERR %s\n", strerror(errno));\r
- return NULL;\r
- }\r
-\r
- dapl_log(DAPL_DBG_TYPE_CM, \r
- " dapls_create_ah: AH %p for lid %x\n", \r
- ah, qp_attr.ah_attr.dlid);\r
-\r
- return ah;\r
-}\r
-\r
-/*\r
- * Local variables:\r
- * c-indent-level: 4\r
- * c-basic-offset: 4\r
- * tab-width: 8\r
- * End:\r
- */\r
+/*
+ * 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.
+ */
+#include "dapl.h"
+#include "dapl_adapter_util.h"
+#include "dapl_ep_util.h"
+
+/*
+ * dapl_ib_qp_alloc
+ *
+ * Alloc a QP
+ *
+ * Input:
+ * *ep_ptr pointer to EP INFO
+ * ib_hca_handle provider HCA handle
+ * ib_pd_handle provider protection domain handle
+ * cq_recv provider recv CQ handle
+ * cq_send provider send CQ handle
+ *
+ * Output:
+ * none
+ *
+ * Returns:
+ * DAT_SUCCESS
+ * DAT_INSUFFICIENT_RESOURCES
+ * DAT_INTERNAL_ERROR
+ *
+ */
+DAT_RETURN
+dapls_ib_qp_alloc(IN DAPL_IA * ia_ptr,
+ IN DAPL_EP * ep_ptr, IN DAPL_EP * ep_ctx_ptr)
+{
+ DAT_EP_ATTR *attr;
+ DAPL_EVD *rcv_evd, *req_evd;
+ ib_cq_handle_t rcv_cq, req_cq;
+ ib_pd_handle_t ib_pd_handle;
+ struct ibv_qp_init_attr qp_create;
+#ifdef _OPENIB_CMA_
+ dp_ib_cm_handle_t conn;
+#endif
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " qp_alloc: ia_ptr %p ep_ptr %p ep_ctx_ptr %p\n",
+ ia_ptr, ep_ptr, ep_ctx_ptr);
+
+ attr = &ep_ptr->param.ep_attr;
+ ib_pd_handle = ((DAPL_PZ *) ep_ptr->param.pz_handle)->pd_handle;
+ rcv_evd = (DAPL_EVD *) ep_ptr->param.recv_evd_handle;
+ req_evd = (DAPL_EVD *) ep_ptr->param.request_evd_handle;
+
+ /*
+ * DAT allows usage model of EP's with no EVD's but IB does not.
+ * Create a CQ with zero entries under the covers to support and
+ * catch any invalid posting.
+ */
+ if (rcv_evd != DAT_HANDLE_NULL)
+ rcv_cq = rcv_evd->ib_cq_handle;
+ else if (!ia_ptr->hca_ptr->ib_trans.ib_cq_empty)
+ rcv_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty;
+ else {
+ struct ibv_comp_channel *channel;
+
+ channel = ibv_create_comp_channel(ia_ptr->hca_ptr->ib_hca_handle);
+ if (!channel)
+ return (dapl_convert_errno(ENOMEM, "create_cq"));
+
+ /* Call IB verbs to create CQ */
+ rcv_cq = ibv_create_cq(ia_ptr->hca_ptr->ib_hca_handle,
+ 0, NULL, channel, 0);
+
+ if (rcv_cq == IB_INVALID_HANDLE) {
+ ibv_destroy_comp_channel(channel);
+ return (dapl_convert_errno(ENOMEM, "create_cq"));
+ }
+
+ ia_ptr->hca_ptr->ib_trans.ib_cq_empty = rcv_cq;
+ }
+ if (req_evd != DAT_HANDLE_NULL)
+ req_cq = req_evd->ib_cq_handle;
+ else
+ req_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty;
+
+ /*
+ * IMPLEMENTATION NOTE:
+ * uDAPL allows consumers to post buffers on the EP after creation
+ * and before a connect request (outbound and inbound). This forces
+ * a binding to a device during the hca_open call and requires the
+ * consumer to predetermine which device to listen on or connect from.
+ * This restriction eliminates any option of listening or connecting
+ * over multiple devices. uDAPL should add API's to resolve addresses
+ * and bind to the device at the approriate time (before connect
+ * and after CR arrives). Discovery should happen at connection time
+ * based on addressing and not on static configuration during open.
+ */
+
+#ifdef _OPENIB_CMA_
+ /* Allocate CM and initialize lock */
+ if ((conn = dapls_ib_cm_create(ep_ptr)) == NULL)
+ return (dapl_convert_errno(ENOMEM, "cm_create"));
+
+ /* open identifies the local device; per DAT specification */
+ if (rdma_bind_addr(conn->cm_id,
+ (struct sockaddr *)&ia_ptr->hca_ptr->hca_address)) {
+ dapls_cm_free(conn);
+ return (dapl_convert_errno(EAFNOSUPPORT, "rdma_bind_addr"));
+ }
+#endif
+ /* Setup attributes and create qp */
+ dapl_os_memzero((void *)&qp_create, sizeof(qp_create));
+ qp_create.send_cq = req_cq;
+ qp_create.cap.max_send_wr = attr->max_request_dtos;
+ qp_create.cap.max_send_sge = attr->max_request_iov;
+ qp_create.cap.max_inline_data =
+ ia_ptr->hca_ptr->ib_trans.max_inline_send;
+ qp_create.qp_type = IBV_QPT_RC;
+ qp_create.qp_context = (void *)ep_ptr;
+
+#ifdef DAT_EXTENSIONS
+ if (attr->service_type == DAT_IB_SERVICE_TYPE_UD) {
+#ifdef _OPENIB_CMA_
+ return (DAT_NOT_IMPLEMENTED);
+#endif
+ qp_create.qp_type = IBV_QPT_UD;
+ if (attr->max_message_size >
+ (128 << ia_ptr->hca_ptr->ib_trans.mtu)) {
+ return (DAT_INVALID_PARAMETER | DAT_INVALID_ARG6);
+ }
+ }
+#endif
+
+ /* ibv assumes rcv_cq is never NULL, set to req_cq */
+ if (rcv_cq == NULL) {
+ qp_create.recv_cq = req_cq;
+ qp_create.cap.max_recv_wr = 0;
+ qp_create.cap.max_recv_sge = 0;
+ } else {
+ qp_create.recv_cq = rcv_cq;
+ qp_create.cap.max_recv_wr = attr->max_recv_dtos;
+ qp_create.cap.max_recv_sge = attr->max_recv_iov;
+ }
+
+#ifdef _OPENIB_CMA_
+ if (rdma_create_qp(conn->cm_id, ib_pd_handle, &qp_create)) {
+ dapls_cm_free(conn);
+ return (dapl_convert_errno(errno, "rdma_create_qp"));
+ }
+ ep_ptr->qp_handle = conn->cm_id->qp;
+ ep_ptr->qp_state = IBV_QPS_INIT;
+
+ ep_ptr->param.local_port_qual = rdma_get_src_port(conn->cm_id);
+#else
+ ep_ptr->qp_handle = ibv_create_qp(ib_pd_handle, &qp_create);
+ if (!ep_ptr->qp_handle)
+ return (dapl_convert_errno(ENOMEM, "create_qp"));
+
+ /* Setup QP attributes for INIT state on the way out */
+ if (dapls_modify_qp_state(ep_ptr->qp_handle,
+ IBV_QPS_INIT, 0, 0, 0) != DAT_SUCCESS) {
+ ibv_destroy_qp(ep_ptr->qp_handle);
+ ep_ptr->qp_handle = IB_INVALID_HANDLE;
+ return DAT_INTERNAL_ERROR;
+ }
+#endif
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " qp_alloc: qpn %p sq %d,%d rq %d,%d\n",
+ ep_ptr->qp_handle->qp_num,
+ qp_create.cap.max_send_wr, qp_create.cap.max_send_sge,
+ qp_create.cap.max_recv_wr, qp_create.cap.max_recv_sge);
+
+ return DAT_SUCCESS;
+}
+
+/*
+ * dapl_ib_qp_free
+ *
+ * Free a QP
+ *
+ * Input:
+ * ia_handle IA handle
+ * *ep_ptr pointer to EP INFO
+ *
+ * Output:
+ * none
+ *
+ * Returns:
+ * DAT_SUCCESS
+ * dapl_convert_errno
+ *
+ */
+DAT_RETURN dapls_ib_qp_free(IN DAPL_IA * ia_ptr, IN DAPL_EP * ep_ptr)
+{
+#ifdef _OPENIB_CMA_
+ dp_ib_cm_handle_t cm_ptr = dapl_get_cm_from_ep(ep_ptr);
+
+ dapl_os_lock(&ep_ptr->header.lock);
+ if (cm_ptr && cm_ptr->cm_id->qp) {
+ rdma_destroy_qp(cm_ptr->cm_id);
+ cm_ptr->cm_id->qp = NULL;
+ ep_ptr->qp_handle = NULL;
+ }
+#else
+ dapl_os_lock(&ep_ptr->header.lock);
+ if (ep_ptr->qp_handle != NULL) {
+ /* force error state to flush queue, then destroy */
+ dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0,0,0);
+
+ if (ibv_destroy_qp(ep_ptr->qp_handle)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " qp_free: ibv_destroy_qp error - %s\n",
+ strerror(errno));
+ }
+ ep_ptr->qp_handle = NULL;
+ }
+#endif
+ dapl_os_unlock(&ep_ptr->header.lock);
+ return DAT_SUCCESS;
+}
+
+/*
+ * dapl_ib_qp_modify
+ *
+ * Set the QP to the parameters specified in an EP_PARAM
+ *
+ * The EP_PARAM structure that is provided has been
+ * sanitized such that only non-zero values are valid.
+ *
+ * Input:
+ * ib_hca_handle HCA handle
+ * qp_handle QP handle
+ * ep_attr Sanitized EP Params
+ *
+ * Output:
+ * none
+ *
+ * Returns:
+ * DAT_SUCCESS
+ * DAT_INSUFFICIENT_RESOURCES
+ * DAT_INVALID_PARAMETER
+ *
+ */
+DAT_RETURN
+dapls_ib_qp_modify(IN DAPL_IA * ia_ptr,
+ IN DAPL_EP * ep_ptr, IN DAT_EP_ATTR * attr)
+{
+ struct ibv_qp_attr qp_attr;
+
+ if (ep_ptr->qp_handle == IB_INVALID_HANDLE)
+ return DAT_INVALID_PARAMETER;
+
+ /*
+ * EP state, qp_handle state should be an indication
+ * of current state but the only way to be sure is with
+ * a user mode ibv_query_qp call which is NOT available
+ */
+
+ /* move to error state if necessary */
+ if ((ep_ptr->qp_state == IB_QP_STATE_ERROR) &&
+ (ep_ptr->qp_handle->state != IBV_QPS_ERR)) {
+ return (dapls_modify_qp_state(ep_ptr->qp_handle,
+ IBV_QPS_ERR, 0, 0, 0));
+ }
+
+ /*
+ * Check if we have the right qp_state to modify attributes
+ */
+ if ((ep_ptr->qp_handle->state != IBV_QPS_RTR) &&
+ (ep_ptr->qp_handle->state != IBV_QPS_RTS))
+ return DAT_INVALID_STATE;
+
+ /* Adjust to current EP attributes */
+ dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
+ qp_attr.cap.max_send_wr = attr->max_request_dtos;
+ qp_attr.cap.max_recv_wr = attr->max_recv_dtos;
+ qp_attr.cap.max_send_sge = attr->max_request_iov;
+ qp_attr.cap.max_recv_sge = attr->max_recv_iov;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ "modify_qp: qp %p sq %d,%d, rq %d,%d\n",
+ ep_ptr->qp_handle,
+ qp_attr.cap.max_send_wr, qp_attr.cap.max_send_sge,
+ qp_attr.cap.max_recv_wr, qp_attr.cap.max_recv_sge);
+
+ if (ibv_modify_qp(ep_ptr->qp_handle, &qp_attr, IBV_QP_CAP)) {
+ dapl_dbg_log(DAPL_DBG_TYPE_ERR,
+ "modify_qp: modify ep %p qp %p failed\n",
+ ep_ptr, ep_ptr->qp_handle);
+ return (dapl_convert_errno(errno, "modify_qp_state"));
+ }
+
+ return DAT_SUCCESS;
+}
+
+/*
+ * dapls_ib_reinit_ep
+ *
+ * Move the QP to INIT state again.
+ *
+ * Input:
+ * ep_ptr DAPL_EP
+ *
+ * Output:
+ * none
+ *
+ * Returns:
+ * void
+ *
+ */
+#if defined(_WIN32) || defined(_WIN64) || defined(_OPENIB_CMA_)
+void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr)
+{
+ dp_ib_cm_handle_t cm_ptr, next_cm_ptr;
+
+ /* work around bug in low level driver - 3/24/09 */
+ /* RTS -> RESET -> INIT -> ERROR QP transition crashes system */
+ if (ep_ptr->qp_handle != IB_INVALID_HANDLE) {
+ dapls_ib_qp_free(ep_ptr->header.owner_ia, ep_ptr);
+
+ /* free any CM object's created */
+ cm_ptr = (dapl_llist_is_empty(&ep_ptr->cm_list_head)
+ ? NULL : dapl_llist_peek_head(&ep_ptr->cm_list_head));
+ while (cm_ptr != NULL) {
+ next_cm_ptr = dapl_llist_next_entry(&ep_ptr->cm_list_head,
+ &cm_ptr->list_entry);
+ dapls_cm_free(cm_ptr);
+ cm_ptr = next_cm_ptr;
+ }
+ dapls_ib_qp_alloc(ep_ptr->header.owner_ia, ep_ptr, ep_ptr);
+ }
+}
+#else // _WIN32 || _WIN64
+void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr)
+{
+ if (ep_ptr->qp_handle != IB_INVALID_HANDLE &&
+ ep_ptr->qp_handle->qp_type != IBV_QPT_UD) {
+ /* move to RESET state and then to INIT */
+ dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_RESET,0,0,0);
+ dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_INIT,0,0,0);
+ }
+}
+#endif // _WIN32 || _WIN64
+
+/*
+ * Generic QP modify for init, reset, error, RTS, RTR
+ * For UD, create_ah on RTR, qkey on INIT
+ * CM msg provides QP attributes, info in network order
+ */
+DAT_RETURN
+dapls_modify_qp_state(IN ib_qp_handle_t qp_handle,
+ IN ib_qp_state_t qp_state,
+ IN uint32_t qpn,
+ IN uint16_t lid,
+ IN ib_gid_handle_t gid)
+{
+ struct ibv_qp_attr qp_attr;
+ enum ibv_qp_attr_mask mask = IBV_QP_STATE;
+ DAPL_EP *ep_ptr = (DAPL_EP *) qp_handle->qp_context;
+ DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;
+ int ret;
+
+ dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
+ qp_attr.qp_state = qp_state;
+
+ switch (qp_state) {
+ case IBV_QPS_RTR:
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " QPS_RTR: type %d qpn 0x%x gid %p (%d) lid 0x%x"
+ " port %d ep %p qp_state %d \n",
+ qp_handle->qp_type, ntohl(qpn), gid,
+ ia_ptr->hca_ptr->ib_trans.global,
+ ntohs(lid), ia_ptr->hca_ptr->port_num,
+ ep_ptr, ep_ptr->qp_state);
+
+ mask |= IBV_QP_AV |
+ IBV_QP_PATH_MTU |
+ IBV_QP_DEST_QPN |
+ IBV_QP_RQ_PSN |
+ IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER;
+
+ qp_attr.dest_qp_num = ntohl(qpn);
+ qp_attr.rq_psn = 1;
+ qp_attr.path_mtu = ia_ptr->hca_ptr->ib_trans.mtu;
+ qp_attr.max_dest_rd_atomic =
+ ep_ptr->param.ep_attr.max_rdma_read_out;
+ qp_attr.min_rnr_timer =
+ ia_ptr->hca_ptr->ib_trans.rnr_timer;
+
+ /* address handle. RC and UD */
+ qp_attr.ah_attr.dlid = ntohs(lid);
+ if (gid && ia_ptr->hca_ptr->ib_trans.global) {
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " QPS_RTR: GID Subnet 0x" F64x " ID 0x" F64x "\n",
+ (unsigned long long)htonll(gid->global.subnet_prefix),
+ (unsigned long long)htonll(gid->global.interface_id));
+
+ qp_attr.ah_attr.is_global = 1;
+ qp_attr.ah_attr.grh.dgid.global.subnet_prefix =
+ gid->global.subnet_prefix;
+ qp_attr.ah_attr.grh.dgid.global.interface_id =
+ gid->global.interface_id;
+ qp_attr.ah_attr.grh.hop_limit =
+ ia_ptr->hca_ptr->ib_trans.hop_limit;
+ qp_attr.ah_attr.grh.traffic_class =
+ ia_ptr->hca_ptr->ib_trans.tclass;
+ }
+ qp_attr.ah_attr.sl = 0;
+ qp_attr.ah_attr.src_path_bits = 0;
+ qp_attr.ah_attr.port_num = ia_ptr->hca_ptr->port_num;
+
+ /* UD: already in RTR, RTS state */
+ if (qp_handle->qp_type == IBV_QPT_UD) {
+ mask = IBV_QP_STATE;
+ if (ep_ptr->qp_state == IBV_QPS_RTR ||
+ ep_ptr->qp_state == IBV_QPS_RTS)
+ return DAT_SUCCESS;
+ }
+ break;
+ case IBV_QPS_RTS:
+ if (qp_handle->qp_type == IBV_QPT_RC) {
+ mask |= IBV_QP_SQ_PSN |
+ IBV_QP_TIMEOUT |
+ IBV_QP_RETRY_CNT |
+ IBV_QP_RNR_RETRY | IBV_QP_MAX_QP_RD_ATOMIC;
+ qp_attr.timeout =
+ ia_ptr->hca_ptr->ib_trans.ack_timer;
+ qp_attr.retry_cnt =
+ ia_ptr->hca_ptr->ib_trans.ack_retry;
+ qp_attr.rnr_retry =
+ ia_ptr->hca_ptr->ib_trans.rnr_retry;
+ qp_attr.max_rd_atomic =
+ ep_ptr->param.ep_attr.max_rdma_read_out;
+ }
+ /* RC and UD */
+ qp_attr.qp_state = IBV_QPS_RTS;
+ qp_attr.sq_psn = 1;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " QPS_RTS: psn %x rd_atomic %d ack %d "
+ " retry %d rnr_retry %d ep %p qp_state %d\n",
+ qp_attr.sq_psn, qp_attr.max_rd_atomic,
+ qp_attr.timeout, qp_attr.retry_cnt,
+ qp_attr.rnr_retry, ep_ptr,
+ ep_ptr->qp_state);
+
+ if (qp_handle->qp_type == IBV_QPT_UD) {
+ /* already RTS, multi remote AH's on QP */
+ if (ep_ptr->qp_state == IBV_QPS_RTS)
+ return DAT_SUCCESS;
+ else
+ mask = IBV_QP_STATE | IBV_QP_SQ_PSN;
+ }
+ break;
+ case IBV_QPS_INIT:
+ mask |= IBV_QP_PKEY_INDEX | IBV_QP_PORT;
+ if (qp_handle->qp_type == IBV_QPT_RC) {
+ mask |= IBV_QP_ACCESS_FLAGS;
+ qp_attr.qp_access_flags =
+ IBV_ACCESS_LOCAL_WRITE |
+ IBV_ACCESS_REMOTE_WRITE |
+ IBV_ACCESS_REMOTE_READ |
+ IBV_ACCESS_REMOTE_ATOMIC |
+ IBV_ACCESS_MW_BIND;
+ }
+
+ if (qp_handle->qp_type == IBV_QPT_UD) {
+ /* already INIT, multi remote AH's on QP */
+ if (ep_ptr->qp_state == IBV_QPS_INIT)
+ return DAT_SUCCESS;
+ mask |= IBV_QP_QKEY;
+ qp_attr.qkey = DAT_UD_QKEY;
+ }
+
+ qp_attr.pkey_index = 0;
+ qp_attr.port_num = ia_ptr->hca_ptr->port_num;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " QPS_INIT: pi %x port %x acc %x qkey 0x%x\n",
+ qp_attr.pkey_index, qp_attr.port_num,
+ qp_attr.qp_access_flags, qp_attr.qkey);
+ break;
+ default:
+ break;
+ }
+
+ ret = ibv_modify_qp(qp_handle, &qp_attr, mask);
+ if (ret == 0) {
+ ep_ptr->qp_state = qp_state;
+ return DAT_SUCCESS;
+ } else {
+ return (dapl_convert_errno(errno, "modify_qp_state"));
+ }
+}
+
+/* Modify UD type QP from init, rtr, rts, info network order */
+DAT_RETURN
+dapls_modify_qp_ud(IN DAPL_HCA *hca, IN ib_qp_handle_t qp)
+{
+ struct ibv_qp_attr qp_attr;
+
+ /* modify QP, setup and prepost buffers */
+ dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
+ qp_attr.qp_state = IBV_QPS_INIT;
+ qp_attr.pkey_index = 0;
+ qp_attr.port_num = hca->port_num;
+ qp_attr.qkey = DAT_UD_QKEY;
+ if (ibv_modify_qp(qp, &qp_attr,
+ IBV_QP_STATE |
+ IBV_QP_PKEY_INDEX |
+ IBV_QP_PORT |
+ IBV_QP_QKEY)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " modify_ud_qp INIT: ERR %s\n", strerror(errno));
+ return (dapl_convert_errno(errno, "modify_qp"));
+ }
+ dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
+ qp_attr.qp_state = IBV_QPS_RTR;
+ if (ibv_modify_qp(qp, &qp_attr,IBV_QP_STATE)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " modify_ud_qp RTR: ERR %s\n", strerror(errno));
+ return (dapl_convert_errno(errno, "modify_qp"));
+ }
+ dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
+ qp_attr.qp_state = IBV_QPS_RTS;
+ qp_attr.sq_psn = 1;
+ if (ibv_modify_qp(qp, &qp_attr,
+ IBV_QP_STATE | IBV_QP_SQ_PSN)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " modify_ud_qp RTS: ERR %s\n", strerror(errno));
+ return (dapl_convert_errno(errno, "modify_qp"));
+ }
+ return DAT_SUCCESS;
+}
+
+/* Create address handle for remote QP, info in network order */
+ib_ah_handle_t
+dapls_create_ah(IN DAPL_HCA *hca,
+ IN ib_pd_handle_t pd,
+ IN ib_qp_handle_t qp,
+ IN uint16_t lid,
+ IN ib_gid_handle_t gid)
+{
+ struct ibv_qp_attr qp_attr;
+ ib_ah_handle_t ah;
+
+ if (qp->qp_type != IBV_QPT_UD)
+ return NULL;
+
+ dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr));
+ qp_attr.qp_state = IBV_QP_STATE;
+
+ /* address handle. RC and UD */
+ qp_attr.ah_attr.dlid = ntohs(lid);
+ if (gid != NULL) {
+ dapl_log(DAPL_DBG_TYPE_CM, "dapl_create_ah: with GID\n");
+ qp_attr.ah_attr.is_global = 1;
+ qp_attr.ah_attr.grh.dgid.global.subnet_prefix =
+ ntohll(gid->global.subnet_prefix);
+ qp_attr.ah_attr.grh.dgid.global.interface_id =
+ ntohll(gid->global.interface_id);
+ qp_attr.ah_attr.grh.hop_limit = hca->ib_trans.hop_limit;
+ qp_attr.ah_attr.grh.traffic_class = hca->ib_trans.tclass;
+ }
+ qp_attr.ah_attr.sl = 0;
+ qp_attr.ah_attr.src_path_bits = 0;
+ qp_attr.ah_attr.port_num = hca->port_num;
+
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " dapls_create_ah: port %x lid %x pd %p ctx %p handle 0x%x\n",
+ hca->port_num,qp_attr.ah_attr.dlid, pd, pd->context, pd->handle);
+
+ /* UD: create AH for remote side */
+ ah = ibv_create_ah(pd, &qp_attr.ah_attr);
+ if (!ah) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " create_ah: ERR %s\n", strerror(errno));
+ return NULL;
+ }
+
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " dapls_create_ah: AH %p for lid %x\n",
+ ah, qp_attr.ah_attr.dlid);
+
+ return ah;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * End:
+ */
/* set MTU to actual settings */
ib_attrs[0].value = ia_ptr->hca_ptr->ib_trans.named_attr.value;
}
+
+/*
+ * Map all socket CM event codes to the DAT equivelent. Common to all providers
+ */
+#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_EVENT_ESTABLISHED},
+/* 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_BROKEN,
+ DAT_CONNECTION_EVENT_BROKEN},
+/* 11 */ {IB_CME_TIMEOUT,
+ DAT_CONNECTION_EVENT_TIMED_OUT},
+/* 12 */ {IB_CME_LOCAL_FAILURE, /* always last */
+ DAT_CONNECTION_EVENT_BROKEN}
+};
+
+/*
+ * 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;
+
+ if (ib_cm_event > IB_CME_LOCAL_FAILURE)
+ return (DAT_EVENT_NUMBER) 0;
+
+ 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 translate(%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;
+}
-/*\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: uDAPL\r
- *\r
- * Filename: dapl_ib_cm.c\r
- *\r
- * Author: Arlin Davis\r
- *\r
- * Created: 3/10/2005\r
- *\r
- * Description: \r
- *\r
- * The uDAPL openib provider - connection management\r
- *\r
- ****************************************************************************\r
- * Source Control System Information\r
- *\r
- * $Id: $\r
- *\r
- * Copyright (c) 2005 Intel Corporation. All rights reserved.\r
- *\r
- **************************************************************************/\r
-\r
-#if defined(_WIN32)\r
-#define FD_SETSIZE 1024\r
-#define DAPL_FD_SETSIZE FD_SETSIZE\r
-#endif\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_osd.h"\r
-\r
-#if defined(_WIN32) || defined(_WIN64)\r
-enum DAPL_FD_EVENTS {\r
- DAPL_FD_READ = 0x1,\r
- DAPL_FD_WRITE = 0x2,\r
- DAPL_FD_ERROR = 0x4\r
-};\r
-\r
-static int dapl_config_socket(DAPL_SOCKET s)\r
-{\r
- unsigned long nonblocking = 1;\r
- int ret, opt;\r
-\r
- ret = ioctlsocket(s, FIONBIO, &nonblocking);\r
-\r
- /* no delay for small packets */\r
- if (!ret)\r
- ret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, \r
- (char *)&opt, sizeof(opt));\r
- return ret;\r
-}\r
-\r
-static int dapl_connect_socket(DAPL_SOCKET s, struct sockaddr *addr,\r
- int addrlen)\r
-{\r
- int err;\r
-\r
- err = connect(s, addr, addrlen);\r
- if (err == SOCKET_ERROR)\r
- err = WSAGetLastError();\r
- return (err == WSAEWOULDBLOCK) ? EAGAIN : err;\r
-}\r
-\r
-struct dapl_fd_set {\r
- struct fd_set set[3];\r
-};\r
-\r
-static struct dapl_fd_set *dapl_alloc_fd_set(void)\r
-{\r
- return dapl_os_alloc(sizeof(struct dapl_fd_set));\r
-}\r
-\r
-static void dapl_fd_zero(struct dapl_fd_set *set)\r
-{\r
- FD_ZERO(&set->set[0]);\r
- FD_ZERO(&set->set[1]);\r
- FD_ZERO(&set->set[2]);\r
-}\r
-\r
-static int dapl_fd_set(DAPL_SOCKET s, struct dapl_fd_set *set,\r
- enum DAPL_FD_EVENTS event)\r
-{\r
- FD_SET(s, &set->set[(event == DAPL_FD_READ) ? 0 : 1]);\r
- FD_SET(s, &set->set[2]);\r
- return 0;\r
-}\r
-\r
-static enum DAPL_FD_EVENTS dapl_poll(DAPL_SOCKET s, enum DAPL_FD_EVENTS event)\r
-{\r
- struct fd_set rw_fds;\r
- struct fd_set err_fds;\r
- struct timeval tv;\r
- int ret;\r
-\r
- FD_ZERO(&rw_fds);\r
- FD_ZERO(&err_fds);\r
- FD_SET(s, &rw_fds);\r
- FD_SET(s, &err_fds);\r
-\r
- tv.tv_sec = 0;\r
- tv.tv_usec = 0;\r
-\r
- if (event == DAPL_FD_READ)\r
- ret = select(1, &rw_fds, NULL, &err_fds, &tv);\r
- else\r
- ret = select(1, NULL, &rw_fds, &err_fds, &tv);\r
-\r
- if (ret == 0)\r
- return 0;\r
- else if (ret == SOCKET_ERROR)\r
- return DAPL_FD_ERROR;\r
- else if (FD_ISSET(s, &rw_fds))\r
- return event;\r
- else\r
- return DAPL_FD_ERROR;\r
-}\r
-\r
-static int dapl_select(struct dapl_fd_set *set)\r
-{\r
- int ret;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: sleep\n");\r
- ret = select(0, &set->set[0], &set->set[1], &set->set[2], NULL);\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: wakeup\n");\r
-\r
- if (ret == SOCKET_ERROR)\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " dapl_select: error 0x%x\n", WSAGetLastError());\r
-\r
- return ret;\r
-}\r
-\r
-static int dapl_socket_errno(void)\r
-{\r
- int err;\r
-\r
- err = WSAGetLastError();\r
- switch (err) {\r
- case WSAEACCES:\r
- case WSAEADDRINUSE:\r
- return EADDRINUSE;\r
- case WSAECONNRESET:\r
- return ECONNRESET;\r
- default:\r
- return err;\r
- }\r
-}\r
-#else // _WIN32 || _WIN64\r
-enum DAPL_FD_EVENTS {\r
- DAPL_FD_READ = POLLIN,\r
- DAPL_FD_WRITE = POLLOUT,\r
- DAPL_FD_ERROR = POLLERR\r
-};\r
-\r
-static int dapl_config_socket(DAPL_SOCKET s)\r
-{\r
- int ret, opt = 1;\r
-\r
- /* non-blocking */\r
- ret = fcntl(s, F_GETFL);\r
- if (ret >= 0)\r
- ret = fcntl(s, F_SETFL, ret | O_NONBLOCK);\r
-\r
- /* no delay for small packets */\r
- if (!ret)\r
- ret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, \r
- (char *)&opt, sizeof(opt));\r
- return ret;\r
-}\r
-\r
-static int dapl_connect_socket(DAPL_SOCKET s, struct sockaddr *addr,\r
- int addrlen)\r
-{\r
- int ret;\r
-\r
- ret = connect(s, addr, addrlen);\r
-\r
- return (errno == EINPROGRESS) ? EAGAIN : ret;\r
-}\r
-\r
-struct dapl_fd_set {\r
- int index;\r
- struct pollfd set[DAPL_FD_SETSIZE];\r
-};\r
-\r
-static struct dapl_fd_set *dapl_alloc_fd_set(void)\r
-{\r
- return dapl_os_alloc(sizeof(struct dapl_fd_set));\r
-}\r
-\r
-static void dapl_fd_zero(struct dapl_fd_set *set)\r
-{\r
- set->index = 0;\r
-}\r
-\r
-static int dapl_fd_set(DAPL_SOCKET s, struct dapl_fd_set *set,\r
- enum DAPL_FD_EVENTS event)\r
-{\r
- if (set->index == DAPL_FD_SETSIZE - 1) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- "SCM ERR: cm_thread exceeded FD_SETSIZE %d\n",\r
- set->index + 1);\r
- return -1;\r
- }\r
-\r
- set->set[set->index].fd = s;\r
- set->set[set->index].revents = 0;\r
- set->set[set->index++].events = event;\r
- return 0;\r
-}\r
-\r
-static enum DAPL_FD_EVENTS dapl_poll(DAPL_SOCKET s, enum DAPL_FD_EVENTS event)\r
-{\r
- struct pollfd fds;\r
- int ret;\r
-\r
- fds.fd = s;\r
- fds.events = event;\r
- fds.revents = 0;\r
- ret = poll(&fds, 1, 0);\r
- dapl_log(DAPL_DBG_TYPE_CM, " dapl_poll: fd=%d ret=%d, evnts=0x%x\n",\r
- s, ret, fds.revents);\r
- if (ret == 0)\r
- return 0;\r
- else if (ret < 0 || (fds.revents & (POLLERR | POLLHUP | POLLNVAL))) \r
- return DAPL_FD_ERROR;\r
- else \r
- return event;\r
-}\r
-\r
-static int dapl_select(struct dapl_fd_set *set)\r
-{\r
- int ret;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: sleep, fds=%d\n", set->index);\r
- ret = poll(set->set, set->index, -1);\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: wakeup, ret=0x%x\n", ret);\r
- return ret;\r
-}\r
-\r
-#define dapl_socket_errno() errno\r
-#endif\r
-\r
-dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep)\r
-{\r
- dp_ib_cm_handle_t cm_ptr;\r
-\r
- /* Allocate CM, init lock, and initialize */\r
- if ((cm_ptr = dapl_os_alloc(sizeof(*cm_ptr))) == NULL)\r
- return NULL;\r
-\r
- (void)dapl_os_memzero(cm_ptr, sizeof(*cm_ptr));\r
- if (dapl_os_lock_init(&cm_ptr->lock))\r
- goto bail;\r
-\r
- cm_ptr->msg.ver = htons(DCM_VER);\r
- cm_ptr->socket = DAPL_INVALID_SOCKET;\r
- cm_ptr->ep = ep;\r
- return cm_ptr;\r
-bail:\r
- dapl_os_free(cm_ptr, sizeof(*cm_ptr));\r
- return NULL;\r
-}\r
-\r
-/* mark for destroy, remove all references, schedule cleanup */\r
-/* cm_ptr == NULL (UD), then multi CR's, kill all associated with EP */\r
-void dapls_ib_cm_free(dp_ib_cm_handle_t cm_ptr, DAPL_EP *ep)\r
-{\r
- DAPL_IA *ia_ptr;\r
- DAPL_HCA *hca_ptr = NULL;\r
- dp_ib_cm_handle_t cr, next_cr;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " cm_destroy: cm %p ep %p\n", cm_ptr, ep);\r
-\r
- if (cm_ptr == NULL)\r
- goto multi_cleanup;\r
-\r
- /* to notify cleanup thread */\r
- hca_ptr = cm_ptr->hca;\r
-\r
- /* cleanup, never made it to work queue */\r
- dapl_os_lock(&cm_ptr->lock);\r
- if (cm_ptr->state == DCM_INIT) {\r
- if (cm_ptr->socket != DAPL_INVALID_SOCKET) {\r
- shutdown(cm_ptr->socket, SHUT_RDWR);\r
- closesocket(cm_ptr->socket);\r
- }\r
- dapl_os_unlock(&cm_ptr->lock);\r
- dapl_os_lock_destroy(&cm_ptr->lock);\r
- dapl_os_free(cm_ptr, sizeof(*cm_ptr));\r
- return;\r
- }\r
-\r
- /* free could be called before disconnect, disc_clean will destroy */\r
- if (cm_ptr->state == DCM_CONNECTED) {\r
- dapl_os_unlock(&cm_ptr->lock);\r
- dapli_socket_disconnect(cm_ptr);\r
+/*
+ * 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: uDAPL
+ *
+ * Filename: dapl_ib_cm.c
+ *
+ * Author: Arlin Davis
+ *
+ * Created: 3/10/2005
+ *
+ * Description:
+ *
+ * The uDAPL openib provider - connection management
+ *
+ ****************************************************************************
+ * Source Control System Information
+ *
+ * $Id: $
+ *
+ * Copyright (c) 2005 Intel Corporation. All rights reserved.
+ *
+ **************************************************************************/
+
+#if defined(_WIN32)
+#define FD_SETSIZE 1024
+#define DAPL_FD_SETSIZE FD_SETSIZE
+#endif
+
+#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_ep_util.h"
+#include "dapl_osd.h"
+
+#if defined(_WIN32) || defined(_WIN64)
+enum DAPL_FD_EVENTS {
+ DAPL_FD_READ = 0x1,
+ DAPL_FD_WRITE = 0x2,
+ DAPL_FD_ERROR = 0x4
+};
+
+static int dapl_config_socket(DAPL_SOCKET s)
+{
+ unsigned long nonblocking = 1;
+ int ret, opt = 1;
+
+ ret = ioctlsocket(s, FIONBIO, &nonblocking);
+
+ /* no delay for small packets */
+ if (!ret)
+ ret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&opt, sizeof(opt));
+ return ret;
+}
+
+static int dapl_connect_socket(DAPL_SOCKET s, struct sockaddr *addr,
+ int addrlen)
+{
+ int err;
+
+ err = connect(s, addr, addrlen);
+ if (err == SOCKET_ERROR)
+ err = WSAGetLastError();
+ return (err == WSAEWOULDBLOCK) ? EAGAIN : err;
+}
+
+struct dapl_fd_set {
+ struct fd_set set[3];
+};
+
+static struct dapl_fd_set *dapl_alloc_fd_set(void)
+{
+ return dapl_os_alloc(sizeof(struct dapl_fd_set));
+}
+
+static void dapl_fd_zero(struct dapl_fd_set *set)
+{
+ FD_ZERO(&set->set[0]);
+ FD_ZERO(&set->set[1]);
+ FD_ZERO(&set->set[2]);
+}
+
+static int dapl_fd_set(DAPL_SOCKET s, struct dapl_fd_set *set,
+ enum DAPL_FD_EVENTS event)
+{
+ FD_SET(s, &set->set[(event == DAPL_FD_READ) ? 0 : 1]);
+ FD_SET(s, &set->set[2]);
+ return 0;
+}
+
+static enum DAPL_FD_EVENTS dapl_poll(DAPL_SOCKET s, enum DAPL_FD_EVENTS event)
+{
+ struct fd_set rw_fds;
+ struct fd_set err_fds;
+ struct timeval tv;
+ int ret;
+
+ FD_ZERO(&rw_fds);
+ FD_ZERO(&err_fds);
+ FD_SET(s, &rw_fds);
+ FD_SET(s, &err_fds);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ if (event == DAPL_FD_READ)
+ ret = select(1, &rw_fds, NULL, &err_fds, &tv);
+ else
+ ret = select(1, NULL, &rw_fds, &err_fds, &tv);
+
+ if (ret == 0)
+ return 0;
+ else if (ret == SOCKET_ERROR)
+ return DAPL_FD_ERROR;
+ else if (FD_ISSET(s, &rw_fds))
+ return event;
+ else
+ return DAPL_FD_ERROR;
+}
+
+static int dapl_select(struct dapl_fd_set *set)
+{
+ int ret;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: sleep\n");
+ ret = select(0, &set->set[0], &set->set[1], &set->set[2], NULL);
+ dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: wakeup\n");
+
+ if (ret == SOCKET_ERROR)
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " dapl_select: error 0x%x\n", WSAGetLastError());
+
+ return ret;
+}
+
+static int dapl_socket_errno(void)
+{
+ int err;
+
+ err = WSAGetLastError();
+ switch (err) {
+ case WSAEACCES:
+ case WSAEADDRINUSE:
+ return EADDRINUSE;
+ case WSAECONNRESET:
+ return ECONNRESET;
+ default:
+ return err;
+ }
+}
+#else // _WIN32 || _WIN64
+enum DAPL_FD_EVENTS {
+ DAPL_FD_READ = POLLIN,
+ DAPL_FD_WRITE = POLLOUT,
+ DAPL_FD_ERROR = POLLERR
+};
+
+static int dapl_config_socket(DAPL_SOCKET s)
+{
+ int ret, opt = 1;
+
+ /* non-blocking */
+ ret = fcntl(s, F_GETFL);
+ if (ret >= 0)
+ ret = fcntl(s, F_SETFL, ret | O_NONBLOCK);
+
+ /* no delay for small packets */
+ if (!ret)
+ ret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&opt, sizeof(opt));
+ return ret;
+}
+
+static int dapl_connect_socket(DAPL_SOCKET s, struct sockaddr *addr,
+ int addrlen)
+{
+ int ret;
+
+ ret = connect(s, addr, addrlen);
+
+ return (errno == EINPROGRESS) ? EAGAIN : ret;
+}
+
+struct dapl_fd_set {
+ int index;
+ struct pollfd set[DAPL_FD_SETSIZE];
+};
+
+static struct dapl_fd_set *dapl_alloc_fd_set(void)
+{
+ return dapl_os_alloc(sizeof(struct dapl_fd_set));
+}
+
+static void dapl_fd_zero(struct dapl_fd_set *set)
+{
+ set->index = 0;
+}
+
+static int dapl_fd_set(DAPL_SOCKET s, struct dapl_fd_set *set,
+ enum DAPL_FD_EVENTS event)
+{
+ if (set->index == DAPL_FD_SETSIZE - 1) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ "SCM ERR: cm_thread exceeded FD_SETSIZE %d\n",
+ set->index + 1);
+ return -1;
+ }
+
+ set->set[set->index].fd = s;
+ set->set[set->index].revents = 0;
+ set->set[set->index++].events = event;
+ return 0;
+}
+
+static enum DAPL_FD_EVENTS dapl_poll(DAPL_SOCKET s, enum DAPL_FD_EVENTS event)
+{
+ struct pollfd fds;
+ int ret;
+
+ fds.fd = s;
+ fds.events = event;
+ fds.revents = 0;
+ ret = poll(&fds, 1, 0);
+ dapl_log(DAPL_DBG_TYPE_THREAD, " dapl_poll: fd=%d ret=%d, evnts=0x%x\n",
+ s, ret, fds.revents);
+ if (ret == 0)
+ return 0;
+ else if (ret < 0 || (fds.revents & (POLLERR | POLLHUP | POLLNVAL)))
+ return DAPL_FD_ERROR;
+ else
+ return event;
+}
+
+static int dapl_select(struct dapl_fd_set *set)
+{
+ int ret;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " dapl_select: sleep, fds=%d\n", set->index);
+ ret = poll(set->set, set->index, -1);
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " dapl_select: wakeup, ret=0x%x\n", ret);
+ return ret;
+}
+
+#define dapl_socket_errno() errno
+#endif
+
+static void dapli_cm_thread_signal(dp_ib_cm_handle_t cm_ptr)
+{
+ send(cm_ptr->hca->ib_trans.scm[1], "w", sizeof "w", 0);
+}
+
+static void dapli_cm_free(dp_ib_cm_handle_t cm_ptr)
+{
+ dapl_os_lock(&cm_ptr->lock);
+ cm_ptr->state = DCM_FREE;
+ dapl_os_unlock(&cm_ptr->lock);
+ dapli_cm_thread_signal(cm_ptr);
+}
+
+static void dapli_cm_dealloc(dp_ib_cm_handle_t cm_ptr)
+{
+ dapl_os_assert(!cm_ptr->ref_count);
+
+ if (cm_ptr->socket != DAPL_INVALID_SOCKET) {
+ shutdown(cm_ptr->socket, SHUT_RDWR);
+ closesocket(cm_ptr->socket);
+ }
+ if (cm_ptr->ah)
+ ibv_destroy_ah(cm_ptr->ah);
+
+ dapl_os_lock_destroy(&cm_ptr->lock);
+ dapl_os_wait_object_destroy(&cm_ptr->event);
+ dapl_os_free(cm_ptr, sizeof(*cm_ptr));
+}
+
+void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr)
+{
+ dapl_os_lock(&cm_ptr->lock);
+ cm_ptr->ref_count++;
+ dapl_os_unlock(&cm_ptr->lock);
+}
+
+void dapls_cm_release(dp_ib_cm_handle_t cm_ptr)
+{
+ dapl_os_lock(&cm_ptr->lock);
+ cm_ptr->ref_count--;\r
+ if (cm_ptr->ref_count) {\r
+ dapl_os_unlock(&cm_ptr->lock);\r
return;\r
}\r
-\r
- cm_ptr->state = DCM_DESTROY;\r
- if ((cm_ptr->ep) && (cm_ptr->ep->cm_handle == cm_ptr)) {\r
- cm_ptr->ep->cm_handle = IB_INVALID_HANDLE;\r
- cm_ptr->ep = NULL;\r
- }\r
-\r
- dapl_os_unlock(&cm_ptr->lock);\r
- goto notify_thread;\r
-\r
-multi_cleanup:\r
-\r
- /* \r
- * UD CR objects are kept active because of direct private data references\r
- * from CONN events. The cr->socket is closed and marked inactive but the \r
- * object remains allocated and queued on the CR resource list. There can\r
- * be multiple CR's associated with a given EP. There is no way to determine \r
- * when consumer is finished with event until the dat_ep_free.\r
- *\r
- * Schedule destruction for all CR's associated with this EP, cr_thread will\r
- * complete the cleanup with state == DCM_DESTROY. \r
- */ \r
- ia_ptr = ep->header.owner_ia;\r
- dapl_os_lock(&ia_ptr->hca_ptr->ib_trans.lock);\r
- if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)\r
- &ia_ptr->hca_ptr->ib_trans.list))\r
- next_cr = dapl_llist_peek_head((DAPL_LLIST_HEAD*)\r
- &ia_ptr->hca_ptr->ib_trans.list);\r
- else\r
- next_cr = NULL;\r
-\r
- while (next_cr) {\r
- cr = next_cr;\r
- next_cr = dapl_llist_next_entry((DAPL_LLIST_HEAD*)\r
- &ia_ptr->hca_ptr->ib_trans.list,\r
- (DAPL_LLIST_ENTRY*)&cr->entry);\r
- if (cr->ep == ep) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " qp_free CR: ep %p cr %p\n", ep, cr);\r
- dapli_socket_disconnect(cr);\r
- dapl_os_lock(&cr->lock);\r
- hca_ptr = cr->hca;\r
- cr->ep = NULL;\r
- if (cr->ah) {\r
- ibv_destroy_ah(cr->ah);\r
- cr->ah = NULL;\r
- }\r
- cr->state = DCM_DESTROY;\r
- dapl_os_unlock(&cr->lock);\r
- }\r
- }\r
- dapl_os_unlock(&ia_ptr->hca_ptr->ib_trans.lock);\r
-\r
-notify_thread:\r
-\r
- /* wakeup work thread, if something destroyed */\r
- if (hca_ptr != NULL) \r
- send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0);\r
-}\r
-\r
-/* queue socket for processing CM work */\r
-static void dapli_cm_queue(struct ib_cm_handle *cm_ptr)\r
-{\r
- DAPL_HCA *hca = cm_ptr->hca;\r
-\r
- /* add to work queue for cr thread processing */\r
- dapl_llist_init_entry((DAPL_LLIST_ENTRY *) & cm_ptr->entry);\r
- dapl_os_lock(&hca->ib_trans.lock);\r
- dapl_llist_add_tail(&hca->ib_trans.list,\r
- (DAPL_LLIST_ENTRY *) & cm_ptr->entry, cm_ptr);\r
- dapl_os_unlock(&hca->ib_trans.lock);\r
-\r
- /* wakeup CM work thread */\r
- send(hca->ib_trans.scm[1], "w", sizeof "w", 0);\r
-}\r
-\r
-/*\r
- * ACTIVE/PASSIVE: called from CR thread or consumer via ep_disconnect\r
- * or from ep_free\r
- */\r
-DAT_RETURN dapli_socket_disconnect(dp_ib_cm_handle_t cm_ptr)\r
-{\r
- DAPL_EP *ep_ptr = cm_ptr->ep;\r
- DAT_UINT32 disc_data = htonl(0xdead);\r
-\r
- if (ep_ptr == NULL)\r
- return DAT_SUCCESS;\r
-\r
- dapl_os_lock(&cm_ptr->lock);\r
- if (cm_ptr->state != DCM_CONNECTED) {\r
- dapl_os_unlock(&cm_ptr->lock);\r
- return DAT_SUCCESS;\r
- }\r
-\r
- /* send disc date, close socket, schedule destroy */\r
- dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0,0,0);\r
- cm_ptr->state = DCM_DISCONNECTED;\r
- send(cm_ptr->socket, (char *)&disc_data, sizeof(disc_data), 0);\r
- dapl_os_unlock(&cm_ptr->lock);\r
-\r
- /* disconnect events for RC's only */\r
- if (ep_ptr->param.ep_attr.service_type == DAT_SERVICE_TYPE_RC) {\r
- if (ep_ptr->cr_ptr) {\r
- dapls_cr_callback(cm_ptr,\r
- IB_CME_DISCONNECTED,\r
- NULL, 0,\r
- ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr);\r
- } else {\r
- dapl_evd_connection_callback(ep_ptr->cm_handle,\r
- IB_CME_DISCONNECTED,\r
- NULL, 0, ep_ptr);\r
- }\r
- }\r
-\r
- /* scheduled destroy via disconnect clean in callback */\r
- return DAT_SUCCESS;\r
-}\r
-\r
-/*\r
- * ACTIVE: socket connected, send QP information to peer \r
- */\r
-static void dapli_socket_connected(dp_ib_cm_handle_t cm_ptr, int err)\r
-{\r
- int len, exp;\r
- struct iovec iov[2];\r
- struct dapl_ep *ep_ptr = cm_ptr->ep;\r
-\r
- if (err) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " CONN_PENDING: %s ERR %s -> %s %d\n",\r
- err == -1 ? "POLL" : "SOCKOPT",\r
- err == -1 ? strerror(errno) : strerror(err), \r
- inet_ntoa(((struct sockaddr_in *)\r
- &cm_ptr->addr)->sin_addr), \r
- ntohs(((struct sockaddr_in *)\r
- &cm_ptr->addr)->sin_port));\r
- goto bail;\r
- }\r
-\r
- cm_ptr->state = DCM_REP_PENDING;\r
-\r
- /* send qp info and pdata to remote peer */\r
- exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;\r
- iov[0].iov_base = (void *)&cm_ptr->msg;\r
- iov[0].iov_len = exp;\r
- if (cm_ptr->msg.p_size) {\r
- iov[1].iov_base = cm_ptr->msg.p_data;\r
- iov[1].iov_len = ntohs(cm_ptr->msg.p_size);\r
- len = writev(cm_ptr->socket, iov, 2);\r
- } else {\r
- len = writev(cm_ptr->socket, iov, 1);\r
- }\r
-\r
- if (len != (exp + ntohs(cm_ptr->msg.p_size))) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " CONN_PENDING len ERR %s, wcnt=%d(%d) -> %s\n",\r
- strerror(errno), len, \r
- exp + ntohs(cm_ptr->msg.p_size), \r
- inet_ntoa(((struct sockaddr_in *)\r
- ep_ptr->param.\r
- remote_ia_address_ptr)->sin_addr));\r
- goto bail;\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " CONN_PENDING: sending SRC lid=0x%x,"\r
- " qpn=0x%x, psize=%d\n",\r
- ntohs(cm_ptr->msg.saddr.ib.lid),\r
- ntohl(cm_ptr->msg.saddr.ib.qpn), \r
- ntohs(cm_ptr->msg.p_size));\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " CONN_PENDING: SRC GID subnet %016llx id %016llx\n",\r
- (unsigned long long)\r
- htonll(*(uint64_t*)&cm_ptr->msg.saddr.ib.gid[0]),\r
- (unsigned long long)\r
- htonll(*(uint64_t*)&cm_ptr->msg.saddr.ib.gid[8]));\r
- return;\r
-\r
-bail:\r
- /* close socket, free cm structure and post error event */\r
- dapls_ib_cm_free(cm_ptr, cm_ptr->ep);\r
- dapl_evd_connection_callback(NULL, IB_CME_LOCAL_FAILURE, NULL, 0, ep_ptr);\r
-}\r
-\r
-/*\r
- * ACTIVE: Create socket, connect, defer exchange QP information to CR thread\r
- * to avoid blocking. \r
- */\r
-DAT_RETURN\r
-dapli_socket_connect(DAPL_EP * ep_ptr,\r
- DAT_IA_ADDRESS_PTR r_addr,\r
- DAT_CONN_QUAL r_qual, DAT_COUNT p_size, DAT_PVOID p_data)\r
-{\r
- dp_ib_cm_handle_t cm_ptr;\r
- int ret;\r
- socklen_t sl;\r
- DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;\r
- DAT_RETURN dat_ret = DAT_INSUFFICIENT_RESOURCES;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect: r_qual %d p_size=%d\n",\r
- r_qual, p_size);\r
-\r
- cm_ptr = dapls_ib_cm_create(ep_ptr);\r
- if (cm_ptr == NULL)\r
- return dat_ret;\r
-\r
- /* create, connect, sockopt, and exchange QP information */\r
- if ((cm_ptr->socket =\r
- socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == DAPL_INVALID_SOCKET) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " connect: socket create ERR %s\n", strerror(errno));\r
- goto bail;\r
- }\r
-\r
- ret = dapl_config_socket(cm_ptr->socket);\r
- if (ret < 0) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " connect: config socket %d ERR %d %s\n",\r
- cm_ptr->socket, ret, strerror(dapl_socket_errno()));\r
- dat_ret = DAT_INTERNAL_ERROR;\r
- goto bail;\r
- }\r
-\r
- /* save remote address */\r
- dapl_os_memcpy(&cm_ptr->addr, r_addr, sizeof(r_addr));\r
-\r
-#ifdef DAPL_DBG\r
- /* DBG: Active PID [0], PASSIVE PID [2]*/\r
- *(uint16_t*)&cm_ptr->msg.resv[0] = htons((uint16_t)dapl_os_getpid()); \r
- *(uint16_t*)&cm_ptr->msg.resv[2] = ((struct sockaddr_in *)&cm_ptr->addr)->sin_port;\r
-#endif\r
- ((struct sockaddr_in *)&cm_ptr->addr)->sin_port = htons(r_qual + 1000);\r
- ret = dapl_connect_socket(cm_ptr->socket, (struct sockaddr *)&cm_ptr->addr,\r
- sizeof(cm_ptr->addr));\r
- if (ret && ret != EAGAIN) {\r
- dat_ret = DAT_INVALID_ADDRESS;\r
- goto bail;\r
- }\r
-\r
- /* REQ: QP info in msg.saddr, IA address in msg.daddr, and pdata */\r
- cm_ptr->msg.op = ntohs(DCM_REQ);\r
- cm_ptr->msg.saddr.ib.qpn = htonl(ep_ptr->qp_handle->qp_num);\r
- cm_ptr->msg.saddr.ib.qp_type = ep_ptr->qp_handle->qp_type;\r
- cm_ptr->msg.saddr.ib.lid = ia_ptr->hca_ptr->ib_trans.lid;\r
- dapl_os_memcpy(&cm_ptr->msg.saddr.ib.gid[0], \r
- &ia_ptr->hca_ptr->ib_trans.gid, 16);\r
- \r
- /* save references */\r
- cm_ptr->hca = ia_ptr->hca_ptr;\r
- cm_ptr->ep = ep_ptr;\r
- \r
- /* get local address information from socket */\r
- sl = sizeof(cm_ptr->msg.daddr.so);\r
- if (getsockname(cm_ptr->socket, (struct sockaddr *)&cm_ptr->msg.daddr.so, &sl)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " connect getsockname ERROR: %s -> %s r_qual %d\n",\r
- strerror(errno), \r
- inet_ntoa(((struct sockaddr_in *)r_addr)->sin_addr),\r
- (unsigned int)r_qual);;\r
- }\r
-\r
- if (p_size) {\r
- cm_ptr->msg.p_size = htons(p_size);\r
- dapl_os_memcpy(cm_ptr->msg.p_data, p_data, p_size);\r
- }\r
-\r
- /* connected or pending, either way results via async event */\r
- if (ret == 0)\r
- dapli_socket_connected(cm_ptr, 0);\r
- else\r
- cm_ptr->state = DCM_CONN_PENDING;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect: p_data=%p %p\n",\r
- cm_ptr->msg.p_data, cm_ptr->msg.p_data);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " connect: %s r_qual %d pending, p_sz=%d, %d %d ...\n",\r
- inet_ntoa(((struct sockaddr_in *)&cm_ptr->addr)->sin_addr), \r
- (unsigned int)r_qual, ntohs(cm_ptr->msg.p_size),\r
- cm_ptr->msg.p_data[0], cm_ptr->msg.p_data[1]);\r
-\r
- dapli_cm_queue(cm_ptr);\r
- return DAT_SUCCESS;\r
-\r
-bail:\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " connect ERROR: %s -> %s r_qual %d\n",\r
- strerror(errno), \r
- inet_ntoa(((struct sockaddr_in *)r_addr)->sin_addr),\r
- (unsigned int)r_qual);\r
-\r
- /* close socket, free cm structure */\r
- dapls_ib_cm_free(cm_ptr, NULL);\r
- return dat_ret;\r
-}\r
-\r
-/*\r
- * ACTIVE: exchange QP information, called from CR thread\r
- */\r
-static void dapli_socket_connect_rtu(dp_ib_cm_handle_t cm_ptr)\r
-{\r
- DAPL_EP *ep_ptr = cm_ptr->ep;\r
- int len, exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;\r
- ib_cm_events_t event = IB_CME_LOCAL_FAILURE;\r
- socklen_t sl;\r
-\r
- /* read DST information into cm_ptr, overwrite SRC info */\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect_rtu: recv peer QP data\n");\r
-\r
- len = recv(cm_ptr->socket, (char *)&cm_ptr->msg, exp, 0);\r
- if (len != exp || ntohs(cm_ptr->msg.ver) != DCM_VER) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " CONN_RTU read: sk %d ERR %s, rcnt=%d, v=%d -> %s PORT L-%x R-%x PID L-%x R-%x\n",\r
- cm_ptr->socket, strerror(errno), len, ntohs(cm_ptr->msg.ver),\r
- inet_ntoa(((struct sockaddr_in *)&cm_ptr->addr)->sin_addr),\r
- ntohs(((struct sockaddr_in *)&cm_ptr->msg.daddr.so)->sin_port),\r
- ntohs(((struct sockaddr_in *)&cm_ptr->addr)->sin_port),\r
- ntohs(*(uint16_t*)&cm_ptr->msg.resv[0]),\r
- ntohs(*(uint16_t*)&cm_ptr->msg.resv[2]));\r
-\r
- /* Retry; corner case where server tcp stack resets under load */\r
- if (dapl_socket_errno() == ECONNRESET) {\r
- closesocket(cm_ptr->socket);\r
- cm_ptr->socket = DAPL_INVALID_SOCKET;\r
- dapli_socket_connect(cm_ptr->ep, (DAT_IA_ADDRESS_PTR)&cm_ptr->addr, \r
- ntohs(((struct sockaddr_in *)&cm_ptr->addr)->sin_port) - 1000,\r
- ntohs(cm_ptr->msg.p_size), &cm_ptr->msg.p_data);\r
- dapls_ib_cm_free(cm_ptr, NULL);\r
- return;\r
- }\r
- goto bail;\r
- }\r
-\r
- /* keep the QP, address info in network order */\r
- \r
- /* save remote address information, in msg.daddr */\r
- dapl_os_memcpy(&ep_ptr->remote_ia_address,\r
- &cm_ptr->msg.daddr.so,\r
- sizeof(union dcm_addr));\r
-\r
- /* save local address information from socket */\r
- sl = sizeof(cm_ptr->addr);\r
- getsockname(cm_ptr->socket,(struct sockaddr *)&cm_ptr->addr, &sl);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " CONN_RTU: DST %s %d lid=0x%x,"\r
- " qpn=0x%x, qp_type=%d, psize=%d\n",\r
- inet_ntoa(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_addr),\r
- ntohs(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_port),\r
- ntohs(cm_ptr->msg.saddr.ib.lid),\r
- ntohl(cm_ptr->msg.saddr.ib.qpn), \r
- cm_ptr->msg.saddr.ib.qp_type, \r
- ntohs(cm_ptr->msg.p_size));\r
-\r
- /* validate private data size before reading */\r
- if (ntohs(cm_ptr->msg.p_size) > DCM_MAX_PDATA_SIZE) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " CONN_RTU read: psize (%d) wrong -> %s\n",\r
- ntohs(cm_ptr->msg.p_size), \r
- inet_ntoa(((struct sockaddr_in *)\r
- ep_ptr->param.\r
- remote_ia_address_ptr)->sin_addr));\r
- goto bail;\r
- }\r
-\r
- /* read private data into cm_handle if any present */\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP," CONN_RTU: read private data\n");\r
- exp = ntohs(cm_ptr->msg.p_size);\r
- if (exp) {\r
- len = recv(cm_ptr->socket, cm_ptr->msg.p_data, exp, 0);\r
- if (len != exp) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " CONN_RTU read pdata: ERR %s, rcnt=%d -> %s\n",\r
- strerror(errno), len,\r
- inet_ntoa(((struct sockaddr_in *)\r
- ep_ptr->param.\r
- remote_ia_address_ptr)->sin_addr));\r
- goto bail;\r
- }\r
- }\r
-\r
- /* check for consumer or protocol stack reject */\r
- if (ntohs(cm_ptr->msg.op) == DCM_REP)\r
- event = IB_CME_CONNECTED;\r
- else if (ntohs(cm_ptr->msg.op) == DCM_REJ_USER) \r
- event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA;\r
- else \r
- event = IB_CME_DESTINATION_REJECT;\r
- \r
- if (event != IB_CME_CONNECTED) {\r
- dapl_log(DAPL_DBG_TYPE_CM,\r
- " CONN_RTU: reject from %s %x\n",\r
- inet_ntoa(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_addr),\r
- ntohs(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_port));\r
- goto bail;\r
- }\r
-\r
- /* modify QP to RTR and then to RTS with remote info */\r
- dapl_os_lock(&ep_ptr->header.lock);\r
- if (dapls_modify_qp_state(ep_ptr->qp_handle,\r
- IBV_QPS_RTR, \r
- cm_ptr->msg.saddr.ib.qpn,\r
- cm_ptr->msg.saddr.ib.lid,\r
- NULL) != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " CONN_RTU: QPS_RTR ERR %s (%d,%d,%x,%x,%x) -> %s %x\n",\r
- strerror(errno), ep_ptr->qp_handle->qp_type,\r
- ep_ptr->qp_state, ep_ptr->qp_handle->qp_num,\r
- ntohl(cm_ptr->msg.saddr.ib.qpn), \r
- ntohs(cm_ptr->msg.saddr.ib.lid),\r
- inet_ntoa(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_addr),\r
- ntohs(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_port));\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- goto bail;\r
- }\r
- if (dapls_modify_qp_state(ep_ptr->qp_handle,\r
- IBV_QPS_RTS, \r
- cm_ptr->msg.saddr.ib.qpn,\r
- cm_ptr->msg.saddr.ib.lid,\r
- NULL) != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " CONN_RTU: QPS_RTS ERR %s (%d,%d,%x,%x,%x) -> %s %x\n",\r
- strerror(errno), ep_ptr->qp_handle->qp_type,\r
- ep_ptr->qp_state, ep_ptr->qp_handle->qp_num,\r
- ntohl(cm_ptr->msg.saddr.ib.qpn), \r
- ntohs(cm_ptr->msg.saddr.ib.lid),\r
- inet_ntoa(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_addr),\r
- ntohs(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_port));\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- goto bail;\r
- }\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect_rtu: send RTU\n");\r
-\r
- /* complete handshake after final QP state change, Just ver+op */\r
- cm_ptr->state = DCM_CONNECTED;\r
- cm_ptr->msg.op = ntohs(DCM_RTU);\r
- if (send(cm_ptr->socket, (char *)&cm_ptr->msg, 4, 0) == -1) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " CONN_RTU: write error = %s\n", strerror(errno));\r
- goto bail;\r
- }\r
- /* post the event with private data */\r
- event = IB_CME_CONNECTED;\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " ACTIVE: connected!\n");\r
-\r
-#ifdef DAT_EXTENSIONS\r
-ud_bail:\r
- if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) {\r
- DAT_IB_EXTENSION_EVENT_DATA xevent;\r
- ib_pd_handle_t pd_handle = \r
- ((DAPL_PZ *)ep_ptr->param.pz_handle)->pd_handle;\r
-\r
- if (event == IB_CME_CONNECTED) {\r
- cm_ptr->ah = dapls_create_ah(cm_ptr->hca, pd_handle,\r
- ep_ptr->qp_handle,\r
- cm_ptr->msg.saddr.ib.lid, \r
- NULL);\r
- if (cm_ptr->ah) {\r
- /* post UD extended EVENT */\r
- xevent.status = 0;\r
- xevent.type = DAT_IB_UD_REMOTE_AH;\r
- xevent.remote_ah.ah = cm_ptr->ah;\r
- xevent.remote_ah.qpn = ntohl(cm_ptr->msg.saddr.ib.qpn);\r
- dapl_os_memcpy(&xevent.remote_ah.ia_addr,\r
- &ep_ptr->remote_ia_address,\r
- sizeof(union dcm_addr));\r
- event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED;\r
-\r
- dapl_log(DAPL_DBG_TYPE_CM, \r
- " CONN_RTU: UD AH %p for lid 0x%x"\r
- " qpn 0x%x\n", \r
- cm_ptr->ah, \r
- ntohs(cm_ptr->msg.saddr.ib.lid),\r
- ntohl(cm_ptr->msg.saddr.ib.qpn));\r
- \r
- } else \r
- event = DAT_IB_UD_CONNECTION_ERROR_EVENT;\r
- \r
- } else if (event == IB_CME_LOCAL_FAILURE) {\r
- event = DAT_IB_UD_CONNECTION_ERROR_EVENT;\r
- } else \r
- event = DAT_IB_UD_CONNECTION_REJECT_EVENT;\r
- \r
- dapls_evd_post_connection_event_ext(\r
- (DAPL_EVD *) ep_ptr->param.connect_evd_handle,\r
- event,\r
- (DAT_EP_HANDLE) ep_ptr,\r
- (DAT_COUNT) exp,\r
- (DAT_PVOID *) cm_ptr->msg.p_data,\r
- (DAT_PVOID *) &xevent);\r
-\r
- /* done with socket, don't destroy cm_ptr, need pdata */\r
- closesocket(cm_ptr->socket);\r
- cm_ptr->socket = DAPL_INVALID_SOCKET;\r
- cm_ptr->state = DCM_RELEASED;\r
- } else\r
-#endif\r
- {\r
- ep_ptr->cm_handle = cm_ptr; /* only RC, multi CR's on UD */\r
- dapl_evd_connection_callback(cm_ptr, event, cm_ptr->msg.p_data,\r
- DCM_MAX_PDATA_SIZE, ep_ptr);\r
- }\r
- return;\r
-\r
-bail:\r
-\r
-#ifdef DAT_EXTENSIONS\r
- if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) \r
- goto ud_bail;\r
-#endif\r
- /* close socket, and post error event */\r
- dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0, 0, 0);\r
- closesocket(cm_ptr->socket);\r
- cm_ptr->socket = DAPL_INVALID_SOCKET;\r
- dapl_evd_connection_callback(NULL, event, cm_ptr->msg.p_data,\r
- DCM_MAX_PDATA_SIZE, ep_ptr);\r
-}\r
-\r
-/*\r
- * PASSIVE: Create socket, listen, accept, exchange QP information \r
- */\r
-DAT_RETURN\r
-dapli_socket_listen(DAPL_IA * ia_ptr, DAT_CONN_QUAL serviceID, DAPL_SP * sp_ptr)\r
-{\r
- struct sockaddr_in addr;\r
- ib_cm_srvc_handle_t cm_ptr = NULL;\r
- DAT_RETURN dat_status = DAT_SUCCESS;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " listen(ia_ptr %p ServiceID %d sp_ptr %p)\n",\r
- ia_ptr, serviceID, sp_ptr);\r
-\r
- cm_ptr = dapls_ib_cm_create(NULL);\r
- if (cm_ptr == NULL)\r
- return DAT_INSUFFICIENT_RESOURCES;\r
-\r
- cm_ptr->sp = sp_ptr;\r
- cm_ptr->hca = ia_ptr->hca_ptr;\r
-\r
- /* bind, listen, set sockopt, accept, exchange data */\r
- if ((cm_ptr->socket =\r
- socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == DAPL_INVALID_SOCKET) {\r
- dapl_log(DAPL_DBG_TYPE_ERR, " ERR: listen socket create: %s\n",\r
- strerror(errno));\r
- dat_status = DAT_INSUFFICIENT_RESOURCES;\r
- goto bail;\r
- }\r
-\r
- addr.sin_port = htons(serviceID + 1000);\r
- addr.sin_family = AF_INET;\r
- addr.sin_addr = ((struct sockaddr_in *) &ia_ptr->hca_ptr->hca_address)->sin_addr;\r
-\r
- if ((bind(cm_ptr->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0)\r
- || (listen(cm_ptr->socket, 128) < 0)) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " listen: ERROR %s on conn_qual 0x%x\n",\r
- strerror(errno), serviceID + 1000);\r
- if (dapl_socket_errno() == EADDRINUSE)\r
- dat_status = DAT_CONN_QUAL_IN_USE;\r
- else\r
- dat_status = DAT_CONN_QUAL_UNAVAILABLE;\r
- goto bail;\r
- }\r
-\r
- /* set cm_handle for this service point, save listen socket */\r
- sp_ptr->cm_srvc_handle = cm_ptr;\r
- dapl_os_memcpy(&cm_ptr->addr, &addr, sizeof(addr)); \r
-\r
- /* queue up listen socket to process inbound CR's */\r
- cm_ptr->state = DCM_LISTEN;\r
- dapli_cm_queue(cm_ptr);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " listen: qual 0x%x cr %p s_fd %d\n",\r
- ntohs(serviceID + 1000), cm_ptr, cm_ptr->socket);\r
-\r
- return dat_status;\r
-bail:\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " listen: ERROR on conn_qual 0x%x\n", serviceID + 1000);\r
- dapls_ib_cm_free(cm_ptr, cm_ptr->ep);\r
- return dat_status;\r
-}\r
-\r
-/*\r
- * PASSIVE: accept socket \r
- */\r
-static void dapli_socket_accept(ib_cm_srvc_handle_t cm_ptr)\r
-{\r
- dp_ib_cm_handle_t acm_ptr;\r
- int ret, len, opt = 1;\r
- socklen_t sl;\r
-\r
- /* \r
- * Accept all CR's on this port to avoid half-connection (SYN_RCV)\r
- * stalls with many to one connection storms\r
- */\r
- do {\r
- /* Allocate accept CM and initialize */\r
- if ((acm_ptr = dapls_ib_cm_create(NULL)) == NULL)\r
- return;\r
-\r
- acm_ptr->sp = cm_ptr->sp;\r
- acm_ptr->hca = cm_ptr->hca;\r
-\r
- len = sizeof(union dcm_addr);\r
- acm_ptr->socket = accept(cm_ptr->socket,\r
- (struct sockaddr *)\r
- &acm_ptr->msg.daddr.so,\r
- (socklen_t *) &len);\r
- if (acm_ptr->socket == DAPL_INVALID_SOCKET) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT: ERR %s on FD %d l_cr %p\n",\r
- strerror(errno), cm_ptr->socket, cm_ptr);\r
- dapls_ib_cm_free(acm_ptr, acm_ptr->ep);\r
- return;\r
- }\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " accepting from %s %x\n",\r
- inet_ntoa(((struct sockaddr_in *)\r
- &acm_ptr->msg.daddr.so)->sin_addr),\r
- ntohs(((struct sockaddr_in *)\r
- &acm_ptr->msg.daddr.so)->sin_port));\r
-\r
- /* no delay for small packets */\r
- ret = setsockopt(acm_ptr->socket, IPPROTO_TCP, TCP_NODELAY,\r
- (char *)&opt, sizeof(opt));\r
- if (ret)\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT: NODELAY setsockopt: 0x%x 0x%x %s\n",\r
- ret, dapl_socket_errno(), strerror(dapl_socket_errno()));\r
- \r
- /* get local address information from socket */\r
- sl = sizeof(acm_ptr->addr);\r
- getsockname(acm_ptr->socket, (struct sockaddr *)&acm_ptr->addr, &sl);\r
- acm_ptr->state = DCM_ACCEPTING;\r
- dapli_cm_queue(acm_ptr);\r
- \r
- } while (dapl_poll(cm_ptr->socket, DAPL_FD_READ) == DAPL_FD_READ);\r
-}\r
-\r
-/*\r
- * PASSIVE: receive peer QP information, private data, post cr_event \r
- */\r
-static void dapli_socket_accept_data(ib_cm_srvc_handle_t acm_ptr)\r
-{\r
- int len, exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;\r
- void *p_data = NULL;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " socket accepted, read QP data\n");\r
-\r
- /* read in DST QP info, IA address. check for private data */\r
- len = recv(acm_ptr->socket, (char *)&acm_ptr->msg, exp, 0);\r
- if (len != exp || ntohs(acm_ptr->msg.ver) != DCM_VER) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT read: ERR %s, rcnt=%d, ver=%d\n",\r
- strerror(errno), len, ntohs(acm_ptr->msg.ver));\r
- goto bail;\r
- }\r
-\r
- /* keep the QP, address info in network order */\r
-\r
- /* validate private data size before reading */\r
- exp = ntohs(acm_ptr->msg.p_size);\r
- if (exp > DCM_MAX_PDATA_SIZE) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " accept read: psize (%d) wrong\n",\r
- acm_ptr->msg.p_size);\r
- goto bail;\r
- }\r
-\r
- /* read private data into cm_handle if any present */\r
- if (exp) {\r
- len = recv(acm_ptr->socket, acm_ptr->msg.p_data, exp, 0);\r
- if (len != exp) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " accept read pdata: ERR %s, rcnt=%d\n",\r
- strerror(errno), len);\r
- goto bail;\r
- }\r
- p_data = acm_ptr->msg.p_data;\r
- }\r
-\r
- acm_ptr->state = DCM_ACCEPTING_DATA;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " ACCEPT: DST %s %x lid=0x%x, qpn=0x%x, psz=%d\n",\r
- inet_ntoa(((struct sockaddr_in *)\r
- &acm_ptr->msg.daddr.so)->sin_addr), \r
- ntohs(((struct sockaddr_in *)\r
- &acm_ptr->msg.daddr.so)->sin_port),\r
- ntohs(acm_ptr->msg.saddr.ib.lid), \r
- ntohl(acm_ptr->msg.saddr.ib.qpn), exp);\r
-\r
-#ifdef DAT_EXTENSIONS\r
- if (acm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) {\r
- DAT_IB_EXTENSION_EVENT_DATA xevent;\r
-\r
- /* post EVENT, modify_qp created ah */\r
- xevent.status = 0;\r
- xevent.type = DAT_IB_UD_CONNECT_REQUEST;\r
-\r
- dapls_evd_post_cr_event_ext(acm_ptr->sp,\r
- DAT_IB_UD_CONNECTION_REQUEST_EVENT,\r
- acm_ptr,\r
- (DAT_COUNT) exp,\r
- (DAT_PVOID *) acm_ptr->msg.p_data,\r
- (DAT_PVOID *) &xevent);\r
- } else\r
-#endif\r
- /* trigger CR event and return SUCCESS */\r
- dapls_cr_callback(acm_ptr,\r
- IB_CME_CONNECTION_REQUEST_PENDING,\r
- p_data, exp, acm_ptr->sp);\r
- return;\r
-bail:\r
- /* close socket, free cm structure, active will see close as rej */\r
- dapls_ib_cm_free(acm_ptr, acm_ptr->ep);\r
- return;\r
-}\r
-\r
-/*\r
- * PASSIVE: consumer accept, send local QP information, private data, \r
- * queue on work thread to receive RTU information to avoid blocking\r
- * user thread. \r
- */\r
-static DAT_RETURN\r
-dapli_socket_accept_usr(DAPL_EP * ep_ptr,\r
- DAPL_CR * cr_ptr, DAT_COUNT p_size, DAT_PVOID p_data)\r
-{\r
- DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;\r
- dp_ib_cm_handle_t cm_ptr = cr_ptr->ib_cm_handle;\r
- ib_cm_msg_t local;\r
- struct iovec iov[2];\r
- int len, exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;\r
- DAT_RETURN ret = DAT_INTERNAL_ERROR;\r
- socklen_t sl;\r
-\r
- if (p_size > DCM_MAX_PDATA_SIZE) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " accept_usr: psize(%d) too large\n", p_size);\r
- return DAT_LENGTH_ERROR;\r
- }\r
-\r
- /* must have a accepted socket */\r
- if (cm_ptr->socket == DAPL_INVALID_SOCKET) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " accept_usr: cm socket invalid\n");\r
- goto bail;\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " ACCEPT_USR: remote lid=0x%x"\r
- " qpn=0x%x qp_type %d, psize=%d\n",\r
- ntohs(cm_ptr->msg.saddr.ib.lid),\r
- ntohl(cm_ptr->msg.saddr.ib.qpn), \r
- cm_ptr->msg.saddr.ib.qp_type, \r
- ntohs(cm_ptr->msg.p_size));\r
-\r
-#ifdef DAT_EXTENSIONS\r
- if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD &&\r
- ep_ptr->qp_handle->qp_type != IBV_QPT_UD) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT_USR: ERR remote QP is UD,"\r
- ", but local QP is not\n");\r
- ret = (DAT_INVALID_HANDLE | DAT_INVALID_HANDLE_EP);\r
- goto bail;\r
- }\r
-#endif\r
-\r
- /* modify QP to RTR and then to RTS with remote info already read */\r
- dapl_os_lock(&ep_ptr->header.lock);\r
- if (dapls_modify_qp_state(ep_ptr->qp_handle,\r
- IBV_QPS_RTR, \r
- cm_ptr->msg.saddr.ib.qpn,\r
- cm_ptr->msg.saddr.ib.lid,\r
- NULL) != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT_USR: QPS_RTR ERR %s -> %s\n",\r
- strerror(errno), \r
- inet_ntoa(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_addr));\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- goto bail;\r
- }\r
- if (dapls_modify_qp_state(ep_ptr->qp_handle,\r
- IBV_QPS_RTS, \r
- cm_ptr->msg.saddr.ib.qpn,\r
- cm_ptr->msg.saddr.ib.lid,\r
- NULL) != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT_USR: QPS_RTS ERR %s -> %s\n",\r
- strerror(errno), \r
- inet_ntoa(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_addr));\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
- goto bail;\r
- }\r
- dapl_os_unlock(&ep_ptr->header.lock);\r
-\r
- /* save remote address information */\r
- dapl_os_memcpy(&ep_ptr->remote_ia_address,\r
- &cm_ptr->msg.daddr.so,\r
- sizeof(union dcm_addr));\r
-\r
- /* send our QP info, IA address, pdata. Don't overwrite dst data */\r
- local.ver = htons(DCM_VER);\r
- local.op = htons(DCM_REP);\r
- local.saddr.ib.qpn = htonl(ep_ptr->qp_handle->qp_num);\r
- local.saddr.ib.qp_type = ep_ptr->qp_handle->qp_type;\r
- local.saddr.ib.lid = ia_ptr->hca_ptr->ib_trans.lid;\r
- dapl_os_memcpy(&local.saddr.ib.gid[0], \r
- &ia_ptr->hca_ptr->ib_trans.gid, 16);\r
- \r
- /* Get local address information from socket */\r
- sl = sizeof(local.daddr.so);\r
- getsockname(cm_ptr->socket, (struct sockaddr *)&local.daddr.so, &sl);\r
-\r
-#ifdef DAPL_DBG\r
- /* DBG: Active PID [0], PASSIVE PID [2] */\r
- *(uint16_t*)&cm_ptr->msg.resv[2] = htons((uint16_t)dapl_os_getpid()); \r
- dapl_os_memcpy(local.resv, cm_ptr->msg.resv, 4); \r
-#endif\r
-\r
- cm_ptr->ep = ep_ptr;\r
- cm_ptr->hca = ia_ptr->hca_ptr;\r
- cm_ptr->state = DCM_ACCEPTED;\r
-\r
- local.p_size = htons(p_size);\r
- iov[0].iov_base = (void *)&local;\r
- iov[0].iov_len = exp;\r
- \r
- if (p_size) {\r
- iov[1].iov_base = p_data;\r
- iov[1].iov_len = p_size;\r
- len = writev(cm_ptr->socket, iov, 2);\r
- } else \r
- len = writev(cm_ptr->socket, iov, 1);\r
- \r
- if (len != (p_size + exp)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT_USR: ERR %s, wcnt=%d -> %s\n",\r
- strerror(errno), len, \r
- inet_ntoa(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_addr));\r
- cm_ptr->ep = NULL;\r
- goto bail;\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " ACCEPT_USR: local lid=0x%x qpn=0x%x psz=%d\n",\r
- ntohs(local.saddr.ib.lid),\r
- ntohl(local.saddr.ib.qpn), ntohs(local.p_size));\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " ACCEPT_USR: SRC GID subnet %016llx id %016llx\n",\r
- (unsigned long long)\r
- htonll(*(uint64_t*)&local.saddr.ib.gid[0]),\r
- (unsigned long long)\r
- htonll(*(uint64_t*)&local.saddr.ib.gid[8]));\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " PASSIVE: accepted!\n");\r
- return DAT_SUCCESS;\r
-bail:\r
- dapls_ib_cm_free(cm_ptr, NULL);\r
- return ret;\r
-}\r
-\r
-/*\r
- * PASSIVE: read RTU from active peer, post CONN event\r
- */\r
-static void dapli_socket_accept_rtu(dp_ib_cm_handle_t cm_ptr)\r
-{\r
- int len;\r
- ib_cm_events_t event = IB_CME_CONNECTED;\r
-\r
- /* complete handshake after final QP state change, VER and OP */\r
- len = recv(cm_ptr->socket, (char *)&cm_ptr->msg, 4, 0);\r
- if (len != 4 || ntohs(cm_ptr->msg.op) != DCM_RTU) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT_RTU: rcv ERR, rcnt=%d op=%x\n",\r
- len, ntohs(cm_ptr->msg.op),\r
- inet_ntoa(((struct sockaddr_in *)\r
- &cm_ptr->msg.daddr.so)->sin_addr));\r
- event = IB_CME_DESTINATION_REJECT;\r
- goto bail;\r
- }\r
-\r
- /* save state and reference to EP, queue for disc event */\r
- cm_ptr->state = DCM_CONNECTED;\r
-\r
- /* final data exchange if remote QP state is good to go */\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " PASSIVE: connected!\n");\r
-\r
-#ifdef DAT_EXTENSIONS\r
-ud_bail:\r
- if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) {\r
- DAT_IB_EXTENSION_EVENT_DATA xevent;\r
-\r
- ib_pd_handle_t pd_handle = \r
- ((DAPL_PZ *)cm_ptr->ep->param.pz_handle)->pd_handle;\r
- \r
- if (event == IB_CME_CONNECTED) {\r
- cm_ptr->ah = dapls_create_ah(cm_ptr->hca, pd_handle,\r
- cm_ptr->ep->qp_handle,\r
- cm_ptr->msg.saddr.ib.lid, \r
- NULL);\r
- if (cm_ptr->ah) { \r
- /* post EVENT, modify_qp created ah */\r
- xevent.status = 0;\r
- xevent.type = DAT_IB_UD_PASSIVE_REMOTE_AH;\r
- xevent.remote_ah.ah = cm_ptr->ah;\r
- xevent.remote_ah.qpn = ntohl(cm_ptr->msg.saddr.ib.qpn);\r
- dapl_os_memcpy(&xevent.remote_ah.ia_addr,\r
- &cm_ptr->msg.daddr.so,\r
- sizeof(union dcm_addr));\r
- event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED;\r
- } else \r
- event = DAT_IB_UD_CONNECTION_ERROR_EVENT;\r
- } else \r
- event = DAT_IB_UD_CONNECTION_ERROR_EVENT;\r
-\r
- dapl_log(DAPL_DBG_TYPE_CM, \r
- " CONN_RTU: UD AH %p for lid 0x%x qpn 0x%x\n", \r
- cm_ptr->ah, ntohs(cm_ptr->msg.saddr.ib.lid),\r
- ntohl(cm_ptr->msg.saddr.ib.qpn));\r
-\r
- dapls_evd_post_connection_event_ext(\r
- (DAPL_EVD *) \r
- cm_ptr->ep->param.connect_evd_handle,\r
- event,\r
- (DAT_EP_HANDLE) cm_ptr->ep,\r
- (DAT_COUNT) ntohs(cm_ptr->msg.p_size),\r
- (DAT_PVOID *) cm_ptr->msg.p_data,\r
- (DAT_PVOID *) &xevent);\r
-\r
- /* done with socket, don't destroy cm_ptr, need pdata */\r
- closesocket(cm_ptr->socket);\r
- cm_ptr->socket = DAPL_INVALID_SOCKET;\r
- cm_ptr->state = DCM_RELEASED;\r
- } else \r
-#endif\r
- {\r
- cm_ptr->ep->cm_handle = cm_ptr; /* only RC, multi CR's on UD */\r
- dapls_cr_callback(cm_ptr, event, NULL, 0, cm_ptr->sp);\r
- }\r
- return;\r
- \r
-bail:\r
-#ifdef DAT_EXTENSIONS\r
- if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) \r
- goto ud_bail;\r
-#endif\r
- dapls_modify_qp_state(cm_ptr->ep->qp_handle, IBV_QPS_ERR, 0, 0, 0);\r
- dapls_ib_cm_free(cm_ptr, cm_ptr->ep);\r
- dapls_cr_callback(cm_ptr, event, NULL, 0, cm_ptr->sp);\r
-}\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\r
-dapls_ib_connect(IN DAT_EP_HANDLE ep_handle,\r
- IN DAT_IA_ADDRESS_PTR remote_ia_address,\r
- IN DAT_CONN_QUAL remote_conn_qual,\r
- IN DAT_COUNT private_data_size, IN void *private_data)\r
-{\r
- DAPL_EP *ep_ptr;\r
- ib_qp_handle_t qp_ptr;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " connect(ep_handle %p ....)\n", ep_handle);\r
-\r
- ep_ptr = (DAPL_EP *) ep_handle;\r
- qp_ptr = ep_ptr->qp_handle;\r
-\r
- return (dapli_socket_connect(ep_ptr, remote_ia_address,\r
- remote_conn_qual,\r
- private_data_size, private_data));\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
-DAT_RETURN\r
-dapls_ib_disconnect(IN DAPL_EP * ep_ptr, IN DAT_CLOSE_FLAGS close_flags)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- "dapls_ib_disconnect(ep_handle %p ....)\n", ep_ptr);\r
-\r
- /* Transition to error state to flush queue */\r
- dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0, 0, 0);\r
- \r
- if (ep_ptr->cm_handle == NULL ||\r
- ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED)\r
- return DAT_SUCCESS;\r
- else\r
- return (dapli_socket_disconnect(ep_ptr->cm_handle));\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. It is also called if dat_ep_connect\r
- * times out using the consumer supplied timeout value.\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
- /* NOTE: SCM will only initialize cm_handle with RC type\r
- * \r
- * For UD there can many in-flight CR's so you \r
- * cannot cleanup timed out CR's with EP reference \r
- * alone since they share the same EP. The common\r
- * code that handles connection timeout logic needs \r
- * updated for UD support.\r
- */\r
- if (ep_ptr->cm_handle)\r
- dapls_ib_cm_free(ep_ptr->cm_handle, ep_ptr);\r
-\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
- return (dapli_socket_listen(ia_ptr, ServiceID, sp_ptr));\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 cm_ptr = sp_ptr->cm_srvc_handle;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- "dapls_ib_remove_conn_listener(ia_ptr %p sp_ptr %p cm_ptr %p)\n",\r
- ia_ptr, sp_ptr, cm_ptr);\r
-\r
- /* close accepted socket, free cm_srvc_handle and return */\r
- if (cm_ptr != NULL) {\r
- /* cr_thread will free */\r
- dapl_os_lock(&cm_ptr->lock);\r
- cm_ptr->state = DCM_DESTROY;\r
- sp_ptr->cm_srvc_handle = NULL;\r
- send(cm_ptr->hca->ib_trans.scm[1], "w", sizeof "w", 0);\r
- dapl_os_unlock(&cm_ptr->lock);\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;\r
- DAPL_EP *ep_ptr;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- "dapls_ib_accept_connection(cr %p ep %p prd %p,%d)\n",\r
- cr_handle, ep_handle, p_data, p_size);\r
-\r
- cr_ptr = (DAPL_CR *) cr_handle;\r
- ep_ptr = (DAPL_EP *) ep_handle;\r
-\r
- /* allocate and attach a QP if necessary */\r
- if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {\r
- DAT_RETURN status;\r
- status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia,\r
- ep_ptr, ep_ptr);\r
- if (status != DAT_SUCCESS)\r
- return status;\r
- }\r
- return (dapli_socket_accept_usr(ep_ptr, cr_ptr, p_size, p_data));\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_ptr,\r
- IN int reason,\r
- IN DAT_COUNT psize, IN const DAT_PVOID pdata)\r
-{\r
- struct iovec iov[2];\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " reject(cm %p reason %x, pdata %p, psize %d)\n",\r
- cm_ptr, reason, pdata, psize);\r
-\r
- if (psize > DCM_MAX_PDATA_SIZE)\r
- return DAT_LENGTH_ERROR;\r
-\r
- dapl_os_lock(&cm_ptr->lock);\r
-\r
- /* write reject data to indicate reject */\r
- cm_ptr->msg.op = htons(DCM_REJ_USER);\r
- cm_ptr->msg.p_size = htons(psize);\r
- \r
- iov[0].iov_base = (void *)&cm_ptr->msg;\r
- iov[0].iov_len = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;\r
- if (psize) {\r
- iov[1].iov_base = pdata;\r
- iov[1].iov_len = psize;\r
- writev(cm_ptr->socket, iov, 2);\r
- } else {\r
- writev(cm_ptr->socket, iov, 1);\r
- }\r
-\r
- /* cr_thread will destroy CR */\r
- cm_ptr->state = DCM_DESTROY;\r
- send(cm_ptr->hca->ib_trans.scm[1], "w", sizeof "w", 0);\r
dapl_os_unlock(&cm_ptr->lock);\r
- return DAT_SUCCESS;\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,\r
- OUT DAT_SOCK_ADDR6 * remote_ia_address)\r
-{\r
- DAPL_HEADER *header;\r
- dp_ib_cm_handle_t ib_cm_handle;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- "dapls_ib_cm_remote_addr(dat_handle %p, ....)\n",\r
- dat_handle);\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
- dapl_os_memcpy(remote_ia_address,\r
- &ib_cm_handle->msg.daddr.so, sizeof(DAT_SOCK_ADDR6));\r
-\r
- return DAT_SUCCESS;\r
-}\r
-\r
-int dapls_ib_private_data_size(\r
- IN DAPL_HCA *hca_ptr)\r
-{\r
- return DCM_MAX_PDATA_SIZE;\r
-}\r
-\r
-/*\r
- * Map all socket CM event codes to the DAT equivelent.\r
- */\r
-#define DAPL_IB_EVENT_CNT 10\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 */ {IB_CME_CONNECTED, \r
- DAT_CONNECTION_EVENT_ESTABLISHED},\r
-/* 01 */ {IB_CME_DISCONNECTED, \r
- DAT_CONNECTION_EVENT_DISCONNECTED},\r
-/* 02 */ {IB_CME_DISCONNECTED_ON_LINK_DOWN,\r
- DAT_CONNECTION_EVENT_DISCONNECTED},\r
-/* 03 */ {IB_CME_CONNECTION_REQUEST_PENDING, \r
- DAT_CONNECTION_REQUEST_EVENT},\r
-/* 04 */ {IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA,\r
- DAT_CONNECTION_REQUEST_EVENT},\r
-/* 05 */ {IB_CME_DESTINATION_REJECT,\r
- DAT_CONNECTION_EVENT_NON_PEER_REJECTED},\r
-/* 06 */ {IB_CME_DESTINATION_REJECT_PRIVATE_DATA,\r
- DAT_CONNECTION_EVENT_PEER_REJECTED},\r
-/* 07 */ {IB_CME_DESTINATION_UNREACHABLE, \r
- DAT_CONNECTION_EVENT_UNREACHABLE},\r
-/* 08 */ {IB_CME_TOO_MANY_CONNECTION_REQUESTS,\r
- DAT_CONNECTION_EVENT_NON_PEER_REJECTED},\r
-/* 09 */ {IB_CME_LOCAL_FAILURE, \r
- DAT_CONNECTION_EVENT_BROKEN}\r
-};\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
- if (ib_cm_event > IB_CME_LOCAL_FAILURE)\r
- return (DAT_EVENT_NUMBER) 0;\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 translate(%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
-/* outbound/inbound CR processing thread to avoid blocking applications */\r
-void cr_thread(void *arg)\r
-{\r
- struct dapl_hca *hca_ptr = arg;\r
- dp_ib_cm_handle_t cr, next_cr;\r
- int opt, ret;\r
- socklen_t opt_len;\r
- char rbuf[2];\r
- struct dapl_fd_set *set;\r
- enum DAPL_FD_EVENTS event;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cr_thread: ENTER hca %p\n", hca_ptr);\r
- set = dapl_alloc_fd_set();\r
- if (!set)\r
- goto out;\r
-\r
- dapl_os_lock(&hca_ptr->ib_trans.lock);\r
- hca_ptr->ib_trans.cr_state = IB_THREAD_RUN;\r
-\r
- while (1) {\r
- dapl_fd_zero(set);\r
- dapl_fd_set(hca_ptr->ib_trans.scm[0], set, DAPL_FD_READ);\r
-\r
- if (!dapl_llist_is_empty(&hca_ptr->ib_trans.list))\r
- next_cr = dapl_llist_peek_head(&hca_ptr->ib_trans.list);\r
- else\r
- next_cr = NULL;\r
-\r
- while (next_cr) {\r
- cr = next_cr;\r
- next_cr = dapl_llist_next_entry(&hca_ptr->ib_trans.list,\r
- (DAPL_LLIST_ENTRY *) &\r
- cr->entry);\r
- dapl_os_lock(&cr->lock);\r
- if (cr->state == DCM_DESTROY\r
- || hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) {\r
- dapl_os_unlock(&cr->lock);\r
- dapl_llist_remove_entry(&hca_ptr->ib_trans.list,\r
- (DAPL_LLIST_ENTRY *) &\r
- cr->entry);\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, \r
- " CR FREE: %p ep=%p st=%d sock=%d\n", \r
- cr, cr->ep, cr->state, cr->socket);\r
-\r
- if (cr->socket != DAPL_INVALID_SOCKET) {\r
- shutdown(cr->socket, SHUT_RDWR);\r
- closesocket(cr->socket);\r
- }\r
- dapl_os_free(cr, sizeof(*cr));\r
- continue;\r
- }\r
- if (cr->socket == DAPL_INVALID_SOCKET) {\r
- dapl_os_unlock(&cr->lock);\r
- continue;\r
- }\r
-\r
- event = (cr->state == DCM_CONN_PENDING) ?\r
- DAPL_FD_WRITE : DAPL_FD_READ;\r
-\r
- if (dapl_fd_set(cr->socket, set, event)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " cr_thread: DESTROY CR st=%d fd %d"\r
- " -> %s\n", cr->state, cr->socket,\r
- inet_ntoa(((struct sockaddr_in *)\r
- &cr->msg.daddr.so)->sin_addr));\r
- dapl_os_unlock(&cr->lock);\r
- dapl_os_lock_destroy(&cr->lock);\r
- dapls_ib_cm_free(cr, cr->ep);\r
- continue;\r
- }\r
- dapl_os_unlock(&cr->lock);\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " poll cr=%p, sck=%d\n", cr, cr->socket);\r
- dapl_os_unlock(&hca_ptr->ib_trans.lock);\r
-\r
- ret = dapl_poll(cr->socket, event);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " poll ret=0x%x cr->state=%d sck=%d\n",\r
- ret, cr->state, cr->socket);\r
-\r
- /* data on listen, qp exchange, and on disc req */\r
- if ((ret == DAPL_FD_READ) || \r
- (cr->state != DCM_CONN_PENDING &&\r
- ret == DAPL_FD_ERROR)) {\r
- if (cr->socket != DAPL_INVALID_SOCKET) {\r
- switch (cr->state) {\r
- case DCM_LISTEN:\r
- dapli_socket_accept(cr);\r
- break;\r
- case DCM_ACCEPTING:\r
- dapli_socket_accept_data(cr);\r
- break;\r
- case DCM_ACCEPTED:\r
- dapli_socket_accept_rtu(cr);\r
- break;\r
- case DCM_REP_PENDING:\r
- dapli_socket_connect_rtu(cr);\r
- break;\r
- case DCM_CONNECTED:\r
- dapli_socket_disconnect(cr);\r
- break;\r
- default:\r
- break;\r
- }\r
- }\r
- /* ASYNC connections, writable, readable, error; check status */\r
- } else if (ret == DAPL_FD_WRITE ||\r
- (cr->state == DCM_CONN_PENDING && \r
- ret == DAPL_FD_ERROR)) {\r
-\r
- if (ret == DAPL_FD_ERROR)\r
- dapl_log(DAPL_DBG_TYPE_ERR, " CONN_PENDING - FD_ERROR\n");\r
- \r
- opt = 0;\r
- opt_len = sizeof(opt);\r
- ret = getsockopt(cr->socket, SOL_SOCKET,\r
- SO_ERROR, (char *)&opt,\r
- &opt_len);\r
- if (!ret && !opt)\r
- dapli_socket_connected(cr, opt);\r
- else\r
- dapli_socket_connected(cr, opt ? opt : dapl_socket_errno());\r
- } \r
- dapl_os_lock(&hca_ptr->ib_trans.lock);\r
- }\r
-\r
- /* set to exit and all resources destroyed */\r
- if ((hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) &&\r
- (dapl_llist_is_empty(&hca_ptr->ib_trans.list)))\r
- break;\r
-\r
- dapl_os_unlock(&hca_ptr->ib_trans.lock);\r
- dapl_select(set);\r
-\r
- /* if pipe used to wakeup, consume */\r
- while (dapl_poll(hca_ptr->ib_trans.scm[0], \r
- DAPL_FD_READ) == DAPL_FD_READ) {\r
- if (recv(hca_ptr->ib_trans.scm[0], rbuf, 2, 0) == -1)\r
- dapl_log(DAPL_DBG_TYPE_CM,\r
- " cr_thread: read pipe error = %s\n",\r
- strerror(errno));\r
- }\r
- dapl_os_lock(&hca_ptr->ib_trans.lock);\r
- \r
- /* set to exit and all resources destroyed */\r
- if ((hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) &&\r
- (dapl_llist_is_empty(&hca_ptr->ib_trans.list)))\r
- break;\r
- }\r
-\r
- dapl_os_unlock(&hca_ptr->ib_trans.lock);\r
- dapl_os_free(set, sizeof(struct dapl_fd_set));\r
-out:\r
- hca_ptr->ib_trans.cr_state = IB_THREAD_EXIT;\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cr_thread(hca %p) exit\n", hca_ptr);\r
-}\r
-\r
-\r
-#ifdef DAPL_COUNTERS\r
-/* Debug aid: List all Connections in process and state */\r
-void dapls_print_cm_list(IN DAPL_IA *ia_ptr)\r
-{\r
- /* Print in process CR's for this IA, if debug type set */\r
- int i = 0;\r
- dp_ib_cm_handle_t cr, next_cr;\r
-\r
- dapl_os_lock(&ia_ptr->hca_ptr->ib_trans.lock);\r
- if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)\r
- &ia_ptr->hca_ptr->ib_trans.list))\r
- next_cr = dapl_llist_peek_head((DAPL_LLIST_HEAD*)\r
- &ia_ptr->hca_ptr->ib_trans.list);\r
- else\r
- next_cr = NULL;\r
-\r
- printf("\n DAPL IA CONNECTIONS IN PROCESS:\n");\r
- while (next_cr) {\r
- cr = next_cr;\r
- next_cr = dapl_llist_next_entry((DAPL_LLIST_HEAD*)\r
- &ia_ptr->hca_ptr->ib_trans.list,\r
- (DAPL_LLIST_ENTRY*)&cr->entry);\r
-\r
- printf( " CONN[%d]: sp %p ep %p sock %d %s %s %s %s %s %s PORT L-%x R-%x PID L-%x R-%x\n",\r
- i, cr->sp, cr->ep, cr->socket,\r
- cr->msg.saddr.ib.qp_type == IBV_QPT_RC ? "RC" : "UD",\r
- dapl_cm_state_str(cr->state), dapl_cm_op_str(ntohs(cr->msg.op)),\r
- ntohs(cr->msg.op) == DCM_REQ ? /* local address */\r
- inet_ntoa(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_addr) :\r
- inet_ntoa(((struct sockaddr_in *)&cr->addr)->sin_addr),\r
- cr->sp ? "<-" : "->",\r
- ntohs(cr->msg.op) == DCM_REQ ? /* remote address */\r
- inet_ntoa(((struct sockaddr_in *)&cr->addr)->sin_addr) :\r
- inet_ntoa(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_addr),\r
-\r
- ntohs(cr->msg.op) == DCM_REQ ? /* local port */\r
- ntohs(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_port) :\r
- ntohs(((struct sockaddr_in *)&cr->addr)->sin_port),\r
-\r
- ntohs(cr->msg.op) == DCM_REQ ? /* remote port */\r
- ntohs(((struct sockaddr_in *)&cr->addr)->sin_port) :\r
- ntohs(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_port),\r
-\r
- cr->sp ? ntohs(*(uint16_t*)&cr->msg.resv[2]) : ntohs(*(uint16_t*)&cr->msg.resv[0]),\r
- cr->sp ? ntohs(*(uint16_t*)&cr->msg.resv[0]) : ntohs(*(uint16_t*)&cr->msg.resv[2]));\r
-\r
- i++;\r
- }\r
- printf("\n");\r
- dapl_os_unlock(&ia_ptr->hca_ptr->ib_trans.lock);\r
-}\r
-#endif\r
+ dapli_cm_dealloc(cm_ptr);\r
+}
+
+static dp_ib_cm_handle_t dapli_cm_alloc(DAPL_EP *ep_ptr)
+{
+ dp_ib_cm_handle_t cm_ptr;
+
+ /* Allocate CM, init lock, and initialize */
+ if ((cm_ptr = dapl_os_alloc(sizeof(*cm_ptr))) == NULL)
+ return NULL;
+
+ (void)dapl_os_memzero(cm_ptr, sizeof(*cm_ptr));
+ if (dapl_os_lock_init(&cm_ptr->lock))
+ goto bail;
+
+ if (dapl_os_wait_object_init(&cm_ptr->event)) {
+ dapl_os_lock_destroy(&cm_ptr->lock);
+ goto bail;
+ }
+ dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm_ptr->list_entry);
+ dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm_ptr->local_entry);
+
+ cm_ptr->msg.ver = htons(DCM_VER);
+ cm_ptr->socket = DAPL_INVALID_SOCKET;
+ dapls_cm_acquire(cm_ptr);
+
+ /* Link EP and CM */
+ if (ep_ptr != NULL) {
+ dapl_ep_link_cm(ep_ptr, cm_ptr); /* ref++ */
+ cm_ptr->ep = ep_ptr;
+ cm_ptr->hca = ((DAPL_IA *)ep_ptr->param.ia_handle)->hca_ptr;
+ }
+ return cm_ptr;
+bail:
+ dapl_os_free(cm_ptr, sizeof(*cm_ptr));
+ return NULL;
+}
+
+/* queue socket for processing CM work */
+static void dapli_cm_queue(dp_ib_cm_handle_t cm_ptr)
+{
+ /* add to work queue for cr thread processing */
+ dapl_os_lock(&cm_ptr->hca->ib_trans.lock);
+ dapls_cm_acquire(cm_ptr);
+ dapl_llist_add_tail(&cm_ptr->hca->ib_trans.list,
+ (DAPL_LLIST_ENTRY *)&cm_ptr->local_entry, cm_ptr);
+ dapl_os_unlock(&cm_ptr->hca->ib_trans.lock);
+ dapli_cm_thread_signal(cm_ptr);
+}
+
+/* called with local LIST lock */
+static void dapli_cm_dequeue(dp_ib_cm_handle_t cm_ptr)
+{
+ /* Remove from work queue, cr thread processing */
+ dapl_llist_remove_entry(&cm_ptr->hca->ib_trans.list,
+ (DAPL_LLIST_ENTRY *)&cm_ptr->local_entry);
+ dapls_cm_release(cm_ptr);
+}
+
+/* BLOCKING: called from dapl_ep_free, EP link will be last ref */
+void dapls_cm_free(dp_ib_cm_handle_t cm_ptr)
+{
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " cm_free: cm %p %s ep %p refs=%d\n",
+ cm_ptr, dapl_cm_state_str(cm_ptr->state),
+ cm_ptr->ep, cm_ptr->ref_count);
+
+ /* free from internal workq, wait until EP is last ref */
+ dapl_os_lock(&cm_ptr->lock);
+ cm_ptr->state = DCM_FREE;
+ while (cm_ptr->ref_count != 1) {
+ dapl_os_unlock(&cm_ptr->lock);
+ dapl_os_sleep_usec(10000);
+ dapl_os_lock(&cm_ptr->lock);
+ }
+ dapl_os_unlock(&cm_ptr->lock);
+
+ /* unlink, dequeue from EP. Final ref so release will destroy */
+ dapl_ep_unlink_cm(cm_ptr->ep, cm_ptr);
+}
+
+/*
+ * ACTIVE/PASSIVE: called from CR thread or consumer via ep_disconnect
+ * or from ep_free.
+ */
+DAT_RETURN dapli_socket_disconnect(dp_ib_cm_handle_t cm_ptr)
+{
+ DAT_UINT32 disc_data = htonl(0xdead);
+
+ dapl_os_lock(&cm_ptr->lock);
+ if (cm_ptr->state != DCM_CONNECTED ||
+ cm_ptr->state == DCM_DISCONNECTED) {
+ dapl_os_unlock(&cm_ptr->lock);
+ return DAT_SUCCESS;
+ }
+ cm_ptr->state = DCM_DISCONNECTED;
+ dapl_os_unlock(&cm_ptr->lock);
+
+ /* send disc date, close socket, schedule destroy */
+ dapls_modify_qp_state(cm_ptr->ep->qp_handle, IBV_QPS_ERR, 0,0,0);
+ send(cm_ptr->socket, (char *)&disc_data, sizeof(disc_data), 0);
+
+ /* disconnect events for RC's only */
+ if (cm_ptr->ep->param.ep_attr.service_type == DAT_SERVICE_TYPE_RC) {
+ if (cm_ptr->ep->cr_ptr) {
+ dapls_cr_callback(cm_ptr,
+ IB_CME_DISCONNECTED,
+ NULL, 0, cm_ptr->sp);
+ } else {
+ dapl_evd_connection_callback(cm_ptr,
+ IB_CME_DISCONNECTED,
+ NULL, 0, cm_ptr->ep);
+ }
+ }
+
+ /* release from workq */
+ dapli_cm_free(cm_ptr);
+
+ /* scheduled destroy via disconnect clean in callback */
+ return DAT_SUCCESS;
+}
+
+/*
+ * ACTIVE: socket connected, send QP information to peer
+ */
+static void dapli_socket_connected(dp_ib_cm_handle_t cm_ptr, int err)
+{
+ int len, exp;
+ struct iovec iov[2];
+ struct dapl_ep *ep_ptr = cm_ptr->ep;
+
+ if (err) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CONN_PENDING: %s ERR %s -> %s %d\n",
+ err == -1 ? "POLL" : "SOCKOPT",
+ err == -1 ? strerror(errno) : strerror(err),
+ inet_ntoa(((struct sockaddr_in *)
+ &cm_ptr->addr)->sin_addr),
+ ntohs(((struct sockaddr_in *)
+ &cm_ptr->addr)->sin_port));
+ goto bail;
+ }
+
+ cm_ptr->state = DCM_REP_PENDING;
+
+ /* send qp info and pdata to remote peer */
+ exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;
+ iov[0].iov_base = (void *)&cm_ptr->msg;
+ iov[0].iov_len = exp;
+ if (cm_ptr->msg.p_size) {
+ iov[1].iov_base = cm_ptr->msg.p_data;
+ iov[1].iov_len = ntohs(cm_ptr->msg.p_size);
+ len = writev(cm_ptr->socket, iov, 2);
+ } else {
+ len = writev(cm_ptr->socket, iov, 1);
+ }
+
+ if (len != (exp + ntohs(cm_ptr->msg.p_size))) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CONN_PENDING len ERR %s, wcnt=%d(%d) -> %s\n",
+ strerror(errno), len,
+ exp + ntohs(cm_ptr->msg.p_size),
+ inet_ntoa(((struct sockaddr_in *)
+ ep_ptr->param.
+ remote_ia_address_ptr)->sin_addr));
+ goto bail;
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " CONN_PENDING: sending SRC lid=0x%x,"
+ " qpn=0x%x, psize=%d\n",
+ ntohs(cm_ptr->msg.saddr.ib.lid),
+ ntohl(cm_ptr->msg.saddr.ib.qpn),
+ ntohs(cm_ptr->msg.p_size));
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " CONN_PENDING: SRC GID subnet %016llx id %016llx\n",
+ (unsigned long long)
+ htonll(*(uint64_t*)&cm_ptr->msg.saddr.ib.gid[0]),
+ (unsigned long long)
+ htonll(*(uint64_t*)&cm_ptr->msg.saddr.ib.gid[8]));
+ return;
+
+bail:
+ /* mark CM object for cleanup */
+ dapli_cm_free(cm_ptr);
+ dapl_evd_connection_callback(NULL, IB_CME_LOCAL_FAILURE, NULL, 0, ep_ptr);
+}
+
+/*
+ * ACTIVE: Create socket, connect, defer exchange QP information to CR thread
+ * to avoid blocking.
+ */
+static DAT_RETURN
+dapli_socket_connect(DAPL_EP * ep_ptr,
+ DAT_IA_ADDRESS_PTR r_addr,
+ DAT_CONN_QUAL r_qual, DAT_COUNT p_size, DAT_PVOID p_data)
+{
+ dp_ib_cm_handle_t cm_ptr;
+ int ret;
+ socklen_t sl;
+ DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;
+ DAT_RETURN dat_ret = DAT_INSUFFICIENT_RESOURCES;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect: r_qual %d p_size=%d\n",
+ r_qual, p_size);
+
+ cm_ptr = dapli_cm_alloc(ep_ptr);
+ if (cm_ptr == NULL)
+ return dat_ret;
+
+ /* create, connect, sockopt, and exchange QP information */
+ if ((cm_ptr->socket =
+ socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == DAPL_INVALID_SOCKET) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " connect: socket create ERR %s\n", strerror(errno));
+ goto bail;
+ }
+
+ ret = dapl_config_socket(cm_ptr->socket);
+ if (ret < 0) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " connect: config socket %d ERR %d %s\n",
+ cm_ptr->socket, ret, strerror(dapl_socket_errno()));
+ dat_ret = DAT_INTERNAL_ERROR;
+ goto bail;
+ }
+
+ /* save remote address */
+ dapl_os_memcpy(&cm_ptr->addr, r_addr, sizeof(*r_addr));
+
+#ifdef DAPL_DBG
+ /* DBG: Active PID [0], PASSIVE PID [2]*/
+ *(uint16_t*)&cm_ptr->msg.resv[0] = htons((uint16_t)dapl_os_getpid());
+ *(uint16_t*)&cm_ptr->msg.resv[2] = ((struct sockaddr_in *)&cm_ptr->addr)->sin_port;
+#endif
+ ((struct sockaddr_in *)&cm_ptr->addr)->sin_port = htons(r_qual + 1000);
+ ret = dapl_connect_socket(cm_ptr->socket, (struct sockaddr *)&cm_ptr->addr,
+ sizeof(cm_ptr->addr));
+ if (ret && ret != EAGAIN) {
+ dat_ret = DAT_INVALID_ADDRESS;
+ goto bail;
+ }
+
+ /* REQ: QP info in msg.saddr, IA address in msg.daddr, and pdata */
+ cm_ptr->hca = ia_ptr->hca_ptr;
+ cm_ptr->msg.op = ntohs(DCM_REQ);
+ cm_ptr->msg.saddr.ib.qpn = htonl(ep_ptr->qp_handle->qp_num);
+ cm_ptr->msg.saddr.ib.qp_type = ep_ptr->qp_handle->qp_type;
+ cm_ptr->msg.saddr.ib.lid = ia_ptr->hca_ptr->ib_trans.lid;
+ dapl_os_memcpy(&cm_ptr->msg.saddr.ib.gid[0],
+ &ia_ptr->hca_ptr->ib_trans.gid, 16);
+
+ /* get local address information from socket */
+ sl = sizeof(cm_ptr->msg.daddr.so);
+ if (getsockname(cm_ptr->socket, (struct sockaddr *)&cm_ptr->msg.daddr.so, &sl)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " connect getsockname ERROR: %s -> %s r_qual %d\n",
+ strerror(errno),
+ inet_ntoa(((struct sockaddr_in *)r_addr)->sin_addr),
+ (unsigned int)r_qual);;
+ }
+
+ if (p_size) {
+ cm_ptr->msg.p_size = htons(p_size);
+ dapl_os_memcpy(cm_ptr->msg.p_data, p_data, p_size);
+ }
+
+ /* connected or pending, either way results via async event */
+ if (ret == 0)
+ dapli_socket_connected(cm_ptr, 0);
+ else
+ cm_ptr->state = DCM_CONN_PENDING;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect: p_data=%p %p\n",
+ cm_ptr->msg.p_data, cm_ptr->msg.p_data);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " connect: %s r_qual %d pending, p_sz=%d, %d %d ...\n",
+ inet_ntoa(((struct sockaddr_in *)&cm_ptr->addr)->sin_addr),
+ (unsigned int)r_qual, ntohs(cm_ptr->msg.p_size),
+ cm_ptr->msg.p_data[0], cm_ptr->msg.p_data[1]);
+
+ /* queue up on work thread */
+ dapli_cm_queue(cm_ptr);
+ return DAT_SUCCESS;
+bail:
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " connect ERROR: %s -> %s r_qual %d\n",
+ strerror(errno),
+ inet_ntoa(((struct sockaddr_in *)r_addr)->sin_addr),
+ (unsigned int)r_qual);
+
+ /* Never queued, destroy */
+ dapls_cm_release(cm_ptr);
+ return dat_ret;
+}
+
+/*
+ * ACTIVE: exchange QP information, called from CR thread
+ */
+static void dapli_socket_connect_rtu(dp_ib_cm_handle_t cm_ptr)
+{
+ DAPL_EP *ep_ptr = cm_ptr->ep;
+ int len, exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;
+ ib_cm_events_t event = IB_CME_LOCAL_FAILURE;
+ socklen_t sl;
+
+ /* read DST information into cm_ptr, overwrite SRC info */
+ dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect_rtu: recv peer QP data\n");
+
+ len = recv(cm_ptr->socket, (char *)&cm_ptr->msg, exp, 0);
+ if (len != exp || ntohs(cm_ptr->msg.ver) != DCM_VER) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " CONN_RTU read: sk %d ERR %s, rcnt=%d, v=%d -> %s PORT L-%x R-%x PID L-%x R-%x\n",
+ cm_ptr->socket, strerror(errno), len, ntohs(cm_ptr->msg.ver),
+ inet_ntoa(((struct sockaddr_in *)&cm_ptr->addr)->sin_addr),
+ ntohs(((struct sockaddr_in *)&cm_ptr->msg.daddr.so)->sin_port),
+ ntohs(((struct sockaddr_in *)&cm_ptr->addr)->sin_port),
+ ntohs(*(uint16_t*)&cm_ptr->msg.resv[0]),
+ ntohs(*(uint16_t*)&cm_ptr->msg.resv[2]));
+
+ /* Retry; corner case where server tcp stack resets under load */
+ if (dapl_socket_errno() == ECONNRESET) {
+ closesocket(cm_ptr->socket);
+ cm_ptr->socket = DAPL_INVALID_SOCKET;
+ dapli_socket_connect(cm_ptr->ep, (DAT_IA_ADDRESS_PTR)&cm_ptr->addr,
+ ntohs(((struct sockaddr_in *)&cm_ptr->addr)->sin_port) - 1000,
+ ntohs(cm_ptr->msg.p_size), &cm_ptr->msg.p_data);
+ dapl_ep_unlink_cm(cm_ptr->ep, cm_ptr);
+ dapli_cm_free(cm_ptr);
+ return;
+ }
+ goto bail;
+ }
+
+ /* keep the QP, address info in network order */
+
+ /* save remote address information, in msg.daddr */
+ dapl_os_memcpy(&ep_ptr->remote_ia_address,
+ &cm_ptr->msg.daddr.so,
+ sizeof(union dcm_addr));
+
+ /* save local address information from socket */
+ sl = sizeof(cm_ptr->addr);
+ getsockname(cm_ptr->socket,(struct sockaddr *)&cm_ptr->addr, &sl);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " CONN_RTU: DST %s %d lid=0x%x,"
+ " qpn=0x%x, qp_type=%d, psize=%d\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_addr),
+ ntohs(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_port),
+ ntohs(cm_ptr->msg.saddr.ib.lid),
+ ntohl(cm_ptr->msg.saddr.ib.qpn),
+ cm_ptr->msg.saddr.ib.qp_type,
+ ntohs(cm_ptr->msg.p_size));
+
+ /* validate private data size before reading */
+ if (ntohs(cm_ptr->msg.p_size) > DCM_MAX_PDATA_SIZE) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CONN_RTU read: psize (%d) wrong -> %s\n",
+ ntohs(cm_ptr->msg.p_size),
+ inet_ntoa(((struct sockaddr_in *)
+ ep_ptr->param.
+ remote_ia_address_ptr)->sin_addr));
+ goto bail;
+ }
+
+ /* read private data into cm_handle if any present */
+ dapl_dbg_log(DAPL_DBG_TYPE_EP," CONN_RTU: read private data\n");
+ exp = ntohs(cm_ptr->msg.p_size);
+ if (exp) {
+ len = recv(cm_ptr->socket, cm_ptr->msg.p_data, exp, 0);
+ if (len != exp) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CONN_RTU read pdata: ERR %s, rcnt=%d -> %s\n",
+ strerror(errno), len,
+ inet_ntoa(((struct sockaddr_in *)
+ ep_ptr->param.
+ remote_ia_address_ptr)->sin_addr));
+ goto bail;
+ }
+ }
+
+ /* check for consumer or protocol stack reject */
+ if (ntohs(cm_ptr->msg.op) == DCM_REP)
+ event = IB_CME_CONNECTED;
+ else if (ntohs(cm_ptr->msg.op) == DCM_REJ_USER)
+ event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA;
+ else
+ event = IB_CME_DESTINATION_REJECT;
+
+ if (event != IB_CME_CONNECTED) {
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " CONN_RTU: reject from %s %x\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_addr),
+ ntohs(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_port));
+ goto bail;
+ }
+
+ /* modify QP to RTR and then to RTS with remote info */
+ if (dapls_modify_qp_state(ep_ptr->qp_handle,
+ IBV_QPS_RTR,
+ cm_ptr->msg.saddr.ib.qpn,
+ cm_ptr->msg.saddr.ib.lid,
+ (ib_gid_handle_t)cm_ptr->msg.saddr.ib.gid) != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CONN_RTU: QPS_RTR ERR %s (%d,%d,%x,%x,%x) -> %s %x\n",
+ strerror(errno), ep_ptr->qp_handle->qp_type,
+ ep_ptr->qp_state, ep_ptr->qp_handle->qp_num,
+ ntohl(cm_ptr->msg.saddr.ib.qpn),
+ ntohs(cm_ptr->msg.saddr.ib.lid),
+ inet_ntoa(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_addr),
+ ntohs(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_port));
+ goto bail;
+ }
+ if (dapls_modify_qp_state(ep_ptr->qp_handle,
+ IBV_QPS_RTS,
+ cm_ptr->msg.saddr.ib.qpn,
+ cm_ptr->msg.saddr.ib.lid,
+ NULL) != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CONN_RTU: QPS_RTS ERR %s (%d,%d,%x,%x,%x) -> %s %x\n",
+ strerror(errno), ep_ptr->qp_handle->qp_type,
+ ep_ptr->qp_state, ep_ptr->qp_handle->qp_num,
+ ntohl(cm_ptr->msg.saddr.ib.qpn),
+ ntohs(cm_ptr->msg.saddr.ib.lid),
+ inet_ntoa(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_addr),
+ ntohs(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_port));
+ goto bail;
+ }
+ dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect_rtu: send RTU\n");
+
+ /* complete handshake after final QP state change, Just ver+op */
+ cm_ptr->state = DCM_CONNECTED;
+ cm_ptr->msg.op = ntohs(DCM_RTU);
+ if (send(cm_ptr->socket, (char *)&cm_ptr->msg, 4, 0) == -1) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CONN_RTU: write error = %s\n", strerror(errno));
+ goto bail;
+ }
+ /* post the event with private data */
+ event = IB_CME_CONNECTED;
+ dapl_dbg_log(DAPL_DBG_TYPE_EP, " ACTIVE: connected!\n");
+
+#ifdef DAT_EXTENSIONS
+ud_bail:
+ if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) {
+ DAT_IB_EXTENSION_EVENT_DATA xevent;
+ ib_pd_handle_t pd_handle =
+ ((DAPL_PZ *)ep_ptr->param.pz_handle)->pd_handle;
+
+ if (event == IB_CME_CONNECTED) {
+ cm_ptr->ah = dapls_create_ah(cm_ptr->hca, pd_handle,
+ ep_ptr->qp_handle,
+ cm_ptr->msg.saddr.ib.lid,
+ NULL);
+ if (cm_ptr->ah) {
+ /* post UD extended EVENT */
+ xevent.status = 0;
+ xevent.type = DAT_IB_UD_REMOTE_AH;
+ xevent.remote_ah.ah = cm_ptr->ah;
+ xevent.remote_ah.qpn = ntohl(cm_ptr->msg.saddr.ib.qpn);
+ dapl_os_memcpy(&xevent.remote_ah.ia_addr,
+ &ep_ptr->remote_ia_address,
+ sizeof(union dcm_addr));
+ event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED;
+
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " CONN_RTU: UD AH %p for lid 0x%x"
+ " qpn 0x%x\n",
+ cm_ptr->ah,
+ ntohs(cm_ptr->msg.saddr.ib.lid),
+ ntohl(cm_ptr->msg.saddr.ib.qpn));
+
+ } else
+ event = DAT_IB_UD_CONNECTION_ERROR_EVENT;
+
+ } else if (event == IB_CME_LOCAL_FAILURE) {
+ event = DAT_IB_UD_CONNECTION_ERROR_EVENT;
+ } else
+ event = DAT_IB_UD_CONNECTION_REJECT_EVENT;
+
+ dapls_evd_post_connection_event_ext(
+ (DAPL_EVD *) ep_ptr->param.connect_evd_handle,
+ event,
+ (DAT_EP_HANDLE) ep_ptr,
+ (DAT_COUNT) exp,
+ (DAT_PVOID *) cm_ptr->msg.p_data,
+ (DAT_PVOID *) &xevent);
+
+ /* cleanup and release from local list */
+ dapli_cm_free(cm_ptr);
+
+ } else
+#endif
+ {
+ dapl_evd_connection_callback(cm_ptr, event, cm_ptr->msg.p_data,
+ DCM_MAX_PDATA_SIZE, ep_ptr);
+ }
+ return;
+
+bail:
+
+#ifdef DAT_EXTENSIONS
+ if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD)
+ goto ud_bail;
+#endif
+ /* close socket, and post error event */
+ cm_ptr->state = DCM_REJECTED;
+ dapl_evd_connection_callback(NULL, event, cm_ptr->msg.p_data,
+ DCM_MAX_PDATA_SIZE, ep_ptr);
+ dapli_cm_free(cm_ptr);
+}
+
+/*
+ * PASSIVE: Create socket, listen, accept, exchange QP information
+ */
+DAT_RETURN
+dapli_socket_listen(DAPL_IA * ia_ptr, DAT_CONN_QUAL serviceID, DAPL_SP * sp_ptr)
+{
+ struct sockaddr_in addr;
+ ib_cm_srvc_handle_t cm_ptr = NULL;
+ DAT_RETURN dat_status = DAT_SUCCESS;
+ int opt = 1;\r
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " setup listen(ia_ptr %p ServiceID %d sp_ptr %p)\n",
+ ia_ptr, serviceID, sp_ptr);
+
+ cm_ptr = dapli_cm_alloc(NULL);
+ if (cm_ptr == NULL)
+ return DAT_INSUFFICIENT_RESOURCES;
+
+ cm_ptr->sp = sp_ptr;
+ cm_ptr->hca = ia_ptr->hca_ptr;
+
+ /* bind, listen, set sockopt, accept, exchange data */
+ if ((cm_ptr->socket =
+ socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == DAPL_INVALID_SOCKET) {
+ dapl_log(DAPL_DBG_TYPE_ERR, " ERR: listen socket create: %s\n",
+ strerror(errno));
+ dat_status = DAT_INSUFFICIENT_RESOURCES;
+ goto bail;
+ }
+
+ setsockopt(cm_ptr->socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));\r
+ addr.sin_port = htons(serviceID + 1000);
+ addr.sin_family = AF_INET;
+ addr.sin_addr = ((struct sockaddr_in *) &ia_ptr->hca_ptr->hca_address)->sin_addr;
+
+ if ((bind(cm_ptr->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ || (listen(cm_ptr->socket, 128) < 0)) {
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " listen: ERROR %s on port %d\n",
+ strerror(errno), serviceID + 1000);
+ if (dapl_socket_errno() == EADDRINUSE)
+ dat_status = DAT_CONN_QUAL_IN_USE;
+ else
+ dat_status = DAT_CONN_QUAL_UNAVAILABLE;
+ goto bail;
+ }
+
+ /* set cm_handle for this service point, save listen socket */
+ sp_ptr->cm_srvc_handle = cm_ptr;
+ dapl_os_memcpy(&cm_ptr->addr, &addr, sizeof(addr));
+
+ /* queue up listen socket to process inbound CR's */
+ cm_ptr->state = DCM_LISTEN;
+ dapli_cm_queue(cm_ptr);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " setup listen: port %d cr %p s_fd %d\n",
+ serviceID + 1000, cm_ptr, cm_ptr->socket);
+
+ return dat_status;
+bail:
+ /* Never queued, destroy here */
+ dapls_cm_release(cm_ptr);
+ return dat_status;
+}
+
+/*
+ * PASSIVE: accept socket
+ */
+static void dapli_socket_accept(ib_cm_srvc_handle_t cm_ptr)
+{
+ dp_ib_cm_handle_t acm_ptr;
+ int ret, len, opt = 1;
+ socklen_t sl;
+
+ /*
+ * Accept all CR's on this port to avoid half-connection (SYN_RCV)
+ * stalls with many to one connection storms
+ */
+ do {
+ /* Allocate accept CM and initialize */
+ if ((acm_ptr = dapli_cm_alloc(NULL)) == NULL)
+ return;
+
+ acm_ptr->sp = cm_ptr->sp;
+ acm_ptr->hca = cm_ptr->hca;
+
+ len = sizeof(union dcm_addr);
+ acm_ptr->socket = accept(cm_ptr->socket,
+ (struct sockaddr *)
+ &acm_ptr->msg.daddr.so,
+ (socklen_t *) &len);
+ if (acm_ptr->socket == DAPL_INVALID_SOCKET) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT: ERR %s on FD %d l_cr %p\n",
+ strerror(errno), cm_ptr->socket, cm_ptr);
+ dapls_cm_release(acm_ptr);
+ return;
+ }
+ dapl_dbg_log(DAPL_DBG_TYPE_CM, " accepting from %s %x\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &acm_ptr->msg.daddr.so)->sin_addr),
+ ntohs(((struct sockaddr_in *)
+ &acm_ptr->msg.daddr.so)->sin_port));
+
+ /* no delay for small packets */
+ ret = setsockopt(acm_ptr->socket, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&opt, sizeof(opt));
+ if (ret)
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT: NODELAY setsockopt: 0x%x 0x%x %s\n",
+ ret, dapl_socket_errno(), strerror(dapl_socket_errno()));
+
+ /* get local address information from socket */
+ sl = sizeof(acm_ptr->addr);
+ getsockname(acm_ptr->socket, (struct sockaddr *)&acm_ptr->addr, &sl);
+ acm_ptr->state = DCM_ACCEPTING;
+ dapli_cm_queue(acm_ptr);
+
+ } while (dapl_poll(cm_ptr->socket, DAPL_FD_READ) == DAPL_FD_READ);
+}
+
+/*
+ * PASSIVE: receive peer QP information, private data, post cr_event
+ */
+static void dapli_socket_accept_data(ib_cm_srvc_handle_t acm_ptr)
+{
+ int len, exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;
+ void *p_data = NULL;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP, " socket accepted, read QP data\n");
+
+ /* read in DST QP info, IA address. check for private data */
+ len = recv(acm_ptr->socket, (char *)&acm_ptr->msg, exp, 0);
+ if (len != exp || ntohs(acm_ptr->msg.ver) != DCM_VER) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT read: ERR %s, rcnt=%d, ver=%d\n",
+ strerror(errno), len, ntohs(acm_ptr->msg.ver));
+ goto bail;
+ }
+
+ /* keep the QP, address info in network order */
+
+ /* validate private data size before reading */
+ exp = ntohs(acm_ptr->msg.p_size);
+ if (exp > DCM_MAX_PDATA_SIZE) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " accept read: psize (%d) wrong\n",
+ acm_ptr->msg.p_size);
+ goto bail;
+ }
+
+ /* read private data into cm_handle if any present */
+ if (exp) {
+ len = recv(acm_ptr->socket, acm_ptr->msg.p_data, exp, 0);
+ if (len != exp) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " accept read pdata: ERR %s, rcnt=%d\n",
+ strerror(errno), len);
+ goto bail;
+ }
+ p_data = acm_ptr->msg.p_data;
+ }
+
+ acm_ptr->state = DCM_ACCEPTING_DATA;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " ACCEPT: DST %s %x lid=0x%x, qpn=0x%x, psz=%d\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &acm_ptr->msg.daddr.so)->sin_addr),
+ ntohs(((struct sockaddr_in *)
+ &acm_ptr->msg.daddr.so)->sin_port),
+ ntohs(acm_ptr->msg.saddr.ib.lid),
+ ntohl(acm_ptr->msg.saddr.ib.qpn), exp);
+
+#ifdef DAT_EXTENSIONS
+ if (acm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) {
+ DAT_IB_EXTENSION_EVENT_DATA xevent;
+
+ /* post EVENT, modify_qp created ah */
+ xevent.status = 0;
+ xevent.type = DAT_IB_UD_CONNECT_REQUEST;
+
+ dapls_evd_post_cr_event_ext(acm_ptr->sp,
+ DAT_IB_UD_CONNECTION_REQUEST_EVENT,
+ acm_ptr,
+ (DAT_COUNT) exp,
+ (DAT_PVOID *) acm_ptr->msg.p_data,
+ (DAT_PVOID *) &xevent);
+ } else
+#endif
+ /* trigger CR event and return SUCCESS */
+ dapls_cr_callback(acm_ptr,
+ IB_CME_CONNECTION_REQUEST_PENDING,
+ p_data, exp, acm_ptr->sp);
+ return;
+bail:
+ /* mark for destroy, active will see socket close as rej */
+ dapli_cm_free(acm_ptr);
+ return;
+}
+
+/*
+ * PASSIVE: consumer accept, send local QP information, private data,
+ * queue on work thread to receive RTU information to avoid blocking
+ * user thread.
+ */
+static DAT_RETURN
+dapli_socket_accept_usr(DAPL_EP * ep_ptr,
+ DAPL_CR * cr_ptr, DAT_COUNT p_size, DAT_PVOID p_data)
+{
+ DAPL_IA *ia_ptr = ep_ptr->header.owner_ia;
+ dp_ib_cm_handle_t cm_ptr = cr_ptr->ib_cm_handle;
+ ib_cm_msg_t local;
+ struct iovec iov[2];
+ int len, exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;
+ DAT_RETURN ret = DAT_INTERNAL_ERROR;
+ socklen_t sl;
+
+ if (p_size > DCM_MAX_PDATA_SIZE) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " accept_usr: psize(%d) too large\n", p_size);
+ return DAT_LENGTH_ERROR;
+ }
+
+ /* must have a accepted socket */
+ if (cm_ptr->socket == DAPL_INVALID_SOCKET) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " accept_usr: cm socket invalid\n");
+ goto bail;
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " ACCEPT_USR: remote lid=0x%x"
+ " qpn=0x%x qp_type %d, psize=%d\n",
+ ntohs(cm_ptr->msg.saddr.ib.lid),
+ ntohl(cm_ptr->msg.saddr.ib.qpn),
+ cm_ptr->msg.saddr.ib.qp_type,
+ ntohs(cm_ptr->msg.p_size));
+
+#ifdef DAT_EXTENSIONS
+ if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD &&
+ ep_ptr->qp_handle->qp_type != IBV_QPT_UD) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT_USR: ERR remote QP is UD,"
+ ", but local QP is not\n");
+ ret = (DAT_INVALID_HANDLE | DAT_INVALID_HANDLE_EP);
+ goto bail;
+ }
+#endif
+
+ /* modify QP to RTR and then to RTS with remote info already read */
+ if (dapls_modify_qp_state(ep_ptr->qp_handle,
+ IBV_QPS_RTR,
+ cm_ptr->msg.saddr.ib.qpn,
+ cm_ptr->msg.saddr.ib.lid,
+ (ib_gid_handle_t)cm_ptr->msg.saddr.ib.gid) != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT_USR: QPS_RTR ERR %s -> %s\n",
+ strerror(errno),
+ inet_ntoa(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_addr));
+ goto bail;
+ }
+ if (dapls_modify_qp_state(ep_ptr->qp_handle,
+ IBV_QPS_RTS,
+ cm_ptr->msg.saddr.ib.qpn,
+ cm_ptr->msg.saddr.ib.lid,
+ NULL) != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT_USR: QPS_RTS ERR %s -> %s\n",
+ strerror(errno),
+ inet_ntoa(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_addr));
+ goto bail;
+ }
+
+ /* save remote address information */
+ dapl_os_memcpy(&ep_ptr->remote_ia_address,
+ &cm_ptr->msg.daddr.so,
+ sizeof(union dcm_addr));
+
+ /* send our QP info, IA address, pdata. Don't overwrite dst data */
+ local.ver = htons(DCM_VER);
+ local.op = htons(DCM_REP);
+ local.saddr.ib.qpn = htonl(ep_ptr->qp_handle->qp_num);
+ local.saddr.ib.qp_type = ep_ptr->qp_handle->qp_type;
+ local.saddr.ib.lid = ia_ptr->hca_ptr->ib_trans.lid;
+ dapl_os_memcpy(&local.saddr.ib.gid[0],
+ &ia_ptr->hca_ptr->ib_trans.gid, 16);
+
+ /* Get local address information from socket */
+ sl = sizeof(local.daddr.so);
+ getsockname(cm_ptr->socket, (struct sockaddr *)&local.daddr.so, &sl);
+
+#ifdef DAPL_DBG
+ /* DBG: Active PID [0], PASSIVE PID [2] */
+ *(uint16_t*)&cm_ptr->msg.resv[2] = htons((uint16_t)dapl_os_getpid());
+ dapl_os_memcpy(local.resv, cm_ptr->msg.resv, 4);
+#endif
+ cm_ptr->hca = ia_ptr->hca_ptr;
+ cm_ptr->state = DCM_ACCEPTED;
+
+ local.p_size = htons(p_size);
+ iov[0].iov_base = (void *)&local;
+ iov[0].iov_len = exp;
+
+ if (p_size) {
+ iov[1].iov_base = p_data;
+ iov[1].iov_len = p_size;
+ len = writev(cm_ptr->socket, iov, 2);
+ } else
+ len = writev(cm_ptr->socket, iov, 1);
+
+ if (len != (p_size + exp)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT_USR: ERR %s, wcnt=%d -> %s\n",
+ strerror(errno), len,
+ inet_ntoa(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_addr));
+ goto bail;
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " ACCEPT_USR: local lid=0x%x qpn=0x%x psz=%d\n",
+ ntohs(local.saddr.ib.lid),
+ ntohl(local.saddr.ib.qpn), ntohs(local.p_size));
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " ACCEPT_USR: SRC GID subnet %016llx id %016llx\n",
+ (unsigned long long)
+ htonll(*(uint64_t*)&local.saddr.ib.gid[0]),
+ (unsigned long long)
+ htonll(*(uint64_t*)&local.saddr.ib.gid[8]));
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP, " PASSIVE: accepted!\n");
+
+ /* Link CM to EP, already queued on work thread */
+ dapl_ep_link_cm(ep_ptr, cm_ptr);
+ cm_ptr->ep = ep_ptr;
+ return DAT_SUCCESS;
+bail:
+ /* schedule cleanup from workq */
+ dapli_cm_free(cm_ptr);
+ return ret;
+}
+
+/*
+ * PASSIVE: read RTU from active peer, post CONN event
+ */
+static void dapli_socket_accept_rtu(dp_ib_cm_handle_t cm_ptr)
+{
+ int len;
+ ib_cm_events_t event = IB_CME_CONNECTED;
+
+ /* complete handshake after final QP state change, VER and OP */
+ len = recv(cm_ptr->socket, (char *)&cm_ptr->msg, 4, 0);
+ if (len != 4 || ntohs(cm_ptr->msg.op) != DCM_RTU) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT_RTU: rcv ERR, rcnt=%d op=%x\n",
+ len, ntohs(cm_ptr->msg.op),
+ inet_ntoa(((struct sockaddr_in *)
+ &cm_ptr->msg.daddr.so)->sin_addr));
+ event = IB_CME_DESTINATION_REJECT;
+ goto bail;
+ }
+
+ /* save state and reference to EP, queue for disc event */
+ cm_ptr->state = DCM_CONNECTED;
+
+ /* final data exchange if remote QP state is good to go */
+ dapl_dbg_log(DAPL_DBG_TYPE_EP, " PASSIVE: connected!\n");
+
+#ifdef DAT_EXTENSIONS
+ud_bail:
+ if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) {
+ DAT_IB_EXTENSION_EVENT_DATA xevent;
+
+ ib_pd_handle_t pd_handle =
+ ((DAPL_PZ *)cm_ptr->ep->param.pz_handle)->pd_handle;
+
+ if (event == IB_CME_CONNECTED) {
+ cm_ptr->ah = dapls_create_ah(cm_ptr->hca, pd_handle,
+ cm_ptr->ep->qp_handle,
+ cm_ptr->msg.saddr.ib.lid,
+ NULL);
+ if (cm_ptr->ah) {
+ /* post EVENT, modify_qp created ah */
+ xevent.status = 0;
+ xevent.type = DAT_IB_UD_PASSIVE_REMOTE_AH;
+ xevent.remote_ah.ah = cm_ptr->ah;
+ xevent.remote_ah.qpn = ntohl(cm_ptr->msg.saddr.ib.qpn);
+ dapl_os_memcpy(&xevent.remote_ah.ia_addr,
+ &cm_ptr->msg.daddr.so,
+ sizeof(union dcm_addr));
+ event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED;
+ } else
+ event = DAT_IB_UD_CONNECTION_ERROR_EVENT;
+ } else
+ event = DAT_IB_UD_CONNECTION_ERROR_EVENT;
+
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " CONN_RTU: UD AH %p for lid 0x%x qpn 0x%x\n",
+ cm_ptr->ah, ntohs(cm_ptr->msg.saddr.ib.lid),
+ ntohl(cm_ptr->msg.saddr.ib.qpn));
+
+ dapls_evd_post_connection_event_ext(
+ (DAPL_EVD *)
+ cm_ptr->ep->param.connect_evd_handle,
+ event,
+ (DAT_EP_HANDLE) cm_ptr->ep,
+ (DAT_COUNT) ntohs(cm_ptr->msg.p_size),
+ (DAT_PVOID *) cm_ptr->msg.p_data,
+ (DAT_PVOID *) &xevent);
+
+ /* cleanup and release from local list, still on EP list */
+ dapli_cm_free(cm_ptr);
+
+ } else
+#endif
+ {
+ dapls_cr_callback(cm_ptr, event, NULL, 0, cm_ptr->sp);
+ }
+ return;
+
+bail:
+#ifdef DAT_EXTENSIONS
+ if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD)
+ goto ud_bail;
+#endif
+ cm_ptr->state = DCM_REJECTED;
+ dapls_cr_callback(cm_ptr, event, NULL, 0, cm_ptr->sp);
+ dapli_cm_free(cm_ptr);
+}
+
+/*
+ * 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 remote_ia_address,
+ IN DAT_CONN_QUAL remote_conn_qual,
+ IN DAT_COUNT private_data_size, IN void *private_data)
+{
+ DAPL_EP *ep_ptr = (DAPL_EP *) ep_handle;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " connect(ep_handle %p ....)\n", ep_handle);
+
+ return (dapli_socket_connect(ep_ptr, remote_ia_address,
+ remote_conn_qual,
+ private_data_size, private_data));
+}
+
+/*
+ * 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 cm_ptr = dapl_get_cm_from_ep(ep_ptr);
+
+ if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED ||
+ ep_ptr->param.ep_attr.service_type != DAT_SERVICE_TYPE_RC) {
+ return DAT_SUCCESS;
+ }
+
+ /* RC. Transition to error state to flush queue */
+ dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0, 0, 0);
+
+ return (dapli_socket_disconnect(cm_ptr));
+}
+
+/*
+ * 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. It is also called if dat_ep_connect
+ * times out using the consumer supplied timeout value.
+ *
+ * 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)
+{
+ if (ib_cm_event == IB_CME_TIMEOUT) {
+ dp_ib_cm_handle_t cm_ptr = dapl_get_cm_from_ep(ep_ptr);
+
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ "dapls_ib_disc_clean: CONN_TIMEOUT ep %p cm %p %s\n",
+ ep_ptr, cm_ptr, dapl_cm_state_str(cm_ptr->state));
+
+ /* schedule release of socket and local resources */
+ dapli_cm_free(cm_ptr);
+ }
+}
+
+/*
+ * 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)
+{
+ return (dapli_socket_listen(ia_ptr, ServiceID, sp_ptr));
+}
+
+/*
+ * 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 cm_ptr = sp_ptr->cm_srvc_handle;
+
+ /* free cm_srvc_handle, release will cleanup */
+ if (cm_ptr != NULL) {
+ /* cr_thread will free */
+ sp_ptr->cm_srvc_handle = NULL;
+ dapli_cm_free(cm_ptr);
+ }
+ 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_EP *ep_ptr;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ "dapls_ib_accept_connection(cr %p ep %p prd %p,%d)\n",
+ cr_handle, ep_handle, p_data, p_size);
+
+ cr_ptr = (DAPL_CR *) cr_handle;
+ ep_ptr = (DAPL_EP *) ep_handle;
+
+ /* allocate and attach a QP if necessary */
+ if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {
+ DAT_RETURN status;
+ status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia,
+ ep_ptr, ep_ptr);
+ if (status != DAT_SUCCESS)
+ return status;
+ }
+ return (dapli_socket_accept_usr(ep_ptr, cr_ptr, p_size, p_data));
+}
+
+/*
+ * 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_ptr,
+ IN int reason,
+ IN DAT_COUNT psize, IN const DAT_PVOID pdata)
+{
+ struct iovec iov[2];
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " reject(cm %p reason %x, pdata %p, psize %d)\n",
+ cm_ptr, reason, pdata, psize);
+
+ if (psize > DCM_MAX_PDATA_SIZE)
+ return DAT_LENGTH_ERROR;
+
+ /* write reject data to indicate reject */
+ cm_ptr->msg.op = htons(DCM_REJ_USER);
+ cm_ptr->msg.p_size = htons(psize);
+
+ iov[0].iov_base = (void *)&cm_ptr->msg;
+ iov[0].iov_len = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE;
+ if (psize) {
+ iov[1].iov_base = pdata;
+ iov[1].iov_len = psize;
+ writev(cm_ptr->socket, iov, 2);
+ } else {
+ writev(cm_ptr->socket, iov, 1);
+ }
+
+ /* release and cleanup CM object */
+ dapli_cm_free(cm_ptr);
+ return DAT_SUCCESS;
+}
+
+/*
+ * 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 * remote_ia_address)
+{
+ DAPL_HEADER *header;
+ dp_ib_cm_handle_t conn;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ "dapls_ib_cm_remote_addr(dat_handle %p, ....)\n",
+ dat_handle);
+
+ header = (DAPL_HEADER *) dat_handle;
+
+ if (header->magic == DAPL_MAGIC_EP)
+ conn = dapl_get_cm_from_ep((DAPL_EP *) dat_handle);
+ else if (header->magic == DAPL_MAGIC_CR)
+ conn = ((DAPL_CR *) dat_handle)->ib_cm_handle;
+ else
+ return DAT_INVALID_HANDLE;
+
+ dapl_os_memcpy(remote_ia_address,
+ &conn->msg.daddr.so, sizeof(DAT_SOCK_ADDR6));
+
+ return DAT_SUCCESS;
+}
+
+int dapls_ib_private_data_size(
+ IN DAPL_HCA *hca_ptr)
+{
+ return DCM_MAX_PDATA_SIZE;
+}
+
+/* outbound/inbound CR processing thread to avoid blocking applications */
+void cr_thread(void *arg)
+{
+ struct dapl_hca *hca_ptr = arg;
+ dp_ib_cm_handle_t cr, next_cr;
+ int opt, ret;
+ socklen_t opt_len;
+ char rbuf[2];
+ struct dapl_fd_set *set;
+ enum DAPL_FD_EVENTS event;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cr_thread: ENTER hca %p\n", hca_ptr);
+ set = dapl_alloc_fd_set();
+ if (!set)
+ goto out;
+
+ dapl_os_lock(&hca_ptr->ib_trans.lock);
+ hca_ptr->ib_trans.cr_state = IB_THREAD_RUN;
+
+ while (1) {
+ dapl_fd_zero(set);
+ dapl_fd_set(hca_ptr->ib_trans.scm[0], set, DAPL_FD_READ);
+
+ if (!dapl_llist_is_empty(&hca_ptr->ib_trans.list))
+ next_cr = dapl_llist_peek_head(&hca_ptr->ib_trans.list);
+ else
+ next_cr = NULL;
+
+ while (next_cr) {
+ cr = next_cr;
+ next_cr = dapl_llist_next_entry(&hca_ptr->ib_trans.list,
+ (DAPL_LLIST_ENTRY *)
+ &cr->local_entry);
+ dapls_cm_acquire(cr); /* hold thread ref */
+ dapl_os_lock(&cr->lock);
+ if (cr->state == DCM_FREE ||
+ hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) {
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " CM FREE: %p ep=%p st=%s sck=%d refs=%d\n",
+ cr, cr->ep, dapl_cm_state_str(cr->state),
+ cr->socket, cr->ref_count);
+
+ if (cr->socket != DAPL_INVALID_SOCKET) {
+ shutdown(cr->socket, SHUT_RDWR);
+ closesocket(cr->socket);
+ cr->socket = DAPL_INVALID_SOCKET;
+ }
+ dapl_os_unlock(&cr->lock);
+ dapls_cm_release(cr); /* release alloc ref */
+ dapli_cm_dequeue(cr); /* release workq ref */
+ dapls_cm_release(cr); /* release thread ref */
+ continue;
+ }
+
+ event = (cr->state == DCM_CONN_PENDING) ?
+ DAPL_FD_WRITE : DAPL_FD_READ;
+
+ if (dapl_fd_set(cr->socket, set, event)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " cr_thread: fd_set ERR st=%d fd %d"
+ " -> %s\n", cr->state, cr->socket,
+ inet_ntoa(((struct sockaddr_in *)
+ &cr->msg.daddr.so)->sin_addr));
+ dapl_os_unlock(&cr->lock);
+ dapls_cm_release(cr); /* release ref */
+ continue;
+ }
+ dapl_os_unlock(&cr->lock);
+ dapl_os_unlock(&hca_ptr->ib_trans.lock);
+
+ ret = dapl_poll(cr->socket, event);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " poll ret=0x%x %s sck=%d\n",
+ ret, dapl_cm_state_str(cr->state),
+ cr->socket);
+
+ /* data on listen, qp exchange, and on disc req */
+ if ((ret == DAPL_FD_READ) ||
+ (cr->state != DCM_CONN_PENDING && ret == DAPL_FD_ERROR)) {
+ if (cr->socket != DAPL_INVALID_SOCKET) {
+ switch (cr->state) {
+ case DCM_LISTEN:
+ dapli_socket_accept(cr);
+ break;
+ case DCM_ACCEPTING:
+ dapli_socket_accept_data(cr);
+ break;
+ case DCM_ACCEPTED:
+ dapli_socket_accept_rtu(cr);
+ break;
+ case DCM_REP_PENDING:
+ dapli_socket_connect_rtu(cr);
+ break;
+ case DCM_CONNECTED:
+ dapli_socket_disconnect(cr);
+ break;
+ default:
+ break;
+ }
+ }
+ /* ASYNC connections, writable, readable, error; check status */
+ } else if (ret == DAPL_FD_WRITE ||
+ (cr->state == DCM_CONN_PENDING &&
+ ret == DAPL_FD_ERROR)) {
+
+ if (ret == DAPL_FD_ERROR)
+ dapl_log(DAPL_DBG_TYPE_ERR, " CONN_PENDING - FD_ERROR\n");
+
+ opt = 0;
+ opt_len = sizeof(opt);
+ ret = getsockopt(cr->socket, SOL_SOCKET,
+ SO_ERROR, (char *)&opt,
+ &opt_len);
+ if (!ret && !opt)
+ dapli_socket_connected(cr, opt);
+ else
+ dapli_socket_connected(cr, opt ? opt : dapl_socket_errno());
+ }
+
+ dapls_cm_release(cr); /* release ref */
+ dapl_os_lock(&hca_ptr->ib_trans.lock);
+ }
+
+ /* set to exit and all resources destroyed */
+ if ((hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) &&
+ (dapl_llist_is_empty(&hca_ptr->ib_trans.list)))
+ break;
+
+ dapl_os_unlock(&hca_ptr->ib_trans.lock);
+ dapl_select(set);
+
+ /* if pipe used to wakeup, consume */
+ while (dapl_poll(hca_ptr->ib_trans.scm[0],
+ DAPL_FD_READ) == DAPL_FD_READ) {
+ if (recv(hca_ptr->ib_trans.scm[0], rbuf, 2, 0) == -1)
+ dapl_log(DAPL_DBG_TYPE_THREAD,
+ " cr_thread: read pipe error = %s\n",
+ strerror(errno));
+ }
+ dapl_os_lock(&hca_ptr->ib_trans.lock);
+
+ /* set to exit and all resources destroyed */
+ if ((hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) &&
+ (dapl_llist_is_empty(&hca_ptr->ib_trans.list)))
+ break;
+ }
+
+ dapl_os_unlock(&hca_ptr->ib_trans.lock);
+ dapl_os_free(set, sizeof(struct dapl_fd_set));
+out:
+ hca_ptr->ib_trans.cr_state = IB_THREAD_EXIT;
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " cr_thread(hca %p) exit\n", hca_ptr);
+}
+
+
+#ifdef DAPL_COUNTERS
+/* Debug aid: List all Connections in process and state */
+void dapls_print_cm_list(IN DAPL_IA *ia_ptr)
+{
+ /* Print in process CR's for this IA, if debug type set */
+ int i = 0;
+ dp_ib_cm_handle_t cr, next_cr;
+
+ dapl_os_lock(&ia_ptr->hca_ptr->ib_trans.lock);
+ if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)
+ &ia_ptr->hca_ptr->ib_trans.list))
+ next_cr = dapl_llist_peek_head((DAPL_LLIST_HEAD*)
+ &ia_ptr->hca_ptr->ib_trans.list);
+ else
+ next_cr = NULL;
+
+ printf("\n DAPL IA CONNECTIONS IN PROCESS:\n");
+ while (next_cr) {
+ cr = next_cr;
+ next_cr = dapl_llist_next_entry((DAPL_LLIST_HEAD*)
+ &ia_ptr->hca_ptr->ib_trans.list,
+ (DAPL_LLIST_ENTRY*)&cr->local_entry);
+
+ printf( " CONN[%d]: sp %p ep %p sock %d %s %s %s %s %s %s PORT L-%x R-%x PID L-%x R-%x\n",
+ i, cr->sp, cr->ep, cr->socket,
+ cr->msg.saddr.ib.qp_type == IBV_QPT_RC ? "RC" : "UD",
+ dapl_cm_state_str(cr->state), dapl_cm_op_str(ntohs(cr->msg.op)),
+ ntohs(cr->msg.op) == DCM_REQ ? /* local address */
+ inet_ntoa(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_addr) :
+ inet_ntoa(((struct sockaddr_in *)&cr->addr)->sin_addr),
+ cr->sp ? "<-" : "->",
+ ntohs(cr->msg.op) == DCM_REQ ? /* remote address */
+ inet_ntoa(((struct sockaddr_in *)&cr->addr)->sin_addr) :
+ inet_ntoa(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_addr),
+
+ ntohs(cr->msg.op) == DCM_REQ ? /* local port */
+ ntohs(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_port) :
+ ntohs(((struct sockaddr_in *)&cr->addr)->sin_port),
+
+ ntohs(cr->msg.op) == DCM_REQ ? /* remote port */
+ ntohs(((struct sockaddr_in *)&cr->addr)->sin_port) :
+ ntohs(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_port),
+
+ cr->sp ? ntohs(*(uint16_t*)&cr->msg.resv[2]) : ntohs(*(uint16_t*)&cr->msg.resv[0]),
+ cr->sp ? ntohs(*(uint16_t*)&cr->msg.resv[0]) : ntohs(*(uint16_t*)&cr->msg.resv[2]));
+
+ i++;
+ }
+ printf("\n");
+ dapl_os_unlock(&ia_ptr->hca_ptr->ib_trans.lock);
+}
+#endif
#include "openib_osd.h"
#include "dapl_ib_common.h"
+/* DAPL CM objects MUST include list_entry, ref_count, event for EP linking */
struct ib_cm_handle
{
- struct dapl_llist_entry entry;
+ struct dapl_llist_entry list_entry;
+ struct dapl_llist_entry local_entry;
+ DAPL_OS_WAIT_OBJECT event;
DAPL_OS_LOCK lock;
+ int ref_count;
int state;
DAPL_SOCKET socket;
struct dapl_hca *hca;
DAT_SOCK_ADDR6 addr;
};
-typedef struct ib_cm_handle *dp_ib_cm_handle_t;
+typedef struct ib_cm_handle *dp_ib_cm_handle_t;
typedef dp_ib_cm_handle_t ib_cm_srvc_handle_t;
/* Definitions */
void dapli_cq_thread_destroy(struct dapl_hca *hca_ptr);
void dapli_async_event_cb(struct _ib_hca_transport *tp);
void dapli_cq_event_cb(struct _ib_hca_transport *tp);
-DAT_RETURN dapli_socket_disconnect(dp_ib_cm_handle_t cm_ptr);
-dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep);
-void dapls_ib_cm_free(dp_ib_cm_handle_t cm, DAPL_EP *ep);
+void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr);
+void dapls_cm_release(dp_ib_cm_handle_t cm_ptr);
+void dapls_cm_free(dp_ib_cm_handle_t cm_ptr);
+
+#ifdef DAPL_COUNTERS
void dapls_print_cm_list(IN DAPL_IA *ia_ptr);
+#endif
#endif /* _DAPL_IB_UTIL_H_ */
-/*\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: uDAPL\r
- *\r
- * Filename: dapl_ib_util.c\r
- *\r
- * Author: Arlin Davis\r
- *\r
- * Created: 3/10/2005\r
- *\r
- * Description: \r
- *\r
- * The uDAPL openib provider - init, open, close, utilities\r
- *\r
- ****************************************************************************\r
- * Source Control System Information\r
- *\r
- * $Id: $\r
- *\r
- * Copyright (c) 2005 Intel Corporation. All rights reserved.\r
- *\r
- **************************************************************************/\r
-#ifdef RCSID\r
-static const char rcsid[] = "$Id: $";\r
-#endif\r
-\r
-#include "openib_osd.h"\r
-#include "dapl.h"\r
-#include "dapl_adapter_util.h"\r
-#include "dapl_ib_util.h"\r
-#include "dapl_osd.h"\r
-\r
-#include <stdlib.h>\r
-\r
-ib_thread_state_t g_ib_thread_state = 0;\r
-DAPL_OS_THREAD g_ib_thread;\r
-DAPL_OS_LOCK g_hca_lock;\r
-struct dapl_llist_entry *g_hca_list;\r
-\r
-void dapli_thread(void *arg);\r
-DAT_RETURN dapli_ib_thread_init(void);\r
-void dapli_ib_thread_destroy(void);\r
-\r
-#if defined(_WIN64) || defined(_WIN32)\r
-#include "..\..\..\..\..\etc\user\comp_channel.cpp"\r
-#include <rdma\winverbs.h>\r
-\r
-static COMP_SET ufds;\r
-\r
-static int dapls_os_init(void)\r
-{\r
- return CompSetInit(&ufds);\r
-}\r
-\r
-static void dapls_os_release(void)\r
-{\r
- CompSetCleanup(&ufds);\r
-}\r
-\r
-static int dapls_config_verbs(struct ibv_context *verbs)\r
-{\r
- verbs->channel.Milliseconds = 0;\r
- return 0;\r
-}\r
-\r
-static int dapls_config_comp_channel(struct ibv_comp_channel *channel)\r
-{\r
- channel->comp_channel.Milliseconds = 0;\r
- return 0;\r
-}\r
-\r
-static int dapls_thread_signal(void)\r
-{\r
- CompSetCancel(&ufds);\r
- return 0;\r
-}\r
-#else // _WIN64 || WIN32\r
-int g_ib_pipe[2];\r
-\r
-static int dapls_os_init(void)\r
-{\r
- /* create pipe for waking up work thread */\r
- return pipe(g_ib_pipe);\r
-}\r
-\r
-static void dapls_os_release(void)\r
-{\r
- /* close pipe? */\r
-}\r
-\r
-static int dapls_config_fd(int fd)\r
-{\r
- int opts;\r
-\r
- opts = fcntl(fd, F_GETFL);\r
- if (opts < 0 || fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " dapls_config_fd: fcntl on fd %d ERR %d %s\n",\r
- fd, opts, strerror(errno));\r
- return errno;\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static int dapls_config_verbs(struct ibv_context *verbs)\r
-{\r
- return dapls_config_fd(verbs->async_fd);\r
-}\r
-\r
-static int dapls_config_comp_channel(struct ibv_comp_channel *channel)\r
-{\r
- return dapls_config_fd(channel->fd);\r
-}\r
-\r
-static int dapls_thread_signal(void)\r
-{\r
- return write(g_ib_pipe[1], "w", sizeof "w");\r
-}\r
-#endif\r
-\r
-\r
-static int32_t create_cr_pipe(IN DAPL_HCA * hca_ptr)\r
-{\r
- DAPL_SOCKET listen_socket;\r
- struct sockaddr_in addr;\r
- socklen_t addrlen = sizeof(addr);\r
- int ret;\r
-\r
- listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
- if (listen_socket == DAPL_INVALID_SOCKET)\r
- return 1;\r
-\r
- memset(&addr, 0, sizeof addr);\r
- addr.sin_family = AF_INET;\r
- addr.sin_addr.s_addr = htonl(0x7f000001);\r
- ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof addr);\r
- if (ret)\r
- goto err1;\r
-\r
- ret = getsockname(listen_socket, (struct sockaddr *)&addr, &addrlen);\r
- if (ret)\r
- goto err1;\r
-\r
- ret = listen(listen_socket, 0);\r
- if (ret)\r
- goto err1;\r
-\r
- hca_ptr->ib_trans.scm[1] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
- if (hca_ptr->ib_trans.scm[1] == DAPL_INVALID_SOCKET)\r
- goto err1;\r
-\r
- ret = connect(hca_ptr->ib_trans.scm[1], \r
- (struct sockaddr *)&addr, sizeof(addr));\r
- if (ret)\r
- goto err2;\r
-\r
- hca_ptr->ib_trans.scm[0] = accept(listen_socket, NULL, NULL);\r
- if (hca_ptr->ib_trans.scm[0] == DAPL_INVALID_SOCKET)\r
- goto err2;\r
-\r
- closesocket(listen_socket);\r
- return 0;\r
-\r
- err2:\r
- closesocket(hca_ptr->ib_trans.scm[1]);\r
- err1:\r
- closesocket(listen_socket);\r
- return 1;\r
-}\r
-\r
-static void destroy_cr_pipe(IN DAPL_HCA * hca_ptr)\r
-{\r
- closesocket(hca_ptr->ib_trans.scm[0]);\r
- closesocket(hca_ptr->ib_trans.scm[1]);\r
-}\r
-\r
-\r
-/*\r
- * dapls_ib_init, dapls_ib_release\r
- *\r
- * Initialize Verb related items for device open\r
- *\r
- * Input:\r
- * none\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Returns:\r
- * 0 success, -1 error\r
- *\r
- */\r
-int32_t dapls_ib_init(void)\r
-{\r
- /* initialize hca_list */\r
- dapl_os_lock_init(&g_hca_lock);\r
- dapl_llist_init_head(&g_hca_list);\r
-\r
- if (dapls_os_init())\r
- return 1;\r
-\r
- return 0;\r
-}\r
-\r
-int32_t dapls_ib_release(void)\r
-{\r
- dapli_ib_thread_destroy();\r
- dapls_os_release();\r
- return 0;\r
-}\r
-\r
-/*\r
- * dapls_ib_open_hca\r
- *\r
- * Open HCA\r
- *\r
- * Input:\r
- * *hca_name pointer to provider device name\r
- * *ib_hca_handle_p pointer to provide HCA handle\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Return:\r
- * DAT_SUCCESS\r
- * dapl_convert_errno\r
- *\r
- */\r
-DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr)\r
-{\r
- struct ibv_device **dev_list;\r
- struct ibv_port_attr port_attr;\r
- int i;\r
- DAT_RETURN dat_status;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " open_hca: %s - %p\n", hca_name, hca_ptr);\r
-\r
- /* get the IP address of the device */\r
- dat_status = getlocalipaddr((DAT_SOCK_ADDR *) &hca_ptr->hca_address,\r
- sizeof(DAT_SOCK_ADDR6));\r
- if (dat_status != DAT_SUCCESS)\r
- return dat_status;\r
-\r
-#ifdef DAPL_DBG\r
- /* DBG: unused port, set process id, lower 16 bits of pid */\r
- ((struct sockaddr_in *)&hca_ptr->hca_address)->sin_port = \r
- htons((uint16_t)dapl_os_getpid());\r
-#endif\r
- /* Get list of all IB devices, find match, open */\r
- dev_list = ibv_get_device_list(NULL);\r
- if (!dev_list) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: ibv_get_device_list() failed\n",\r
- hca_name);\r
- return DAT_INTERNAL_ERROR;\r
- }\r
-\r
- for (i = 0; dev_list[i]; ++i) {\r
- hca_ptr->ib_trans.ib_dev = dev_list[i];\r
- if (!strcmp(ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
- hca_name))\r
- goto found;\r
- }\r
-\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: device %s not found\n", hca_name);\r
- goto err;\r
-\r
-found:\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " open_hca: Found dev %s %016llx\n",\r
- ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
- (unsigned long long)\r
- ntohll(ibv_get_device_guid(hca_ptr->ib_trans.ib_dev)));\r
-\r
- hca_ptr->ib_hca_handle = ibv_open_device(hca_ptr->ib_trans.ib_dev);\r
- if (!hca_ptr->ib_hca_handle) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: dev open failed for %s, err=%s\n",\r
- ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
- strerror(errno));\r
- goto err;\r
- }\r
- hca_ptr->ib_trans.ib_ctx = hca_ptr->ib_hca_handle;\r
- dapls_config_verbs(hca_ptr->ib_hca_handle);\r
-\r
- /* get lid for this hca-port, network order */\r
- if (ibv_query_port(hca_ptr->ib_hca_handle,\r
- (uint8_t) hca_ptr->port_num, &port_attr)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: get lid ERR for %s, err=%s\n",\r
- ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
- strerror(errno));\r
- goto err;\r
- } else {\r
- hca_ptr->ib_trans.lid = htons(port_attr.lid);\r
- }\r
-\r
- /* get gid for this hca-port, network order */\r
- if (ibv_query_gid(hca_ptr->ib_hca_handle,\r
- (uint8_t) hca_ptr->port_num,\r
- 0, &hca_ptr->ib_trans.gid)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: query GID ERR for %s, err=%s\n",\r
- ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
- strerror(errno));\r
- goto err;\r
- }\r
-\r
- /* set RC tunables via enviroment or default */\r
- hca_ptr->ib_trans.max_inline_send =\r
- dapl_os_get_env_val("DAPL_MAX_INLINE", INLINE_SEND_DEFAULT);\r
- hca_ptr->ib_trans.ack_retry =\r
- dapl_os_get_env_val("DAPL_ACK_RETRY", SCM_ACK_RETRY);\r
- hca_ptr->ib_trans.ack_timer =\r
- dapl_os_get_env_val("DAPL_ACK_TIMER", SCM_ACK_TIMER);\r
- hca_ptr->ib_trans.rnr_retry =\r
- dapl_os_get_env_val("DAPL_RNR_RETRY", SCM_RNR_RETRY);\r
- hca_ptr->ib_trans.rnr_timer =\r
- dapl_os_get_env_val("DAPL_RNR_TIMER", SCM_RNR_TIMER);\r
- hca_ptr->ib_trans.global =\r
- dapl_os_get_env_val("DAPL_GLOBAL_ROUTING", SCM_GLOBAL);\r
- hca_ptr->ib_trans.hop_limit =\r
- dapl_os_get_env_val("DAPL_HOP_LIMIT", SCM_HOP_LIMIT);\r
- hca_ptr->ib_trans.tclass =\r
- dapl_os_get_env_val("DAPL_TCLASS", SCM_TCLASS);\r
- hca_ptr->ib_trans.mtu =\r
- dapl_ib_mtu(dapl_os_get_env_val("DAPL_IB_MTU", SCM_IB_MTU));\r
-\r
-\r
- /* EVD events without direct CQ channels, CNO support */\r
- hca_ptr->ib_trans.ib_cq =\r
- ibv_create_comp_channel(hca_ptr->ib_hca_handle);\r
- if (hca_ptr->ib_trans.ib_cq == NULL) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: ibv_create_comp_channel ERR %s\n",\r
- strerror(errno));\r
- goto bail;\r
- }\r
- dapls_config_comp_channel(hca_ptr->ib_trans.ib_cq);\r
- \r
- dat_status = dapli_ib_thread_init();\r
- if (dat_status != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: failed to init cq thread lock\n");\r
- goto bail;\r
- }\r
- /* \r
- * Put new hca_transport on list for async and CQ event processing \r
- * Wakeup work thread to add to polling list\r
- */\r
- dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&hca_ptr->ib_trans.entry);\r
- dapl_os_lock(&g_hca_lock);\r
- dapl_llist_add_tail(&g_hca_list,\r
- (DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry,\r
- &hca_ptr->ib_trans.entry);\r
- if (dapls_thread_signal() == -1)\r
- dapl_log(DAPL_DBG_TYPE_UTIL,\r
- " open_hca: thread wakeup error = %s\n",\r
- strerror(errno));\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- /* initialize cr_list lock */\r
- dat_status = dapl_os_lock_init(&hca_ptr->ib_trans.lock);\r
- if (dat_status != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: failed to init cr_list lock\n");\r
- goto bail;\r
- }\r
-\r
- /* initialize CM list for listens on this HCA */\r
- dapl_llist_init_head(&hca_ptr->ib_trans.list);\r
-\r
- /* initialize pipe, user level wakeup on select */\r
- if (create_cr_pipe(hca_ptr)) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: failed to init cr pipe - %s\n",\r
- strerror(errno));\r
- goto bail;\r
- }\r
-\r
- /* create thread to process inbound connect request */\r
- hca_ptr->ib_trans.cr_state = IB_THREAD_INIT;\r
- dat_status = dapl_os_thread_create(cr_thread,\r
- (void *)hca_ptr,\r
- &hca_ptr->ib_trans.thread);\r
- if (dat_status != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " open_hca: failed to create thread\n");\r
- goto bail;\r
- }\r
-\r
- /* wait for thread */\r
- while (hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) {\r
- dapl_os_sleep_usec(1000);\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " open_hca: devname %s, port %d, hostname_IP %s\n",\r
- ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
- hca_ptr->port_num, inet_ntoa(((struct sockaddr_in *)\r
- &hca_ptr->hca_address)->\r
- sin_addr));\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " open_hca: LID 0x%x GID Subnet 0x" F64x " ID 0x" F64x\r
- "\n", ntohs(hca_ptr->ib_trans.lid), (unsigned long long)\r
- htonll(hca_ptr->ib_trans.gid.global.subnet_prefix),\r
- (unsigned long long)htonll(hca_ptr->ib_trans.gid.global.\r
- interface_id));\r
-\r
- ibv_free_device_list(dev_list);\r
- return dat_status;\r
-\r
- bail:\r
- ibv_close_device(hca_ptr->ib_hca_handle);\r
- hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;\r
- err:\r
- ibv_free_device_list(dev_list);\r
- return DAT_INTERNAL_ERROR;\r
-}\r
-\r
-/*\r
- * dapls_ib_close_hca\r
- *\r
- * Open HCA\r
- *\r
- * Input:\r
- * DAPL_HCA provide CA handle\r
- *\r
- * Output:\r
- * none\r
- *\r
- * Return:\r
- * DAT_SUCCESS\r
- * dapl_convert_errno \r
- *\r
- */\r
-DAT_RETURN dapls_ib_close_hca(IN DAPL_HCA * hca_ptr)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " close_hca: %p\n", hca_ptr);\r
-\r
- dapl_os_lock(&g_hca_lock);\r
- if (g_ib_thread_state != IB_THREAD_RUN) {\r
- dapl_os_unlock(&g_hca_lock);\r
- goto out;\r
- }\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- /* destroy cr_thread and lock */\r
- hca_ptr->ib_trans.cr_state = IB_THREAD_CANCEL;\r
- send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0);\r
- while (hca_ptr->ib_trans.cr_state != IB_THREAD_EXIT) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " close_hca: waiting for cr_thread\n");\r
- send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0);\r
- dapl_os_sleep_usec(1000);\r
- }\r
- dapl_os_lock_destroy(&hca_ptr->ib_trans.lock);\r
- destroy_cr_pipe(hca_ptr); /* no longer need pipe */\r
- \r
- /* \r
- * Remove hca from async event processing list\r
- * Wakeup work thread to remove from polling list\r
- */\r
- hca_ptr->ib_trans.destroy = 1;\r
- if (dapls_thread_signal() == -1)\r
- dapl_log(DAPL_DBG_TYPE_UTIL,\r
- " destroy: thread wakeup error = %s\n",\r
- strerror(errno));\r
-\r
- /* wait for thread to remove HCA references */\r
- while (hca_ptr->ib_trans.destroy != 2) {\r
- if (dapls_thread_signal() == -1)\r
- dapl_log(DAPL_DBG_TYPE_UTIL,\r
- " destroy: thread wakeup error = %s\n",\r
- strerror(errno));\r
- dapl_os_sleep_usec(1000);\r
- }\r
-\r
-out:\r
- if (hca_ptr->ib_trans.ib_cq)\r
- ibv_destroy_comp_channel(hca_ptr->ib_trans.ib_cq);\r
-\r
- if (hca_ptr->ib_trans.ib_cq_empty) {\r
- struct ibv_comp_channel *channel;\r
- channel = hca_ptr->ib_trans.ib_cq_empty->channel;\r
- ibv_destroy_cq(hca_ptr->ib_trans.ib_cq_empty);\r
- ibv_destroy_comp_channel(channel);\r
- }\r
-\r
- if (hca_ptr->ib_hca_handle != IB_INVALID_HANDLE) {\r
- if (ibv_close_device(hca_ptr->ib_hca_handle))\r
- return (dapl_convert_errno(errno, "ib_close_device"));\r
- hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;\r
- }\r
- return (DAT_SUCCESS);\r
-}\r
-\r
-DAT_RETURN dapli_ib_thread_init(void)\r
-{\r
- DAT_RETURN dat_status;\r
-\r
- dapl_os_lock(&g_hca_lock);\r
- if (g_ib_thread_state != IB_THREAD_INIT) {\r
- dapl_os_unlock(&g_hca_lock);\r
- return DAT_SUCCESS;\r
- }\r
-\r
- g_ib_thread_state = IB_THREAD_CREATE;\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- /* create thread to process inbound connect request */\r
- dat_status = dapl_os_thread_create(dapli_thread, NULL, &g_ib_thread);\r
- if (dat_status != DAT_SUCCESS)\r
- return (dapl_convert_errno(errno,\r
- "create_thread ERR:"\r
- " check resource limits"));\r
-\r
- /* wait for thread to start */\r
- dapl_os_lock(&g_hca_lock);\r
- while (g_ib_thread_state != IB_THREAD_RUN) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_init: waiting for ib_thread\n");\r
- dapl_os_unlock(&g_hca_lock);\r
- dapl_os_sleep_usec(1000);\r
- dapl_os_lock(&g_hca_lock);\r
- }\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- return DAT_SUCCESS;\r
-}\r
-\r
-void dapli_ib_thread_destroy(void)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_destroy(%d)\n", dapl_os_getpid());\r
- /* \r
- * wait for async thread to terminate. \r
- * pthread_join would be the correct method\r
- * but some applications have some issues\r
- */\r
-\r
- /* destroy ib_thread, wait for termination, if not already */\r
- dapl_os_lock(&g_hca_lock);\r
- if (g_ib_thread_state != IB_THREAD_RUN)\r
- goto bail;\r
-\r
- g_ib_thread_state = IB_THREAD_CANCEL;\r
- while (g_ib_thread_state != IB_THREAD_EXIT) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_destroy: waiting for ib_thread\n");\r
- if (dapls_thread_signal() == -1)\r
- dapl_log(DAPL_DBG_TYPE_UTIL,\r
- " destroy: thread wakeup error = %s\n",\r
- strerror(errno));\r
- dapl_os_unlock(&g_hca_lock);\r
- dapl_os_sleep_usec(2000);\r
- dapl_os_lock(&g_hca_lock);\r
- }\r
-bail:\r
- dapl_os_unlock(&g_hca_lock);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread_destroy(%d) exit\n", dapl_os_getpid());\r
-}\r
-\r
-\r
-#if defined(_WIN64) || defined(_WIN32)\r
-/* work thread for uAT, uCM, CQ, and async events */\r
-void dapli_thread(void *arg)\r
-{\r
- struct _ib_hca_transport *hca;\r
- struct _ib_hca_transport *uhca[8];\r
- int ret, idx, cnt;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d,0x%x): ENTER: \n",\r
- dapl_os_getpid(), g_ib_thread);\r
-\r
- dapl_os_lock(&g_hca_lock);\r
- for (g_ib_thread_state = IB_THREAD_RUN;\r
- g_ib_thread_state == IB_THREAD_RUN; \r
- dapl_os_lock(&g_hca_lock)) {\r
-\r
- CompSetZero(&ufds);\r
- idx = 0;\r
- hca = dapl_llist_is_empty(&g_hca_list) ? NULL :\r
- dapl_llist_peek_head(&g_hca_list);\r
-\r
- while (hca) {\r
- CompSetAdd(&hca->ib_ctx->channel, &ufds);\r
- CompSetAdd(&hca->ib_cq->comp_channel, &ufds);\r
- uhca[idx++] = hca;\r
- hca = dapl_llist_next_entry(&g_hca_list,\r
- (DAPL_LLIST_ENTRY *)\r
- &hca->entry);\r
- }\r
- cnt = idx;\r
-\r
- dapl_os_unlock(&g_hca_lock);\r
- ret = CompSetPoll(&ufds, INFINITE);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
- " ib_thread(%d) poll_event 0x%x\n",\r
- dapl_os_getpid(), ret);\r
-\r
-\r
- /* check and process ASYNC events, per device */\r
- for (idx = 0; idx < cnt; idx++) {\r
- if (uhca[idx]->destroy == 1) {\r
- dapl_os_lock(&g_hca_lock);\r
- dapl_llist_remove_entry(&g_hca_list,\r
- (DAPL_LLIST_ENTRY *)\r
- &uhca[idx]->entry);\r
- dapl_os_unlock(&g_hca_lock);\r
- uhca[idx]->destroy = 2;\r
- } else {\r
- dapli_cq_event_cb(uhca[idx]);\r
- dapli_async_event_cb(uhca[idx]);\r
- }\r
- }\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d) EXIT\n",\r
- dapl_os_getpid());\r
- g_ib_thread_state = IB_THREAD_EXIT;\r
- dapl_os_unlock(&g_hca_lock);\r
-}\r
-#else // _WIN64 || WIN32\r
-\r
-/* work thread for uAT, uCM, CQ, and async events */\r
-void dapli_thread(void *arg)\r
-{\r
- struct pollfd ufds[__FD_SETSIZE];\r
- struct _ib_hca_transport *uhca[__FD_SETSIZE] = { NULL };\r
- struct _ib_hca_transport *hca;\r
- int ret, idx, fds;\r
- char rbuf[2];\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
- " ib_thread(%d,0x%x): ENTER: pipe %d \n",\r
- dapl_os_getpid(), g_ib_thread, g_ib_pipe[0]);\r
-\r
- /* Poll across pipe, CM, AT never changes */\r
- dapl_os_lock(&g_hca_lock);\r
- g_ib_thread_state = IB_THREAD_RUN;\r
-\r
- ufds[0].fd = g_ib_pipe[0]; /* pipe */\r
- ufds[0].events = POLLIN;\r
-\r
- while (g_ib_thread_state == IB_THREAD_RUN) {\r
-\r
- /* build ufds after pipe and uCMA events */\r
- ufds[0].revents = 0;\r
- idx = 0;\r
-\r
- /* Walk HCA list and setup async and CQ events */\r
- if (!dapl_llist_is_empty(&g_hca_list))\r
- hca = dapl_llist_peek_head(&g_hca_list);\r
- else\r
- hca = NULL;\r
-\r
- while (hca) {\r
-\r
- /* uASYNC events */\r
- ufds[++idx].fd = hca->ib_ctx->async_fd;\r
- ufds[idx].events = POLLIN;\r
- ufds[idx].revents = 0;\r
- uhca[idx] = hca;\r
-\r
- /* CQ events are non-direct with CNO's */\r
- ufds[++idx].fd = hca->ib_cq->fd;\r
- ufds[idx].events = POLLIN;\r
- ufds[idx].revents = 0;\r
- uhca[idx] = hca;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
- " ib_thread(%d) poll_fd: hca[%d]=%p,"\r
- " async=%d pipe=%d \n",\r
- dapl_os_getpid(), hca, ufds[idx - 1].fd,\r
- ufds[0].fd);\r
-\r
- hca = dapl_llist_next_entry(&g_hca_list,\r
- (DAPL_LLIST_ENTRY *)\r
- &hca->entry);\r
- }\r
-\r
- /* unlock, and setup poll */\r
- fds = idx + 1;\r
- dapl_os_unlock(&g_hca_lock);\r
- ret = poll(ufds, fds, -1);\r
- if (ret <= 0) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
- " ib_thread(%d): ERR %s poll\n",\r
- dapl_os_getpid(), strerror(errno));\r
- dapl_os_lock(&g_hca_lock);\r
- continue;\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
- " ib_thread(%d) poll_event: "\r
- " async=0x%x pipe=0x%x \n",\r
- dapl_os_getpid(), ufds[idx].revents,\r
- ufds[0].revents);\r
-\r
- /* check and process CQ and ASYNC events, per device */\r
- for (idx = 1; idx < fds; idx++) {\r
- if (ufds[idx].revents == POLLIN) {\r
- dapli_cq_event_cb(uhca[idx]);\r
- dapli_async_event_cb(uhca[idx]);\r
- }\r
- }\r
-\r
- /* check and process user events, PIPE */\r
- if (ufds[0].revents == POLLIN) {\r
- if (read(g_ib_pipe[0], rbuf, 2) == -1)\r
- dapl_log(DAPL_DBG_TYPE_THREAD,\r
- " cr_thread: pipe rd err= %s\n",\r
- strerror(errno));\r
-\r
- /* cleanup any device on list marked for destroy */\r
- for (idx = 1; idx < fds; idx++) {\r
- if (uhca[idx] && uhca[idx]->destroy == 1) {\r
- dapl_os_lock(&g_hca_lock);\r
- dapl_llist_remove_entry(\r
- &g_hca_list,\r
- (DAPL_LLIST_ENTRY*)\r
- &uhca[idx]->entry);\r
- dapl_os_unlock(&g_hca_lock);\r
- uhca[idx]->destroy = 2;\r
- }\r
- }\r
- }\r
- dapl_os_lock(&g_hca_lock);\r
- }\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " ib_thread(%d) EXIT\n",\r
- dapl_os_getpid());\r
- g_ib_thread_state = IB_THREAD_EXIT;\r
- dapl_os_unlock(&g_hca_lock);\r
-}\r
-#endif\r
+/*
+ * 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: uDAPL
+ *
+ * Filename: dapl_ib_util.c
+ *
+ * Author: Arlin Davis
+ *
+ * Created: 3/10/2005
+ *
+ * Description:
+ *
+ * The uDAPL openib provider - init, open, close, utilities
+ *
+ ****************************************************************************
+ * Source Control System Information
+ *
+ * $Id: $
+ *
+ * Copyright (c) 2005 Intel Corporation. All rights reserved.
+ *
+ **************************************************************************/
+#ifdef RCSID
+static const char rcsid[] = "$Id: $";
+#endif
+
+#include "openib_osd.h"
+#include "dapl.h"
+#include "dapl_adapter_util.h"
+#include "dapl_ib_util.h"
+#include "dapl_osd.h"
+
+#include <stdlib.h>
+
+ib_thread_state_t g_ib_thread_state = 0;
+DAPL_OS_THREAD g_ib_thread;
+DAPL_OS_LOCK g_hca_lock;
+struct dapl_llist_entry *g_hca_list;
+
+void dapli_thread(void *arg);
+DAT_RETURN dapli_ib_thread_init(void);
+void dapli_ib_thread_destroy(void);
+
+#if defined(_WIN64) || defined(_WIN32)
+#include "..\..\..\..\..\etc\user\comp_channel.cpp"
+#include <rdma\winverbs.h>
+
+static COMP_SET ufds;
+
+static int dapls_os_init(void)
+{
+ return CompSetInit(&ufds);
+}
+
+static void dapls_os_release(void)
+{
+ CompSetCleanup(&ufds);
+}
+
+static int dapls_config_verbs(struct ibv_context *verbs)
+{
+ verbs->channel.Milliseconds = 0;
+ return 0;
+}
+
+static int dapls_config_comp_channel(struct ibv_comp_channel *channel)
+{
+ channel->comp_channel.Milliseconds = 0;
+ return 0;
+}
+
+static int dapls_thread_signal(void)
+{
+ CompSetCancel(&ufds);
+ return 0;
+}
+#else // _WIN64 || WIN32
+int g_ib_pipe[2];
+
+static int dapls_os_init(void)
+{
+ /* create pipe for waking up work thread */
+ return pipe(g_ib_pipe);
+}
+
+static void dapls_os_release(void)
+{
+ /* close pipe? */
+}
+
+static int dapls_config_fd(int fd)
+{
+ int opts;
+
+ opts = fcntl(fd, F_GETFL);
+ if (opts < 0 || fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " dapls_config_fd: fcntl on fd %d ERR %d %s\n",
+ fd, opts, strerror(errno));
+ return errno;
+ }
+
+ return 0;
+}
+
+static int dapls_config_verbs(struct ibv_context *verbs)
+{
+ return dapls_config_fd(verbs->async_fd);
+}
+
+static int dapls_config_comp_channel(struct ibv_comp_channel *channel)
+{
+ return dapls_config_fd(channel->fd);
+}
+
+static int dapls_thread_signal(void)
+{
+ return write(g_ib_pipe[1], "w", sizeof "w");
+}
+#endif
+
+
+static int32_t create_cr_pipe(IN DAPL_HCA * hca_ptr)
+{
+ DAPL_SOCKET listen_socket;
+ struct sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+ int ret;
+
+ listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (listen_socket == DAPL_INVALID_SOCKET)
+ return 1;
+
+ memset(&addr, 0, sizeof addr);
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(0x7f000001);
+ ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof addr);
+ if (ret)
+ goto err1;
+
+ ret = getsockname(listen_socket, (struct sockaddr *)&addr, &addrlen);
+ if (ret)
+ goto err1;
+
+ ret = listen(listen_socket, 0);
+ if (ret)
+ goto err1;
+
+ hca_ptr->ib_trans.scm[1] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (hca_ptr->ib_trans.scm[1] == DAPL_INVALID_SOCKET)
+ goto err1;
+
+ ret = connect(hca_ptr->ib_trans.scm[1],
+ (struct sockaddr *)&addr, sizeof(addr));
+ if (ret)
+ goto err2;
+
+ hca_ptr->ib_trans.scm[0] = accept(listen_socket, NULL, NULL);
+ if (hca_ptr->ib_trans.scm[0] == DAPL_INVALID_SOCKET)
+ goto err2;
+
+ closesocket(listen_socket);
+ return 0;
+
+ err2:
+ closesocket(hca_ptr->ib_trans.scm[1]);
+ err1:
+ closesocket(listen_socket);
+ return 1;
+}
+
+static void destroy_cr_pipe(IN DAPL_HCA * hca_ptr)
+{
+ closesocket(hca_ptr->ib_trans.scm[0]);
+ closesocket(hca_ptr->ib_trans.scm[1]);
+}
+
+
+/*
+ * dapls_ib_init, dapls_ib_release
+ *
+ * Initialize Verb related items for device open
+ *
+ * Input:
+ * none
+ *
+ * Output:
+ * none
+ *
+ * Returns:
+ * 0 success, -1 error
+ *
+ */
+int32_t dapls_ib_init(void)
+{
+ /* initialize hca_list */
+ dapl_os_lock_init(&g_hca_lock);
+ dapl_llist_init_head(&g_hca_list);
+
+ if (dapls_os_init())
+ return 1;
+
+ return 0;
+}
+
+int32_t dapls_ib_release(void)
+{
+ dapli_ib_thread_destroy();
+ dapls_os_release();
+ return 0;
+}
+
+/*
+ * dapls_ib_open_hca
+ *
+ * Open HCA
+ *
+ * Input:
+ * *hca_name pointer to provider device name
+ * *ib_hca_handle_p pointer to provide HCA handle
+ *
+ * Output:
+ * none
+ *
+ * Return:
+ * DAT_SUCCESS
+ * dapl_convert_errno
+ *
+ */
+DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr)
+{
+ struct ibv_device **dev_list;
+ struct ibv_port_attr port_attr;
+ int i;
+ DAT_RETURN dat_status;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " open_hca: %s - %p\n", hca_name, hca_ptr);
+
+ /* get the IP address of the device */
+ dat_status = getlocalipaddr((DAT_SOCK_ADDR *) &hca_ptr->hca_address,
+ sizeof(DAT_SOCK_ADDR6));
+ if (dat_status != DAT_SUCCESS)
+ return dat_status;
+
+#ifdef DAPL_DBG
+ /* DBG: unused port, set process id, lower 16 bits of pid */
+ ((struct sockaddr_in *)&hca_ptr->hca_address)->sin_port =
+ htons((uint16_t)dapl_os_getpid());
+#endif
+ /* Get list of all IB devices, find match, open */
+ dev_list = ibv_get_device_list(NULL);
+ if (!dev_list) {
+ dapl_dbg_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: ibv_get_device_list() failed\n",
+ hca_name);
+ return DAT_INTERNAL_ERROR;
+ }
+
+ for (i = 0; dev_list[i]; ++i) {
+ hca_ptr->ib_trans.ib_dev = dev_list[i];
+ if (!strcmp(ibv_get_device_name(hca_ptr->ib_trans.ib_dev),
+ hca_name))
+ goto found;
+ }
+
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: device %s not found\n", hca_name);
+ goto err;
+
+found:
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " open_hca: Found dev %s %016llx\n",
+ ibv_get_device_name(hca_ptr->ib_trans.ib_dev),
+ (unsigned long long)
+ ntohll(ibv_get_device_guid(hca_ptr->ib_trans.ib_dev)));
+
+ hca_ptr->ib_hca_handle = ibv_open_device(hca_ptr->ib_trans.ib_dev);
+ if (!hca_ptr->ib_hca_handle) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: dev open failed for %s, err=%s\n",
+ ibv_get_device_name(hca_ptr->ib_trans.ib_dev),
+ strerror(errno));
+ goto err;
+ }
+ hca_ptr->ib_trans.ib_ctx = hca_ptr->ib_hca_handle;
+ dapls_config_verbs(hca_ptr->ib_hca_handle);
+
+ /* get lid for this hca-port, network order */
+ if (ibv_query_port(hca_ptr->ib_hca_handle,
+ (uint8_t) hca_ptr->port_num, &port_attr)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: get lid ERR for %s, err=%s\n",
+ ibv_get_device_name(hca_ptr->ib_trans.ib_dev),
+ strerror(errno));
+ goto err;
+ } else {
+ hca_ptr->ib_trans.lid = htons(port_attr.lid);
+ }
+
+ /* get gid for this hca-port, network order */
+ if (ibv_query_gid(hca_ptr->ib_hca_handle,
+ (uint8_t) hca_ptr->port_num,
+ 0, &hca_ptr->ib_trans.gid)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: query GID ERR for %s, err=%s\n",
+ ibv_get_device_name(hca_ptr->ib_trans.ib_dev),
+ strerror(errno));
+ goto err;
+ }
+
+ /* set RC tunables via enviroment or default */
+ hca_ptr->ib_trans.max_inline_send =
+ dapl_os_get_env_val("DAPL_MAX_INLINE", INLINE_SEND_DEFAULT);
+ hca_ptr->ib_trans.ack_retry =
+ dapl_os_get_env_val("DAPL_ACK_RETRY", SCM_ACK_RETRY);
+ hca_ptr->ib_trans.ack_timer =
+ dapl_os_get_env_val("DAPL_ACK_TIMER", SCM_ACK_TIMER);
+ hca_ptr->ib_trans.rnr_retry =
+ dapl_os_get_env_val("DAPL_RNR_RETRY", SCM_RNR_RETRY);
+ hca_ptr->ib_trans.rnr_timer =
+ dapl_os_get_env_val("DAPL_RNR_TIMER", SCM_RNR_TIMER);
+ hca_ptr->ib_trans.global =
+ dapl_os_get_env_val("DAPL_GLOBAL_ROUTING", SCM_GLOBAL);
+ hca_ptr->ib_trans.hop_limit =
+ dapl_os_get_env_val("DAPL_HOP_LIMIT", SCM_HOP_LIMIT);
+ hca_ptr->ib_trans.tclass =
+ dapl_os_get_env_val("DAPL_TCLASS", SCM_TCLASS);
+ hca_ptr->ib_trans.mtu =
+ dapl_ib_mtu(dapl_os_get_env_val("DAPL_IB_MTU", SCM_IB_MTU));
+
+
+ /* EVD events without direct CQ channels, CNO support */
+ hca_ptr->ib_trans.ib_cq =
+ ibv_create_comp_channel(hca_ptr->ib_hca_handle);
+ if (hca_ptr->ib_trans.ib_cq == NULL) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: ibv_create_comp_channel ERR %s\n",
+ strerror(errno));
+ goto bail;
+ }
+ dapls_config_comp_channel(hca_ptr->ib_trans.ib_cq);
+
+ dat_status = dapli_ib_thread_init();
+ if (dat_status != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: failed to init cq thread lock\n");
+ goto bail;
+ }
+ /*
+ * Put new hca_transport on list for async and CQ event processing
+ * Wakeup work thread to add to polling list
+ */
+ dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&hca_ptr->ib_trans.entry);
+ dapl_os_lock(&g_hca_lock);
+ dapl_llist_add_tail(&g_hca_list,
+ (DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry,
+ &hca_ptr->ib_trans.entry);
+ if (dapls_thread_signal() == -1)
+ dapl_log(DAPL_DBG_TYPE_UTIL,
+ " open_hca: thread wakeup error = %s\n",
+ strerror(errno));
+ dapl_os_unlock(&g_hca_lock);
+
+ /* initialize cr_list lock */
+ dat_status = dapl_os_lock_init(&hca_ptr->ib_trans.lock);
+ if (dat_status != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: failed to init cr_list lock\n");
+ goto bail;
+ }
+
+ /* initialize CM list for listens on this HCA */
+ dapl_llist_init_head(&hca_ptr->ib_trans.list);
+
+ /* initialize pipe, user level wakeup on select */
+ if (create_cr_pipe(hca_ptr)) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: failed to init cr pipe - %s\n",
+ strerror(errno));
+ goto bail;
+ }
+
+ /* create thread to process inbound connect request */
+ hca_ptr->ib_trans.cr_state = IB_THREAD_INIT;
+ dat_status = dapl_os_thread_create(cr_thread,
+ (void *)hca_ptr,
+ &hca_ptr->ib_trans.thread);
+ if (dat_status != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " open_hca: failed to create thread\n");
+ goto bail;
+ }
+
+ /* wait for thread */
+ while (hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) {
+ dapl_os_sleep_usec(1000);
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " open_hca: devname %s, port %d, hostname_IP %s\n",
+ ibv_get_device_name(hca_ptr->ib_trans.ib_dev),
+ hca_ptr->port_num, inet_ntoa(((struct sockaddr_in *)
+ &hca_ptr->hca_address)->
+ sin_addr));
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " open_hca: LID 0x%x GID Subnet 0x" F64x " ID 0x" F64x
+ "\n", ntohs(hca_ptr->ib_trans.lid), (unsigned long long)
+ htonll(hca_ptr->ib_trans.gid.global.subnet_prefix),
+ (unsigned long long)htonll(hca_ptr->ib_trans.gid.global.
+ interface_id));
+
+ ibv_free_device_list(dev_list);
+ return dat_status;
+
+ bail:
+ ibv_close_device(hca_ptr->ib_hca_handle);
+ hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;
+ err:
+ ibv_free_device_list(dev_list);
+ return DAT_INTERNAL_ERROR;
+}
+
+/*
+ * dapls_ib_close_hca
+ *
+ * Open HCA
+ *
+ * Input:
+ * DAPL_HCA provide CA handle
+ *
+ * Output:
+ * none
+ *
+ * Return:
+ * DAT_SUCCESS
+ * dapl_convert_errno
+ *
+ */
+DAT_RETURN dapls_ib_close_hca(IN DAPL_HCA * hca_ptr)
+{
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " close_hca: %p\n", hca_ptr);
+
+ dapl_os_lock(&g_hca_lock);
+ if (g_ib_thread_state != IB_THREAD_RUN) {
+ dapl_os_unlock(&g_hca_lock);
+ goto out;
+ }
+ dapl_os_unlock(&g_hca_lock);
+
+ /* destroy cr_thread and lock */
+ hca_ptr->ib_trans.cr_state = IB_THREAD_CANCEL;
+ send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0);
+ while (hca_ptr->ib_trans.cr_state != IB_THREAD_EXIT) {
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " close_hca: waiting for cr_thread\n");
+ send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0);
+ dapl_os_sleep_usec(1000);
+ }
+ dapl_os_lock_destroy(&hca_ptr->ib_trans.lock);
+ destroy_cr_pipe(hca_ptr); /* no longer need pipe */
+
+ /*
+ * Remove hca from async event processing list
+ * Wakeup work thread to remove from polling list
+ */
+ hca_ptr->ib_trans.destroy = 1;
+ if (dapls_thread_signal() == -1)
+ dapl_log(DAPL_DBG_TYPE_UTIL,
+ " destroy: thread wakeup error = %s\n",
+ strerror(errno));
+
+ /* wait for thread to remove HCA references */
+ while (hca_ptr->ib_trans.destroy != 2) {
+ if (dapls_thread_signal() == -1)
+ dapl_log(DAPL_DBG_TYPE_UTIL,
+ " destroy: thread wakeup error = %s\n",
+ strerror(errno));
+ dapl_os_sleep_usec(1000);
+ }
+
+out:
+ if (hca_ptr->ib_trans.ib_cq)
+ ibv_destroy_comp_channel(hca_ptr->ib_trans.ib_cq);
+
+ if (hca_ptr->ib_trans.ib_cq_empty) {
+ struct ibv_comp_channel *channel;
+ channel = hca_ptr->ib_trans.ib_cq_empty->channel;
+ ibv_destroy_cq(hca_ptr->ib_trans.ib_cq_empty);
+ ibv_destroy_comp_channel(channel);
+ }
+
+ if (hca_ptr->ib_hca_handle != IB_INVALID_HANDLE) {
+ if (ibv_close_device(hca_ptr->ib_hca_handle))
+ return (dapl_convert_errno(errno, "ib_close_device"));
+ hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;
+ }
+ return (DAT_SUCCESS);
+}
+
+DAT_RETURN dapli_ib_thread_init(void)
+{
+ DAT_RETURN dat_status;
+
+ dapl_os_lock(&g_hca_lock);
+ if (g_ib_thread_state != IB_THREAD_INIT) {
+ dapl_os_unlock(&g_hca_lock);
+ return DAT_SUCCESS;
+ }
+
+ g_ib_thread_state = IB_THREAD_CREATE;
+ dapl_os_unlock(&g_hca_lock);
+
+ /* create thread to process inbound connect request */
+ dat_status = dapl_os_thread_create(dapli_thread, NULL, &g_ib_thread);
+ if (dat_status != DAT_SUCCESS)
+ return (dapl_convert_errno(errno,
+ "create_thread ERR:"
+ " check resource limits"));
+
+ /* wait for thread to start */
+ dapl_os_lock(&g_hca_lock);
+ while (g_ib_thread_state != IB_THREAD_RUN) {
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_init: waiting for ib_thread\n");
+ dapl_os_unlock(&g_hca_lock);
+ dapl_os_sleep_usec(1000);
+ dapl_os_lock(&g_hca_lock);
+ }
+ dapl_os_unlock(&g_hca_lock);
+
+ return DAT_SUCCESS;
+}
+
+void dapli_ib_thread_destroy(void)
+{
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_destroy(%d)\n", dapl_os_getpid());
+ /*
+ * wait for async thread to terminate.
+ * pthread_join would be the correct method
+ * but some applications have some issues
+ */
+
+ /* destroy ib_thread, wait for termination, if not already */
+ dapl_os_lock(&g_hca_lock);
+ if (g_ib_thread_state != IB_THREAD_RUN)
+ goto bail;
+
+ g_ib_thread_state = IB_THREAD_CANCEL;
+ while (g_ib_thread_state != IB_THREAD_EXIT) {
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_destroy: waiting for ib_thread\n");
+ if (dapls_thread_signal() == -1)
+ dapl_log(DAPL_DBG_TYPE_UTIL,
+ " destroy: thread wakeup error = %s\n",
+ strerror(errno));
+ dapl_os_unlock(&g_hca_lock);
+ dapl_os_sleep_usec(2000);
+ dapl_os_lock(&g_hca_lock);
+ }
+bail:
+ dapl_os_unlock(&g_hca_lock);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread_destroy(%d) exit\n", dapl_os_getpid());
+}
+
+
+#if defined(_WIN64) || defined(_WIN32)
+/* work thread for uAT, uCM, CQ, and async events */
+void dapli_thread(void *arg)
+{
+ struct _ib_hca_transport *hca;
+ struct _ib_hca_transport *uhca[8];
+ int ret, idx, cnt;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d,0x%x): ENTER: \n",
+ dapl_os_getpid(), g_ib_thread);
+
+ dapl_os_lock(&g_hca_lock);
+ for (g_ib_thread_state = IB_THREAD_RUN;
+ g_ib_thread_state == IB_THREAD_RUN;
+ dapl_os_lock(&g_hca_lock)) {
+
+ CompSetZero(&ufds);
+ idx = 0;
+ hca = dapl_llist_is_empty(&g_hca_list) ? NULL :
+ dapl_llist_peek_head(&g_hca_list);
+
+ while (hca) {
+ CompSetAdd(&hca->ib_ctx->channel, &ufds);
+ CompSetAdd(&hca->ib_cq->comp_channel, &ufds);
+ uhca[idx++] = hca;
+ hca = dapl_llist_next_entry(&g_hca_list,
+ (DAPL_LLIST_ENTRY *)
+ &hca->entry);
+ }
+ cnt = idx;
+
+ dapl_os_unlock(&g_hca_lock);
+ ret = CompSetPoll(&ufds, INFINITE);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL,
+ " ib_thread(%d) poll_event 0x%x\n",
+ dapl_os_getpid(), ret);
+
+
+ /* check and process ASYNC events, per device */
+ for (idx = 0; idx < cnt; idx++) {
+ if (uhca[idx]->destroy == 1) {
+ dapl_os_lock(&g_hca_lock);
+ dapl_llist_remove_entry(&g_hca_list,
+ (DAPL_LLIST_ENTRY *)
+ &uhca[idx]->entry);
+ dapl_os_unlock(&g_hca_lock);
+ uhca[idx]->destroy = 2;
+ } else {
+ dapli_cq_event_cb(uhca[idx]);
+ dapli_async_event_cb(uhca[idx]);
+ }
+ }
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d) EXIT\n",
+ dapl_os_getpid());
+ g_ib_thread_state = IB_THREAD_EXIT;
+ dapl_os_unlock(&g_hca_lock);
+}
+#else // _WIN64 || WIN32
+
+/* work thread for uAT, uCM, CQ, and async events */
+void dapli_thread(void *arg)
+{
+ struct pollfd ufds[__FD_SETSIZE];
+ struct _ib_hca_transport *uhca[__FD_SETSIZE] = { NULL };
+ struct _ib_hca_transport *hca;
+ int ret, idx, fds;
+ char rbuf[2];
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " ib_thread(%d,0x%x): ENTER: pipe %d \n",
+ dapl_os_getpid(), g_ib_thread, g_ib_pipe[0]);
+
+ /* Poll across pipe, CM, AT never changes */
+ dapl_os_lock(&g_hca_lock);
+ g_ib_thread_state = IB_THREAD_RUN;
+
+ ufds[0].fd = g_ib_pipe[0]; /* pipe */
+ ufds[0].events = POLLIN;
+
+ while (g_ib_thread_state == IB_THREAD_RUN) {
+
+ /* build ufds after pipe and uCMA events */
+ ufds[0].revents = 0;
+ idx = 0;
+
+ /* Walk HCA list and setup async and CQ events */
+ if (!dapl_llist_is_empty(&g_hca_list))
+ hca = dapl_llist_peek_head(&g_hca_list);
+ else
+ hca = NULL;
+
+ while (hca) {
+
+ /* uASYNC events */
+ ufds[++idx].fd = hca->ib_ctx->async_fd;
+ ufds[idx].events = POLLIN;
+ ufds[idx].revents = 0;
+ uhca[idx] = hca;
+
+ /* CQ events are non-direct with CNO's */
+ ufds[++idx].fd = hca->ib_cq->fd;
+ ufds[idx].events = POLLIN;
+ ufds[idx].revents = 0;
+ uhca[idx] = hca;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " ib_thread(%d) poll_fd: hca[%d]=%p,"
+ " async=%d pipe=%d \n",
+ dapl_os_getpid(), hca, ufds[idx - 1].fd,
+ ufds[0].fd);
+
+ hca = dapl_llist_next_entry(&g_hca_list,
+ (DAPL_LLIST_ENTRY *)
+ &hca->entry);
+ }
+
+ /* unlock, and setup poll */
+ fds = idx + 1;
+ dapl_os_unlock(&g_hca_lock);
+ ret = poll(ufds, fds, -1);
+ if (ret <= 0) {
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " ib_thread(%d): ERR %s poll\n",
+ dapl_os_getpid(), strerror(errno));
+ dapl_os_lock(&g_hca_lock);
+ continue;
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD,
+ " ib_thread(%d) poll_event: "
+ " async=0x%x pipe=0x%x \n",
+ dapl_os_getpid(), ufds[idx].revents,
+ ufds[0].revents);
+
+ /* check and process CQ and ASYNC events, per device */
+ for (idx = 1; idx < fds; idx++) {
+ if (ufds[idx].revents == POLLIN) {
+ dapli_cq_event_cb(uhca[idx]);
+ dapli_async_event_cb(uhca[idx]);
+ }
+ }
+
+ /* check and process user events, PIPE */
+ if (ufds[0].revents == POLLIN) {
+ if (read(g_ib_pipe[0], rbuf, 2) == -1)
+ dapl_log(DAPL_DBG_TYPE_THREAD,
+ " cr_thread: pipe rd err= %s\n",
+ strerror(errno));
+
+ /* cleanup any device on list marked for destroy */
+ for (idx = 1; idx < fds; idx++) {
+ if (uhca[idx] && uhca[idx]->destroy == 1) {
+ dapl_os_lock(&g_hca_lock);
+ dapl_llist_remove_entry(
+ &g_hca_list,
+ (DAPL_LLIST_ENTRY*)
+ &uhca[idx]->entry);
+ dapl_os_unlock(&g_hca_lock);
+ uhca[idx]->destroy = 2;
+ }
+ }
+ }
+ dapl_os_lock(&g_hca_lock);
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " ib_thread(%d) EXIT\n",
+ dapl_os_getpid());
+ g_ib_thread_state = IB_THREAD_EXIT;
+ dapl_os_unlock(&g_hca_lock);
+}
+#endif
-/*\r
- * Copyright (c) 2009 Intel Corporation. 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
-#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_osd.h"\r
-\r
-\r
-#if defined(_WIN32)\r
-#include <rdma\winverbs.h>\r
-#else // _WIN32\r
-enum DAPL_FD_EVENTS {\r
- DAPL_FD_READ = POLLIN,\r
- DAPL_FD_WRITE = POLLOUT,\r
- DAPL_FD_ERROR = POLLERR\r
-};\r
-\r
-struct dapl_fd_set {\r
- int index;\r
- struct pollfd set[DAPL_FD_SETSIZE];\r
-};\r
-\r
-static struct dapl_fd_set *dapl_alloc_fd_set(void)\r
-{\r
- return dapl_os_alloc(sizeof(struct dapl_fd_set));\r
-}\r
-\r
-static void dapl_fd_zero(struct dapl_fd_set *set)\r
-{\r
- set->index = 0;\r
-}\r
-\r
-static int dapl_fd_set(DAPL_SOCKET s, struct dapl_fd_set *set,\r
- enum DAPL_FD_EVENTS event)\r
-{\r
- if (set->index == DAPL_FD_SETSIZE - 1) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- "SCM ERR: cm_thread exceeded FD_SETSIZE %d\n",\r
- set->index + 1);\r
- return -1;\r
- }\r
-\r
- set->set[set->index].fd = s;\r
- set->set[set->index].revents = 0;\r
- set->set[set->index++].events = event;\r
- return 0;\r
-}\r
-\r
-static enum DAPL_FD_EVENTS dapl_poll(DAPL_SOCKET s, enum DAPL_FD_EVENTS event)\r
-{\r
- struct pollfd fds;\r
- int ret;\r
-\r
- fds.fd = s;\r
- fds.events = event;\r
- fds.revents = 0;\r
- ret = poll(&fds, 1, 0);\r
- dapl_log(DAPL_DBG_TYPE_CM, " dapl_poll: fd=%d ret=%d, evnts=0x%x\n",\r
- s, ret, fds.revents);\r
- if (ret == 0)\r
- return 0;\r
- else if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) \r
- return DAPL_FD_ERROR;\r
- else \r
- return fds.revents;\r
-}\r
-\r
-static int dapl_select(struct dapl_fd_set *set, int time_ms)\r
-{\r
- int ret;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: sleep, fds=%d\n",\r
- set->index);\r
- ret = poll(set->set, set->index, time_ms);\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: wakeup, ret=0x%x\n", ret);\r
- return ret;\r
-}\r
-#endif\r
-\r
-/* forward declarations */\r
-static int ucm_reply(dp_ib_cm_handle_t cm);\r
-static void ucm_accept(ib_cm_srvc_handle_t cm, ib_cm_msg_t *msg);\r
-static void ucm_connect_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg);\r
-static void ucm_accept_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg);\r
-static int ucm_send(ib_hca_transport_t *tp, ib_cm_msg_t *msg, DAT_PVOID p_data, DAT_COUNT p_size);\r
-static void ucm_disconnect_final(dp_ib_cm_handle_t cm);\r
-DAT_RETURN dapli_cm_disconnect(dp_ib_cm_handle_t cm);\r
-DAT_RETURN dapli_cm_connect(DAPL_EP *ep, dp_ib_cm_handle_t cm);\r
-\r
-#define UCM_SND_BURST 50 \r
-\r
-/* Service ids - port space */\r
-static uint16_t ucm_get_port(ib_hca_transport_t *tp, uint16_t port)\r
-{\r
- int i = 0;\r
- \r
- dapl_os_lock(&tp->plock);\r
- /* get specific ID */\r
- if (port) {\r
- if (tp->sid[port] == 0) {\r
- tp->sid[port] = 1;\r
- i = port;\r
- }\r
- goto done;\r
- } \r
- \r
- /* get any free ID */\r
- for (i = 0xffff; i > 0; i--) {\r
- if (tp->sid[i] == 0) {\r
- tp->sid[i] = 1;\r
- break;\r
- }\r
- }\r
-done:\r
- dapl_os_unlock(&tp->plock);\r
- return i;\r
-}\r
-\r
-static void ucm_free_port(ib_hca_transport_t *tp, uint16_t port)\r
-{\r
- dapl_os_lock(&tp->plock);\r
- tp->sid[port] = 0;\r
- dapl_os_unlock(&tp->plock);\r
-}\r
-\r
-static void ucm_check_timers(dp_ib_cm_handle_t cm, int *timer)\r
-{\r
- DAPL_OS_TIMEVAL time;\r
-\r
- dapl_os_lock(&cm->lock);\r
- dapl_os_get_time(&time); \r
- switch (cm->state) {\r
- case DCM_REP_PENDING: \r
- *timer = cm->hca->ib_trans.cm_timer; \r
- /* wait longer each retry */\r
- if ((time - cm->timer)/1000 > \r
- (cm->hca->ib_trans.rep_time << cm->retries)) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " CM_REQ retry %d [lid, port, qpn]:"\r
- " %x %x %x -> %x %x %x Time(ms) %llu > %llu\n", \r
- cm->retries, ntohs(cm->msg.saddr.ib.lid), \r
- ntohs(cm->msg.sport), ntohl(cm->msg.saddr.ib.qpn), \r
- ntohs(cm->msg.daddr.ib.lid), ntohs(cm->msg.dport),\r
- ntohl(cm->msg.dqpn), (time - cm->timer)/1000, \r
- cm->hca->ib_trans.rep_time << cm->retries);\r
- cm->retries++;\r
- dapl_os_unlock(&cm->lock);\r
- dapli_cm_connect(cm->ep, cm);\r
- return;\r
- }\r
- break;\r
- case DCM_RTU_PENDING: \r
- *timer = cm->hca->ib_trans.cm_timer; \r
- if ((time - cm->timer)/1000 > \r
- (cm->hca->ib_trans.rtu_time << cm->retries)) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " CM_REPLY retry %d [lid, port, qpn]:"\r
- " %x %x %x -> %x %x %x r_pid %x,%d Time(ms) %llu > %llu\n", \r
- cm->retries,\r
- ntohs(cm->msg.saddr.ib.lid), \r
- ntohs(cm->msg.sport),\r
- ntohl(cm->msg.saddr.ib.qpn), \r
- ntohs(cm->msg.daddr.ib.lid), \r
- ntohs(cm->msg.dport),\r
- ntohl(cm->msg.daddr.ib.qpn), \r
- ntohl(*(DAT_UINT32*)cm->msg.resv),\r
- ntohl(*(DAT_UINT32*)cm->msg.resv), \r
- (time - cm->timer)/1000, cm->hca->ib_trans.rtu_time << cm->retries);\r
- cm->retries++;\r
- dapl_os_unlock(&cm->lock);\r
- ucm_reply(cm);\r
- return;\r
- }\r
- break;\r
- case DCM_DISC_PENDING: \r
- *timer = cm->hca->ib_trans.cm_timer; \r
- /* wait longer each retry */\r
- if ((time - cm->timer)/1000 > \r
- (cm->hca->ib_trans.rtu_time << cm->retries)) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " CM_DREQ retry %d [lid, port, qpn]:"\r
- " %x %x %x -> %x %x %x r_pid %x,%d Time(ms) %llu > %llu\n", \r
- cm->retries,\r
- ntohs(cm->msg.saddr.ib.lid), \r
- ntohs(cm->msg.sport),\r
- ntohl(cm->msg.saddr.ib.qpn), \r
- ntohs(cm->msg.daddr.ib.lid), \r
- ntohs(cm->msg.dport),\r
- ntohl(cm->msg.dqpn), \r
- ntohl(*(DAT_UINT32*)cm->msg.resv),\r
- ntohl(*(DAT_UINT32*)cm->msg.resv), \r
- (time - cm->timer)/1000, cm->hca->ib_trans.rtu_time << cm->retries);\r
- cm->retries++;\r
- dapl_os_unlock(&cm->lock);\r
- dapli_cm_disconnect(cm);\r
- return;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
- dapl_os_unlock(&cm->lock);\r
-}\r
-\r
-/* SEND CM MESSAGE PROCESSING */\r
-\r
-/* Get CM UD message from send queue, called with s_lock held */\r
-static ib_cm_msg_t *ucm_get_smsg(ib_hca_transport_t *tp)\r
-{\r
- ib_cm_msg_t *msg = NULL; \r
- int ret, polled = 0, hd = tp->s_hd;\r
-\r
- hd++;\r
-retry:\r
- if (hd == tp->qpe)\r
- hd = 0;\r
-\r
- if (hd == tp->s_tl)\r
- msg = NULL;\r
- else {\r
- msg = &tp->sbuf[hd];\r
- tp->s_hd = hd; /* new hd */\r
- }\r
-\r
- /* if empty, process some completions */\r
- if ((msg == NULL) && (!polled)) {\r
- struct ibv_wc wc;\r
-\r
- /* process completions, based on UCM_SND_BURST */\r
- ret = ibv_poll_cq(tp->scq, 1, &wc);\r
- if (ret < 0) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " get_smsg: cq %p %s\n", \r
- tp->scq, strerror(errno));\r
- }\r
- /* free up completed sends, update tail */\r
- if (ret > 0) {\r
- tp->s_tl = (int)wc.wr_id;\r
- dapl_log(DAPL_DBG_TYPE_CM,\r
- " get_smsg: wr_cmp (%d) s_tl=%d\n", \r
- wc.status, tp->s_tl);\r
- }\r
- polled++;\r
- goto retry;\r
- }\r
- return msg;\r
-}\r
-\r
-/* RECEIVE CM MESSAGE PROCESSING */\r
-\r
-static int ucm_post_rmsg(ib_hca_transport_t *tp, ib_cm_msg_t *msg)\r
-{ \r
- struct ibv_recv_wr recv_wr, *recv_err;\r
- struct ibv_sge sge;\r
- \r
- recv_wr.next = NULL;\r
- recv_wr.sg_list = &sge;\r
- recv_wr.num_sge = 1;\r
- recv_wr.wr_id = (uint64_t)(uintptr_t) msg;\r
- sge.length = sizeof(ib_cm_msg_t) + sizeof(struct ibv_grh);\r
- sge.lkey = tp->mr_rbuf->lkey;\r
- sge.addr = (uintptr_t)((char *)msg - sizeof(struct ibv_grh));\r
- \r
- return (ibv_post_recv(tp->qp, &recv_wr, &recv_err));\r
-}\r
-\r
-static int ucm_reject(ib_hca_transport_t *tp, ib_cm_msg_t *msg)\r
-{\r
- ib_cm_msg_t smsg;\r
-\r
- /* setup op, rearrange the src, dst cm and addr info */\r
- (void)dapl_os_memzero(&smsg, sizeof(smsg));\r
- smsg.ver = htons(DCM_VER);\r
- smsg.op = htons(DCM_REJ_CM);\r
- smsg.dport = msg->sport;\r
- smsg.dqpn = msg->sqpn;\r
- smsg.sport = msg->dport; \r
- smsg.sqpn = msg->dqpn;\r
-\r
- dapl_os_memcpy(&smsg.daddr, &msg->saddr, sizeof(union dcm_addr));\r
- \r
- /* no dst_addr IB info in REQ, init lid, gid, get type from saddr */\r
- smsg.saddr.ib.lid = tp->addr.ib.lid; \r
- smsg.saddr.ib.qp_type = msg->saddr.ib.qp_type;\r
- dapl_os_memcpy(&smsg.saddr.ib.gid[0],\r
- &tp->addr.ib.gid, 16); \r
-\r
- dapl_os_memcpy(&smsg.saddr, &msg->daddr, sizeof(union dcm_addr));\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, \r
- " CM reject -> LID %x, QPN %x PORT %d\n", \r
- ntohs(smsg.daddr.ib.lid),\r
- ntohl(smsg.dqpn), ntohs(smsg.dport));\r
-\r
- return (ucm_send(tp, &smsg, NULL, 0));\r
-}\r
-\r
-static void ucm_process_recv(ib_hca_transport_t *tp, \r
- ib_cm_msg_t *msg, \r
- dp_ib_cm_handle_t cm)\r
-{\r
- dapl_os_lock(&cm->lock);\r
- switch (cm->state) {\r
- case DCM_LISTEN: /* passive */\r
- dapl_os_unlock(&cm->lock);\r
- ucm_accept(cm, msg);\r
- break;\r
- case DCM_RTU_PENDING: /* passive */\r
- dapl_os_unlock(&cm->lock);\r
- ucm_accept_rtu(cm, msg);\r
- break;\r
- case DCM_REP_PENDING: /* active */\r
- dapl_os_unlock(&cm->lock);\r
- ucm_connect_rtu(cm, msg);\r
- break;\r
- case DCM_CONNECTED: /* active and passive */\r
- /* DREQ, change state and process */\r
- if (ntohs(msg->op) == DCM_DREQ) {\r
- cm->state = DCM_DISC_RECV;\r
- dapl_os_unlock(&cm->lock);\r
- dapli_cm_disconnect(cm);\r
- break;\r
- } \r
- /* active: RTU was dropped, resend */\r
- if (ntohs(msg->op) == DCM_REP) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " RESEND RTU: op %s st %s [lid, port, qpn]:"\r
- " 0x%x %d 0x%x -> 0x%x %d 0x%x\n", \r
- dapl_cm_op_str(ntohs(msg->op)), \r
- dapl_cm_state_str(cm->state),\r
- ntohs(msg->saddr.ib.lid), \r
- ntohs(msg->sport),\r
- ntohl(msg->saddr.ib.qpn), \r
- ntohs(msg->daddr.ib.lid), \r
- ntohs(msg->dport),\r
- ntohl(msg->daddr.ib.qpn)); \r
-\r
- cm->msg.op = htons(DCM_RTU);\r
- ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0); \r
- }\r
- dapl_os_unlock(&cm->lock);\r
- break;\r
- case DCM_DISC_PENDING: /* active and passive */\r
- /* DREQ or DREP, finalize */\r
- dapl_os_unlock(&cm->lock);\r
- ucm_disconnect_final(cm);\r
- break;\r
- case DCM_DISCONNECTED:\r
- case DCM_DESTROY:\r
- /* DREQ dropped, resend */\r
- if (ntohs(msg->op) == DCM_DREQ) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " RESEND DREP: op %s st %s [lid, port, qpn]:"\r
- " 0x%x %d 0x%x -> 0x%x %d 0x%x\n", \r
- dapl_cm_op_str(ntohs(msg->op)), \r
- dapl_cm_state_str(cm->state),\r
- ntohs(msg->saddr.ib.lid), \r
- ntohs(msg->sport),\r
- ntohl(msg->saddr.ib.qpn), \r
- ntohs(msg->daddr.ib.lid), \r
- ntohs(msg->dport),\r
- ntohl(msg->daddr.ib.qpn)); \r
- cm->msg.op = htons(DCM_DREP);\r
- ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0); \r
- \r
- }\r
- dapl_os_unlock(&cm->lock);\r
- break;\r
- case DCM_RELEASED:\r
- /* UD reply retried, ignore */\r
- if (ntohs(msg->op) != DCM_REP) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " ucm_recv: UNKNOWN operation"\r
- " <- op %d, %s spsp %d sqpn %d\n", \r
- ntohs(msg->op), dapl_cm_state_str(cm->state),\r
- ntohs(msg->sport), ntohl(msg->sqpn));\r
- }\r
- dapl_os_unlock(&cm->lock);\r
- break;\r
- default:\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " ucm_recv: UNKNOWN state"\r
- " <- op %d, %s spsp %d sqpn %d\n", \r
- ntohs(msg->op), dapl_cm_state_str(cm->state), \r
- ntohs(msg->sport), ntohl(msg->sqpn));\r
- dapl_os_unlock(&cm->lock);\r
- break;\r
- }\r
-}\r
-\r
-/* Find matching CM object for this receive message, return CM reference, timer */\r
-dp_ib_cm_handle_t ucm_cm_find(ib_hca_transport_t *tp, ib_cm_msg_t *msg)\r
-{\r
- dp_ib_cm_handle_t cm, next, found = NULL;\r
- struct dapl_llist_entry **list;\r
- DAPL_OS_LOCK *lock;\r
- int listenq = 0;\r
-\r
- /* conn list first, duplicate requests for DCM_REQ */\r
- list = &tp->list;\r
- lock = &tp->lock;\r
-\r
-retry_listenq:\r
- dapl_os_lock(lock);\r
- if (!dapl_llist_is_empty(list))\r
- next = dapl_llist_peek_head(list);\r
- else\r
- next = NULL;\r
-\r
- while (next) {\r
- cm = next;\r
- next = dapl_llist_next_entry(list,\r
- (DAPL_LLIST_ENTRY *)&cm->entry);\r
- if (cm->state == DCM_DESTROY)\r
- continue;\r
- \r
- /* CM sPORT + QPN, match is good enough for listenq */\r
- if (listenq && \r
- cm->msg.sport == msg->dport && \r
- cm->msg.sqpn == msg->dqpn) {\r
- found = cm;\r
- break;\r
- } \r
- /* connectq, check src and dst, check duplicate conn_reqs */\r
- if (!listenq && \r
- cm->msg.sport == msg->dport && cm->msg.sqpn == msg->dqpn && \r
- cm->msg.dport == msg->sport && cm->msg.dqpn == msg->sqpn && \r
- cm->msg.daddr.ib.lid == msg->saddr.ib.lid) {\r
- if (ntohs(msg->op) != DCM_REQ) {\r
- found = cm;\r
- break; \r
- } else {\r
- /* duplicate; bail and throw away */\r
- dapl_os_unlock(lock);\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " DUPLICATE: op %s st %s [lid, port, qpn]:"\r
- " 0x%x %d 0x%x <- 0x%x %d 0x%x\n", \r
- dapl_cm_op_str(ntohs(msg->op)), \r
- dapl_cm_state_str(cm->state),\r
- ntohs(msg->daddr.ib.lid), \r
- ntohs(msg->dport),\r
- ntohl(msg->daddr.ib.qpn), \r
- ntohs(msg->saddr.ib.lid), \r
- ntohs(msg->sport),\r
- ntohl(msg->saddr.ib.qpn)); \r
- return NULL;\r
- }\r
- }\r
- }\r
- dapl_os_unlock(lock);\r
-\r
- /* no duplicate request on connq, check listenq for new request */\r
- if (ntohs(msg->op) == DCM_REQ && !listenq && !found) {\r
- listenq = 1;\r
- list = &tp->llist;\r
- lock = &tp->llock;\r
- goto retry_listenq;\r
- }\r
-\r
- /* not match on listenq for valid request, send reject */\r
- if (ntohs(msg->op) == DCM_REQ && !found)\r
- ucm_reject(tp, msg);\r
-\r
- if (!found) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " ucm_recv: NO MATCH op %s 0x%x %d i0x%x c0x%x"\r
- " < 0x%x %d 0x%x\n", \r
- dapl_cm_op_str(ntohs(msg->op)), \r
- ntohs(msg->daddr.ib.lid), ntohs(msg->dport), \r
- ntohl(msg->daddr.ib.qpn), ntohl(msg->sqpn),\r
- ntohs(msg->saddr.ib.lid), ntohs(msg->sport), \r
- ntohl(msg->saddr.ib.qpn));\r
- }\r
-\r
- return found;\r
-}\r
-\r
-/* Get rmsgs from CM completion queue, 10 at a time */\r
-static void ucm_recv(ib_hca_transport_t *tp)\r
-{\r
- struct ibv_wc wc[10];\r
- ib_cm_msg_t *msg;\r
- dp_ib_cm_handle_t cm;\r
- int i, ret, notify = 0;\r
- struct ibv_cq *ibv_cq = NULL;\r
- DAPL_HCA *hca;\r
-\r
- /* POLLIN on channel FD */\r
- ret = ibv_get_cq_event(tp->rch, &ibv_cq, (void *)&hca);\r
- if (ret == 0) {\r
- ibv_ack_cq_events(ibv_cq, 1);\r
- }\r
-retry: \r
- ret = ibv_poll_cq(tp->rcq, 10, wc);\r
- if (ret <= 0) {\r
- if (!ret && !notify) {\r
- ibv_req_notify_cq(tp->rcq, 0);\r
- notify = 1;\r
- goto retry;\r
- }\r
- return;\r
- } else \r
- notify = 0;\r
- \r
- for (i = 0; i < ret; i++) {\r
- msg = (ib_cm_msg_t*) (uintptr_t) wc[i].wr_id;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, \r
- " ucm_recv: wc status=%d, ln=%d id=%p sqp=%x\n", \r
- wc[i].status, wc[i].byte_len, \r
- (void*)wc[i].wr_id, wc[i].src_qp);\r
-\r
- /* validate CM message, version */\r
- if (ntohs(msg->ver) != DCM_VER) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " ucm_recv: UNKNOWN msg %p, ver %d\n", \r
- msg, msg->ver);\r
- ucm_post_rmsg(tp, msg);\r
- continue;\r
- }\r
- if (!(cm = ucm_cm_find(tp, msg))) {\r
- ucm_post_rmsg(tp, msg);\r
- continue;\r
- }\r
- \r
- /* match, process it */\r
- ucm_process_recv(tp, msg, cm);\r
- ucm_post_rmsg(tp, msg);\r
- }\r
- \r
- /* finished this batch of WC's, poll and rearm */\r
- goto retry;\r
-}\r
-\r
-/* ACTIVE/PASSIVE: build and send CM message out of CM object */\r
-static int ucm_send(ib_hca_transport_t *tp, ib_cm_msg_t *msg, DAT_PVOID p_data, DAT_COUNT p_size)\r
-{\r
- ib_cm_msg_t *smsg = NULL;\r
- struct ibv_send_wr wr, *bad_wr;\r
- struct ibv_sge sge;\r
- int len, ret = -1;\r
- uint16_t dlid = ntohs(msg->daddr.ib.lid);\r
-\r
- /* Get message from send queue, copy data, and send */\r
- dapl_os_lock(&tp->slock);\r
- if ((smsg = ucm_get_smsg(tp)) == NULL)\r
- goto bail;\r
-\r
- len = (sizeof(*msg) - DCM_MAX_PDATA_SIZE);\r
- dapl_os_memcpy(smsg, msg, len);\r
- if (p_size) {\r
- smsg->p_size = ntohs(p_size);\r
- dapl_os_memcpy(&smsg->p_data, p_data, p_size);\r
- }\r
-\r
- wr.next = NULL;\r
- wr.sg_list = &sge;\r
- wr.num_sge = 1;\r
- wr.opcode = IBV_WR_SEND;\r
- wr.wr_id = (unsigned long)tp->s_hd;\r
- wr.send_flags = (wr.wr_id % UCM_SND_BURST) ? 0 : IBV_SEND_SIGNALED;\r
- if (len <= tp->max_inline_send)\r
- wr.send_flags |= IBV_SEND_INLINE; \r
-\r
- sge.length = len + p_size;\r
- sge.lkey = tp->mr_sbuf->lkey;\r
- sge.addr = (uintptr_t)smsg;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, \r
- " ucm_send: op %d ln %d lid %x c_qpn %x rport %d\n", \r
- ntohs(smsg->op), sge.length, htons(smsg->daddr.ib.lid), \r
- htonl(smsg->dqpn), htons(smsg->dport));\r
-\r
- /* empty slot, then create AH */\r
- if (!tp->ah[dlid]) {\r
- tp->ah[dlid] = \r
- dapls_create_ah(tp->hca, tp->pd, tp->qp, \r
- htons(dlid), NULL);\r
- if (!tp->ah[dlid])\r
- goto bail;\r
- }\r
- \r
- wr.wr.ud.ah = tp->ah[dlid];\r
- wr.wr.ud.remote_qpn = ntohl(smsg->dqpn);\r
- wr.wr.ud.remote_qkey = DAT_UD_QKEY;\r
-\r
- ret = ibv_post_send(tp->qp, &wr, &bad_wr);\r
-bail:\r
- dapl_os_unlock(&tp->slock); \r
- return ret;\r
-}\r
-\r
-/* ACTIVE/PASSIVE: CM objects */\r
-dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep)\r
-{\r
- dp_ib_cm_handle_t cm;\r
-\r
- /* Allocate CM, init lock, and initialize */\r
- if ((cm = dapl_os_alloc(sizeof(*cm))) == NULL)\r
- return NULL;\r
-\r
- (void)dapl_os_memzero(cm, sizeof(*cm));\r
- if (dapl_os_lock_init(&cm->lock))\r
- goto bail;\r
-\r
- cm->msg.ver = htons(DCM_VER);\r
- *(DAT_UINT32*)cm->msg.resv = htonl(dapl_os_getpid()); /* exchange PID for debugging */\r
- \r
- /* ACTIVE: init source address QP info from local EP */\r
- if (ep) {\r
- DAPL_HCA *hca = ep->header.owner_ia->hca_ptr;\r
-\r
- cm->msg.sport = htons(ucm_get_port(&hca->ib_trans, 0));\r
- if (!cm->msg.sport) \r
- goto bail;\r
-\r
- /* IB info in network order */\r
- cm->ep = ep;\r
- cm->hca = hca;\r
- cm->msg.sqpn = htonl(hca->ib_trans.qp->qp_num); /* ucm */\r
- cm->msg.saddr.ib.qpn = htonl(ep->qp_handle->qp_num); /* ep */\r
- cm->msg.saddr.ib.qp_type = ep->qp_handle->qp_type;\r
- cm->msg.saddr.ib.lid = hca->ib_trans.addr.ib.lid; \r
- dapl_os_memcpy(&cm->msg.saddr.ib.gid[0], \r
- &hca->ib_trans.addr.ib.gid, 16);\r
- }\r
- return cm;\r
-bail:\r
- dapl_os_free(cm, sizeof(*cm));\r
- return NULL;\r
-}\r
-\r
-/* \r
- * UD CR objects are kept active because of direct private data references\r
- * from CONN events. The cr->socket is closed and marked inactive but the \r
- * object remains allocated and queued on the CR resource list. There can\r
- * be multiple CR's associated with a given EP. There is no way to determine \r
- * when consumer is finished with event until the dat_ep_free.\r
- *\r
- * Schedule destruction for all CR's associated with this EP, cr_thread will\r
- * complete the cleanup with state == DCM_DESTROY. \r
- */ \r
-static void ucm_ud_free(DAPL_EP *ep)\r
-{\r
- DAPL_IA *ia = ep->header.owner_ia;\r
- DAPL_HCA *hca = NULL;\r
- ib_hca_transport_t *tp = &ia->hca_ptr->ib_trans;\r
- dp_ib_cm_handle_t cm, next;\r
-\r
- dapl_os_lock(&tp->lock);\r
- if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)&tp->list))\r
- next = dapl_llist_peek_head((DAPL_LLIST_HEAD*)&tp->list);\r
- else\r
- next = NULL;\r
-\r
- while (next) {\r
- cm = next;\r
- next = dapl_llist_next_entry((DAPL_LLIST_HEAD*)&tp->list,\r
- (DAPL_LLIST_ENTRY*)&cm->entry);\r
- if (cm->ep == ep) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " qp_free CM: ep %p cm %p\n", ep, cm);\r
- dapl_os_lock(&cm->lock);\r
- hca = cm->hca;\r
- cm->ep = NULL;\r
- if (cm->ah) {\r
- ibv_destroy_ah(cm->ah);\r
- cm->ah = NULL;\r
- }\r
- cm->state = DCM_DESTROY;\r
- dapl_os_unlock(&cm->lock);\r
- }\r
- }\r
- dapl_os_unlock(&tp->lock);\r
-\r
- /* wakeup work thread if necessary */\r
- if (hca)\r
- dapls_thread_signal(&tp->signal);\r
-}\r
-\r
-/* mark for destroy, remove all references, schedule cleanup */\r
-/* cm_ptr == NULL (UD), then multi CR's, kill all associated with EP */\r
-void dapls_ib_cm_free(dp_ib_cm_handle_t cm, DAPL_EP *ep)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " cm_destroy: %s cm %p ep %p\n",\r
- cm ? dapl_cm_state_str(cm->state) : "", cm, ep);\r
-\r
- if (!cm && ep) {\r
- ucm_ud_free(ep);\r
+/*
+ * Copyright (c) 2009 Intel Corporation. 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.
+ */
+
+#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_ep_util.h"
+#include "dapl_osd.h"
+
+
+#if defined(_WIN32)
+#include <rdma\winverbs.h>
+#else // _WIN32
+enum DAPL_FD_EVENTS {
+ DAPL_FD_READ = POLLIN,
+ DAPL_FD_WRITE = POLLOUT,
+ DAPL_FD_ERROR = POLLERR
+};
+
+struct dapl_fd_set {
+ int index;
+ struct pollfd set[DAPL_FD_SETSIZE];
+};
+
+static struct dapl_fd_set *dapl_alloc_fd_set(void)
+{
+ return dapl_os_alloc(sizeof(struct dapl_fd_set));
+}
+
+static void dapl_fd_zero(struct dapl_fd_set *set)
+{
+ set->index = 0;
+}
+
+static int dapl_fd_set(DAPL_SOCKET s, struct dapl_fd_set *set,
+ enum DAPL_FD_EVENTS event)
+{
+ if (set->index == DAPL_FD_SETSIZE - 1) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ "SCM ERR: cm_thread exceeded FD_SETSIZE %d\n",
+ set->index + 1);
+ return -1;
+ }
+
+ set->set[set->index].fd = s;
+ set->set[set->index].revents = 0;
+ set->set[set->index++].events = event;
+ return 0;
+}
+
+static enum DAPL_FD_EVENTS dapl_poll(DAPL_SOCKET s, enum DAPL_FD_EVENTS event)
+{
+ struct pollfd fds;
+ int ret;
+
+ fds.fd = s;
+ fds.events = event;
+ fds.revents = 0;
+ ret = poll(&fds, 1, 0);
+ dapl_log(DAPL_DBG_TYPE_CM, " dapl_poll: fd=%d ret=%d, evnts=0x%x\n",
+ s, ret, fds.revents);
+ if (ret == 0)
+ return 0;
+ else if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
+ return DAPL_FD_ERROR;
+ else
+ return fds.revents;
+}
+
+static int dapl_select(struct dapl_fd_set *set, int time_ms)
+{
+ int ret;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: sleep, fds=%d\n",
+ set->index);
+ ret = poll(set->set, set->index, time_ms);
+ dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: wakeup, ret=0x%x\n", ret);
+ return ret;
+}
+#endif
+
+/* forward declarations */
+static int ucm_reply(dp_ib_cm_handle_t cm);
+static void ucm_accept(ib_cm_srvc_handle_t cm, ib_cm_msg_t *msg);
+static void ucm_connect_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg);
+static void ucm_accept_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg);
+static int ucm_send(ib_hca_transport_t *tp, ib_cm_msg_t *msg, DAT_PVOID p_data, DAT_COUNT p_size);
+static void ucm_disconnect_final(dp_ib_cm_handle_t cm);
+DAT_RETURN dapli_cm_disconnect(dp_ib_cm_handle_t cm);
+DAT_RETURN dapli_cm_connect(DAPL_EP *ep, dp_ib_cm_handle_t cm);
+
+#define UCM_SND_BURST 50
+
+/* Service ids - port space */
+static uint16_t ucm_get_port(ib_hca_transport_t *tp, uint16_t port)
+{
+ int i = 0;
+
+ dapl_os_lock(&tp->plock);
+ /* get specific ID */
+ if (port) {
+ if (tp->sid[port] == 0) {
+ tp->sid[port] = 1;
+ i = port;
+ }
+ goto done;
+ }
+
+ /* get any free ID */
+ for (i = 0xffff; i > 0; i--) {
+ if (tp->sid[i] == 0) {
+ tp->sid[i] = 1;
+ break;
+ }
+ }
+done:
+ dapl_os_unlock(&tp->plock);
+ return i;
+}
+
+static void ucm_free_port(ib_hca_transport_t *tp, uint16_t port)
+{
+ dapl_os_lock(&tp->plock);
+ tp->sid[port] = 0;
+ dapl_os_unlock(&tp->plock);
+}
+
+static void ucm_check_timers(dp_ib_cm_handle_t cm, int *timer)
+{
+ DAPL_OS_TIMEVAL time;
+
+ dapl_os_lock(&cm->lock);
+ dapl_os_get_time(&time);
+ switch (cm->state) {
+ case DCM_REP_PENDING:
+ *timer = cm->hca->ib_trans.cm_timer;
+ /* wait longer each retry */
+ if ((time - cm->timer)/1000 >
+ (cm->hca->ib_trans.rep_time << cm->retries)) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " CM_REQ retry %d [lid, port, qpn]:"
+ " %x %x %x -> %x %x %x Time(ms) %llu > %llu\n",
+ cm->retries, ntohs(cm->msg.saddr.ib.lid),
+ ntohs(cm->msg.sport), ntohl(cm->msg.saddr.ib.qpn),
+ ntohs(cm->msg.daddr.ib.lid), ntohs(cm->msg.dport),
+ ntohl(cm->msg.dqpn), (time - cm->timer)/1000,
+ cm->hca->ib_trans.rep_time << cm->retries);
+ cm->retries++;
+ dapl_os_unlock(&cm->lock);
+ dapli_cm_connect(cm->ep, cm);
+ return;
+ }
+ break;
+ case DCM_RTU_PENDING:
+ *timer = cm->hca->ib_trans.cm_timer;
+ if ((time - cm->timer)/1000 >
+ (cm->hca->ib_trans.rtu_time << cm->retries)) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " CM_REPLY retry %d [lid, port, qpn]:"
+ " %x %x %x -> %x %x %x r_pid %x,%d Time(ms) %llu > %llu\n",
+ cm->retries,
+ ntohs(cm->msg.saddr.ib.lid),
+ ntohs(cm->msg.sport),
+ ntohl(cm->msg.saddr.ib.qpn),
+ ntohs(cm->msg.daddr.ib.lid),
+ ntohs(cm->msg.dport),
+ ntohl(cm->msg.daddr.ib.qpn),
+ ntohl(*(DAT_UINT32*)cm->msg.resv),
+ ntohl(*(DAT_UINT32*)cm->msg.resv),
+ (time - cm->timer)/1000, cm->hca->ib_trans.rtu_time << cm->retries);
+ cm->retries++;
+ dapl_os_unlock(&cm->lock);
+ ucm_reply(cm);
+ return;
+ }
+ break;
+ case DCM_DISC_PENDING:
+ *timer = cm->hca->ib_trans.cm_timer;
+ /* wait longer each retry */
+ if ((time - cm->timer)/1000 >
+ (cm->hca->ib_trans.rtu_time << cm->retries)) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " CM_DREQ retry %d [lid, port, qpn]:"
+ " %x %x %x -> %x %x %x r_pid %x,%d Time(ms) %llu > %llu\n",
+ cm->retries,
+ ntohs(cm->msg.saddr.ib.lid),
+ ntohs(cm->msg.sport),
+ ntohl(cm->msg.saddr.ib.qpn),
+ ntohs(cm->msg.daddr.ib.lid),
+ ntohs(cm->msg.dport),
+ ntohl(cm->msg.dqpn),
+ ntohl(*(DAT_UINT32*)cm->msg.resv),
+ ntohl(*(DAT_UINT32*)cm->msg.resv),
+ (time - cm->timer)/1000, cm->hca->ib_trans.rtu_time << cm->retries);
+ cm->retries++;
+ dapl_os_unlock(&cm->lock);
+ dapli_cm_disconnect(cm);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ dapl_os_unlock(&cm->lock);
+}
+
+/* SEND CM MESSAGE PROCESSING */
+
+/* Get CM UD message from send queue, called with s_lock held */
+static ib_cm_msg_t *ucm_get_smsg(ib_hca_transport_t *tp)
+{
+ ib_cm_msg_t *msg = NULL;
+ int ret, polled = 0, hd = tp->s_hd;
+
+ hd++;
+retry:
+ if (hd == tp->qpe)
+ hd = 0;
+
+ if (hd == tp->s_tl)
+ msg = NULL;
+ else {
+ msg = &tp->sbuf[hd];
+ tp->s_hd = hd; /* new hd */
+ }
+
+ /* if empty, process some completions */
+ if ((msg == NULL) && (!polled)) {
+ struct ibv_wc wc;
+
+ /* process completions, based on UCM_SND_BURST */
+ ret = ibv_poll_cq(tp->scq, 1, &wc);
+ if (ret < 0) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " get_smsg: cq %p %s\n",
+ tp->scq, strerror(errno));
+ }
+ /* free up completed sends, update tail */
+ if (ret > 0) {
+ tp->s_tl = (int)wc.wr_id;
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " get_smsg: wr_cmp (%d) s_tl=%d\n",
+ wc.status, tp->s_tl);
+ }
+ polled++;
+ goto retry;
+ }
+ return msg;
+}
+
+/* RECEIVE CM MESSAGE PROCESSING */
+
+static int ucm_post_rmsg(ib_hca_transport_t *tp, ib_cm_msg_t *msg)
+{
+ struct ibv_recv_wr recv_wr, *recv_err;
+ struct ibv_sge sge;
+
+ recv_wr.next = NULL;
+ recv_wr.sg_list = &sge;
+ recv_wr.num_sge = 1;
+ recv_wr.wr_id = (uint64_t)(uintptr_t) msg;
+ sge.length = sizeof(ib_cm_msg_t) + sizeof(struct ibv_grh);
+ sge.lkey = tp->mr_rbuf->lkey;
+ sge.addr = (uintptr_t)((char *)msg - sizeof(struct ibv_grh));
+
+ return (ibv_post_recv(tp->qp, &recv_wr, &recv_err));
+}
+
+static int ucm_reject(ib_hca_transport_t *tp, ib_cm_msg_t *msg)
+{
+ ib_cm_msg_t smsg;
+
+ /* setup op, rearrange the src, dst cm and addr info */
+ (void)dapl_os_memzero(&smsg, sizeof(smsg));
+ smsg.ver = htons(DCM_VER);
+ smsg.op = htons(DCM_REJ_CM);
+ smsg.dport = msg->sport;
+ smsg.dqpn = msg->sqpn;
+ smsg.sport = msg->dport;
+ smsg.sqpn = msg->dqpn;
+
+ dapl_os_memcpy(&smsg.daddr, &msg->saddr, sizeof(union dcm_addr));
+
+ /* no dst_addr IB info in REQ, init lid, gid, get type from saddr */
+ smsg.saddr.ib.lid = tp->addr.ib.lid;
+ smsg.saddr.ib.qp_type = msg->saddr.ib.qp_type;
+ dapl_os_memcpy(&smsg.saddr.ib.gid[0],
+ &tp->addr.ib.gid, 16);
+
+ dapl_os_memcpy(&smsg.saddr, &msg->daddr, sizeof(union dcm_addr));
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " CM reject -> LID %x, QPN %x PORT %d\n",
+ ntohs(smsg.daddr.ib.lid),
+ ntohl(smsg.dqpn), ntohs(smsg.dport));
+
+ return (ucm_send(tp, &smsg, NULL, 0));
+}
+
+static void ucm_process_recv(ib_hca_transport_t *tp,
+ ib_cm_msg_t *msg,
+ dp_ib_cm_handle_t cm)
+{
+ dapl_os_lock(&cm->lock);
+ switch (cm->state) {
+ case DCM_LISTEN: /* passive */
+ dapl_os_unlock(&cm->lock);
+ ucm_accept(cm, msg);
+ break;
+ case DCM_RTU_PENDING: /* passive */
+ dapl_os_unlock(&cm->lock);
+ ucm_accept_rtu(cm, msg);
+ break;
+ case DCM_REP_PENDING: /* active */
+ dapl_os_unlock(&cm->lock);
+ ucm_connect_rtu(cm, msg);
+ break;
+ case DCM_CONNECTED: /* active and passive */
+ /* DREQ, change state and process */
+ if (ntohs(msg->op) == DCM_DREQ) {
+ cm->state = DCM_DISC_RECV;
+ dapl_os_unlock(&cm->lock);
+ dapli_cm_disconnect(cm);
+ break;
+ }
+ /* active: RTU was dropped, resend */
+ if (ntohs(msg->op) == DCM_REP) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " RESEND RTU: op %s st %s [lid, port, qpn]:"
+ " 0x%x %d 0x%x -> 0x%x %d 0x%x\n",
+ dapl_cm_op_str(ntohs(msg->op)),
+ dapl_cm_state_str(cm->state),
+ ntohs(msg->saddr.ib.lid),
+ ntohs(msg->sport),
+ ntohl(msg->saddr.ib.qpn),
+ ntohs(msg->daddr.ib.lid),
+ ntohs(msg->dport),
+ ntohl(msg->daddr.ib.qpn));
+
+ cm->msg.op = htons(DCM_RTU);
+ ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0);
+ }
+ dapl_os_unlock(&cm->lock);
+ break;
+ case DCM_DISC_PENDING: /* active and passive */
+ /* DREQ or DREP, finalize */
+ dapl_os_unlock(&cm->lock);
+ ucm_disconnect_final(cm);
+ break;
+ case DCM_DISCONNECTED:
+ case DCM_FREE:
+ /* DREQ dropped, resend */
+ if (ntohs(msg->op) == DCM_DREQ) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " RESEND DREP: op %s st %s [lid, port, qpn]:"
+ " 0x%x %d 0x%x -> 0x%x %d 0x%x\n",
+ dapl_cm_op_str(ntohs(msg->op)),
+ dapl_cm_state_str(cm->state),
+ ntohs(msg->saddr.ib.lid),
+ ntohs(msg->sport),
+ ntohl(msg->saddr.ib.qpn),
+ ntohs(msg->daddr.ib.lid),
+ ntohs(msg->dport),
+ ntohl(msg->daddr.ib.qpn));
+ cm->msg.op = htons(DCM_DREP);
+ ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0);
+
+ }
+ /* UD reply retried ok to ignore, any other print warning */
+ if (ntohs(msg->op) != DCM_REP) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " ucm_recv: UNKNOWN operation"
+ " <- op %d, %s spsp %d sqpn %d\n",
+ ntohs(msg->op), dapl_cm_state_str(cm->state),
+ ntohs(msg->sport), ntohl(msg->sqpn));
+ }
+ dapl_os_unlock(&cm->lock);
+ break;
+ default:
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " ucm_recv: UNKNOWN state"
+ " <- op %d, %s spsp %d sqpn %d\n",
+ ntohs(msg->op), dapl_cm_state_str(cm->state),
+ ntohs(msg->sport), ntohl(msg->sqpn));
+ dapl_os_unlock(&cm->lock);
+ break;
+ }
+}
+
+/* Find matching CM object for this receive message, return CM reference, timer */
+dp_ib_cm_handle_t ucm_cm_find(ib_hca_transport_t *tp, ib_cm_msg_t *msg)
+{
+ dp_ib_cm_handle_t cm, next, found = NULL;
+ struct dapl_llist_entry **list;
+ DAPL_OS_LOCK *lock;
+ int listenq = 0;
+
+ /* conn list first, duplicate requests for DCM_REQ */
+ list = &tp->list;
+ lock = &tp->lock;
+
+retry_listenq:
+ dapl_os_lock(lock);
+ if (!dapl_llist_is_empty(list))
+ next = dapl_llist_peek_head(list);
+ else
+ next = NULL;
+
+ while (next) {
+ cm = next;
+ next = dapl_llist_next_entry(list,
+ (DAPL_LLIST_ENTRY *)&cm->local_entry);
+ if (cm->state == DCM_DESTROY || cm->state == DCM_FREE)
+ continue;
+
+ /* CM sPORT + QPN, match is good enough for listenq */
+ if (listenq &&
+ cm->msg.sport == msg->dport &&
+ cm->msg.sqpn == msg->dqpn) {
+ found = cm;
+ break;
+ }
+ /* connectq, check src and dst, check duplicate conn_reqs */
+ if (!listenq &&
+ cm->msg.sport == msg->dport && cm->msg.sqpn == msg->dqpn &&
+ cm->msg.dport == msg->sport && cm->msg.dqpn == msg->sqpn &&
+ cm->msg.daddr.ib.lid == msg->saddr.ib.lid) {
+ if (ntohs(msg->op) != DCM_REQ) {
+ found = cm;
+ break;
+ } else {
+ /* duplicate; bail and throw away */
+ dapl_os_unlock(lock);
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " DUPLICATE: op %s st %s [lid, port, qpn]:"
+ " 0x%x %d 0x%x <- 0x%x %d 0x%x\n",
+ dapl_cm_op_str(ntohs(msg->op)),
+ dapl_cm_state_str(cm->state),
+ ntohs(msg->daddr.ib.lid),
+ ntohs(msg->dport),
+ ntohl(msg->daddr.ib.qpn),
+ ntohs(msg->saddr.ib.lid),
+ ntohs(msg->sport),
+ ntohl(msg->saddr.ib.qpn));
+ return NULL;
+ }
+ }
+ }
+ dapl_os_unlock(lock);
+
+ /* no duplicate request on connq, check listenq for new request */
+ if (ntohs(msg->op) == DCM_REQ && !listenq && !found) {
+ listenq = 1;
+ list = &tp->llist;
+ lock = &tp->llock;
+ goto retry_listenq;
+ }
+
+ /* not match on listenq for valid request, send reject */
+ if (ntohs(msg->op) == DCM_REQ && !found)
+ ucm_reject(tp, msg);
+
+ if (!found) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " ucm_recv: NO MATCH op %s 0x%x %d i0x%x c0x%x"
+ " < 0x%x %d 0x%x\n",
+ dapl_cm_op_str(ntohs(msg->op)),
+ ntohs(msg->daddr.ib.lid), ntohs(msg->dport),
+ ntohl(msg->daddr.ib.qpn), ntohl(msg->sqpn),
+ ntohs(msg->saddr.ib.lid), ntohs(msg->sport),
+ ntohl(msg->saddr.ib.qpn));
+ }
+
+ return found;
+}
+
+/* Get rmsgs from CM completion queue, 10 at a time */
+static void ucm_recv(ib_hca_transport_t *tp)
+{
+ struct ibv_wc wc[10];
+ ib_cm_msg_t *msg;
+ dp_ib_cm_handle_t cm;
+ int i, ret, notify = 0;
+ struct ibv_cq *ibv_cq = NULL;
+ DAPL_HCA *hca;
+
+ /* POLLIN on channel FD */
+ ret = ibv_get_cq_event(tp->rch, &ibv_cq, (void *)&hca);
+ if (ret == 0) {
+ ibv_ack_cq_events(ibv_cq, 1);
+ }
+retry:
+ ret = ibv_poll_cq(tp->rcq, 10, wc);
+ if (ret <= 0) {
+ if (!ret && !notify) {
+ ibv_req_notify_cq(tp->rcq, 0);
+ notify = 1;
+ goto retry;
+ }
+ return;
+ } else
+ notify = 0;
+
+ for (i = 0; i < ret; i++) {
+ msg = (ib_cm_msg_t*) (uintptr_t) wc[i].wr_id;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " ucm_recv: wc status=%d, ln=%d id=%p sqp=%x\n",
+ wc[i].status, wc[i].byte_len,
+ (void*)wc[i].wr_id, wc[i].src_qp);
+
+ /* validate CM message, version */
+ if (ntohs(msg->ver) != DCM_VER) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " ucm_recv: UNKNOWN msg %p, ver %d\n",
+ msg, msg->ver);
+ ucm_post_rmsg(tp, msg);
+ continue;
+ }
+ if (!(cm = ucm_cm_find(tp, msg))) {
+ ucm_post_rmsg(tp, msg);
+ continue;
+ }
+
+ /* match, process it */
+ ucm_process_recv(tp, msg, cm);
+ ucm_post_rmsg(tp, msg);
+ }
+
+ /* finished this batch of WC's, poll and rearm */
+ goto retry;
+}
+
+/* ACTIVE/PASSIVE: build and send CM message out of CM object */
+static int ucm_send(ib_hca_transport_t *tp, ib_cm_msg_t *msg, DAT_PVOID p_data, DAT_COUNT p_size)
+{
+ ib_cm_msg_t *smsg = NULL;
+ struct ibv_send_wr wr, *bad_wr;
+ struct ibv_sge sge;
+ int len, ret = -1;
+ uint16_t dlid = ntohs(msg->daddr.ib.lid);
+
+ /* Get message from send queue, copy data, and send */
+ dapl_os_lock(&tp->slock);
+ if ((smsg = ucm_get_smsg(tp)) == NULL)
+ goto bail;
+
+ len = (sizeof(*msg) - DCM_MAX_PDATA_SIZE);
+ dapl_os_memcpy(smsg, msg, len);
+ if (p_size) {
+ smsg->p_size = ntohs(p_size);
+ dapl_os_memcpy(&smsg->p_data, p_data, p_size);
+ }
+
+ wr.next = NULL;
+ wr.sg_list = &sge;
+ wr.num_sge = 1;
+ wr.opcode = IBV_WR_SEND;
+ wr.wr_id = (unsigned long)tp->s_hd;
+ wr.send_flags = (wr.wr_id % UCM_SND_BURST) ? 0 : IBV_SEND_SIGNALED;
+ if (len <= tp->max_inline_send)
+ wr.send_flags |= IBV_SEND_INLINE;
+
+ sge.length = len + p_size;
+ sge.lkey = tp->mr_sbuf->lkey;
+ sge.addr = (uintptr_t)smsg;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " ucm_send: op %d ln %d lid %x c_qpn %x rport %d\n",
+ ntohs(smsg->op), sge.length, htons(smsg->daddr.ib.lid),
+ htonl(smsg->dqpn), htons(smsg->dport));
+
+ /* empty slot, then create AH */
+ if (!tp->ah[dlid]) {
+ tp->ah[dlid] =
+ dapls_create_ah(tp->hca, tp->pd, tp->qp,
+ htons(dlid), NULL);
+ if (!tp->ah[dlid])
+ goto bail;
+ }
+
+ wr.wr.ud.ah = tp->ah[dlid];
+ wr.wr.ud.remote_qpn = ntohl(smsg->dqpn);
+ wr.wr.ud.remote_qkey = DAT_UD_QKEY;
+
+ ret = ibv_post_send(tp->qp, &wr, &bad_wr);
+bail:
+ dapl_os_unlock(&tp->slock);
+ return ret;
+}
+
+/* ACTIVE/PASSIVE: CM objects */
+static void dapli_cm_dealloc(dp_ib_cm_handle_t cm) {
+
+ dapl_os_assert(!cm->ref_count);
+ dapl_os_lock_destroy(&cm->lock);
+ dapl_os_wait_object_destroy(&cm->event);
+ dapl_os_free(cm, sizeof(*cm));
+}
+
+void dapls_cm_acquire(dp_ib_cm_handle_t cm)
+{
+ dapl_os_lock(&cm->lock);
+ cm->ref_count++;
+ dapl_os_unlock(&cm->lock);
+}
+
+void dapls_cm_release(dp_ib_cm_handle_t cm)
+{
+ dapl_os_lock(&cm->lock);
+ cm->ref_count--;\r
+ if (cm->ref_count) {\r
+ dapl_os_unlock(&cm->lock);\r
return;\r
}\r
-\r
- dapl_os_lock(&cm->lock);\r
-\r
- /* client, release local conn id port */\r
- if (!cm->sp && cm->msg.sport)\r
- ucm_free_port(&cm->hca->ib_trans, cm->msg.sport);\r
-\r
- /* cleanup, never made it to work queue */\r
- if (cm->state == DCM_INIT) {\r
- dapl_os_unlock(&cm->lock);\r
- dapl_os_lock_destroy(&cm->lock);\r
- dapl_os_free(cm, sizeof(*cm));\r
- return;\r
- }\r
-\r
- /* free could be called before disconnect, disc_clean will destroy */\r
- if (cm->state == DCM_CONNECTED) {\r
- dapl_os_unlock(&cm->lock);\r
- dapli_cm_disconnect(cm);\r
- return;\r
- }\r
-\r
- cm->state = DCM_DESTROY;\r
- if ((cm->ep) && (cm->ep->cm_handle == cm)) {\r
- cm->ep->cm_handle = IB_INVALID_HANDLE;\r
- cm->ep = NULL;\r
- }\r
-\r
- dapl_os_unlock(&cm->lock);\r
-\r
- /* wakeup work thread */\r
- dapls_thread_signal(&cm->hca->ib_trans.signal);\r
-}\r
-\r
-/* ACTIVE/PASSIVE: queue up connection object on CM list */\r
-static void ucm_queue_conn(dp_ib_cm_handle_t cm)\r
-{\r
- /* add to work queue, list, for cm thread processing */\r
- dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm->entry);\r
- dapl_os_lock(&cm->hca->ib_trans.lock);\r
- dapl_llist_add_tail(&cm->hca->ib_trans.list,\r
- (DAPL_LLIST_ENTRY *)&cm->entry, cm);\r
- dapl_os_unlock(&cm->hca->ib_trans.lock);\r
- dapls_thread_signal(&cm->hca->ib_trans.signal);\r
-}\r
-\r
-/* PASSIVE: queue up listen object on listen list */\r
-static void ucm_queue_listen(dp_ib_cm_handle_t cm)\r
-{\r
- /* add to work queue, llist, for cm thread processing */\r
- dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm->entry);\r
- dapl_os_lock(&cm->hca->ib_trans.llock);\r
- dapl_llist_add_tail(&cm->hca->ib_trans.llist,\r
- (DAPL_LLIST_ENTRY *)&cm->entry, cm);\r
- dapl_os_unlock(&cm->hca->ib_trans.llock);\r
-}\r
-\r
-static void ucm_dequeue_listen(dp_ib_cm_handle_t cm) {\r
- dapl_os_lock(&cm->hca->ib_trans.llock);\r
- dapl_llist_remove_entry(&cm->hca->ib_trans.llist, \r
- (DAPL_LLIST_ENTRY *)&cm->entry);\r
- dapl_os_unlock(&cm->hca->ib_trans.llock);\r
-}\r
-\r
-static void ucm_disconnect_final(dp_ib_cm_handle_t cm) \r
-{\r
- /* no EP attachment or not RC, nothing to process */\r
- if (cm->ep == NULL ||\r
- cm->ep->param.ep_attr.service_type != DAT_SERVICE_TYPE_RC) \r
- return;\r
-\r
- dapl_os_lock(&cm->lock);\r
- if (cm->state == DCM_DISCONNECTED) {\r
- dapl_os_unlock(&cm->lock);\r
- return;\r
- }\r
- \r
- cm->state = DCM_DISCONNECTED;\r
- dapl_os_unlock(&cm->lock);\r
-\r
- if (cm->sp) \r
- dapls_cr_callback(cm, IB_CME_DISCONNECTED, NULL, 0, cm->sp);\r
- else\r
- dapl_evd_connection_callback(cm, IB_CME_DISCONNECTED, NULL, 0, cm->ep);\r
-}\r
-\r
-/*\r
- * called from consumer thread via ep_disconnect/ep_free or \r
- * from cm_thread when receiving DREQ\r
- */\r
-DAT_RETURN dapli_cm_disconnect(dp_ib_cm_handle_t cm)\r
-{\r
- int finalize = 1;\r
-\r
- dapl_os_lock(&cm->lock);\r
- switch (cm->state) {\r
- case DCM_CONNECTED:\r
- /* CONSUMER: move to err state to flush, if not UD */\r
- if (cm->ep->qp_handle->qp_type != IBV_QPT_UD) \r
- dapls_modify_qp_state(cm->ep->qp_handle, IBV_QPS_ERR,0,0,0);\r
-\r
- /* send DREQ, event after DREP or DREQ timeout */\r
- cm->state = DCM_DISC_PENDING;\r
- cm->msg.op = htons(DCM_DREQ);\r
- finalize = 0; /* wait for DREP, wakeup timer thread */\r
- dapls_thread_signal(&cm->hca->ib_trans.signal);\r
- break;\r
- case DCM_DISC_PENDING:\r
- /* DREQ timeout, resend until retries exhausted */\r
- cm->msg.op = htons(DCM_DREQ);\r
- if (cm->retries >= cm->hca->ib_trans.retries) {\r
- dapl_log(DAPL_DBG_TYPE_ERR, \r
- " CM_DREQ: RETRIES EXHAUSTED:"\r
- " 0x%x %d 0x%x -> 0x%x %d 0x%x\n",\r
- htons(cm->msg.saddr.ib.lid), \r
- htonl(cm->msg.saddr.ib.qpn), \r
- htons(cm->msg.sport), \r
- htons(cm->msg.daddr.ib.lid), \r
- htonl(cm->msg.dqpn), \r
- htons(cm->msg.dport));\r
- finalize = 1;\r
- }\r
- break;\r
- case DCM_DISC_RECV:\r
- /* CM_THREAD: move to err state to flush, if not UD */\r
- if (cm->ep->qp_handle->qp_type != IBV_QPT_UD) \r
- dapls_modify_qp_state(cm->ep->qp_handle, IBV_QPS_ERR,0,0,0);\r
-\r
- /* DREQ received, send DREP and schedule event */\r
- cm->msg.op = htons(DCM_DREP);\r
- break;\r
- default:\r
- dapl_os_unlock(&cm->lock);\r
- return DAT_SUCCESS;\r
- }\r
- \r
- dapl_os_get_time(&cm->timer); /* reply expected */\r
- ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0); \r
- dapl_os_unlock(&cm->lock);\r
-\r
- if (finalize)\r
- ucm_disconnect_final(cm);\r
- \r
- return DAT_SUCCESS;\r
-}\r
-\r
-/*\r
- * ACTIVE: get remote CM SID server info from r_addr. \r
- * send, or resend CM msg via UD CM QP \r
- */\r
-DAT_RETURN\r
-dapli_cm_connect(DAPL_EP *ep, dp_ib_cm_handle_t cm)\r
-{\r
- dapl_log(DAPL_DBG_TYPE_EP, \r
- " connect: lid %x i_qpn %x lport %d p_sz=%d -> "\r
- " lid %x c_qpn %x rport %d\n",\r
- htons(cm->msg.saddr.ib.lid), htonl(cm->msg.saddr.ib.qpn),\r
- htons(cm->msg.sport), htons(cm->msg.p_size),\r
- htons(cm->msg.daddr.ib.lid), htonl(cm->msg.dqpn),\r
- htons(cm->msg.dport));\r
-\r
- dapl_os_lock(&cm->lock);\r
- if (cm->state != DCM_REP_PENDING) {\r
- dapl_os_unlock(&cm->lock);\r
- return DAT_INVALID_STATE;\r
- }\r
- \r
- if (cm->retries == cm->hca->ib_trans.retries) {\r
- dapl_log(DAPL_DBG_TYPE_ERR, \r
- " CM_REQ: RETRIES EXHAUSTED:"\r
- " 0x%x %d 0x%x -> 0x%x %d 0x%x\n",\r
- htons(cm->msg.saddr.ib.lid), \r
- htonl(cm->msg.saddr.ib.qpn), \r
- htons(cm->msg.sport), \r
- htons(cm->msg.daddr.ib.lid), \r
- htonl(cm->msg.dqpn), \r
- htons(cm->msg.dport));\r
-\r
- /* update ep->cm reference so we get cleaned up on callback */\r
- if (cm->msg.saddr.ib.qp_type == IBV_QPT_RC);\r
- ep->cm_handle = cm;\r
-\r
- dapl_os_unlock(&cm->lock);\r
-\r
-#ifdef DAPL_COUNTERS\r
- /* called from check_timers in cm_thread, cm lock held */\r
- if (g_dapl_dbg_type & DAPL_DBG_TYPE_CM_LIST) {\r
- dapl_os_unlock(&cm->hca->ib_trans.lock);\r
- dapls_print_cm_list(ep->header.owner_ia);\r
- dapl_os_lock(&cm->hca->ib_trans.lock);\r
- }\r
-#endif\r
- dapl_evd_connection_callback(cm, \r
- IB_CME_DESTINATION_UNREACHABLE,\r
- NULL, 0, ep);\r
- \r
- return DAT_ERROR(DAT_INVALID_ADDRESS, \r
- DAT_INVALID_ADDRESS_UNREACHABLE);\r
+ /* client, release local conn id port */
+ if (!cm->sp && cm->msg.sport)
+ ucm_free_port(&cm->hca->ib_trans, ntohs(cm->msg.sport));
+
+ /* server, release local conn id port */
+ if (cm->sp && cm->msg.dport)
+ ucm_free_port(&cm->hca->ib_trans, ntohs(cm->msg.dport));
+
+ /* clean up any UD address handles */
+ if (cm->ah) {
+ ibv_destroy_ah(cm->ah);
+ cm->ah = NULL;
}\r
dapl_os_unlock(&cm->lock);\r
-\r
- cm->msg.op = htons(DCM_REQ);\r
- dapl_os_get_time(&cm->timer); /* reply expected */\r
- if (ucm_send(&cm->hca->ib_trans, &cm->msg, \r
- &cm->msg.p_data, ntohs(cm->msg.p_size))) \r
- goto bail;\r
-\r
- /* first time through, put on work queue */\r
- if (!cm->retries)\r
- ucm_queue_conn(cm);\r
-\r
- return DAT_SUCCESS;\r
-\r
-bail:\r
- dapl_log(DAPL_DBG_TYPE_WARN, \r
- " connect: ERR %s -> cm_lid %d cm_qpn %d r_psp %d p_sz=%d\n",\r
- strerror(errno), htons(cm->msg.daddr.ib.lid), \r
- htonl(cm->msg.dqpn), htons(cm->msg.dport), \r
- htonl(cm->msg.p_size));\r
-\r
- /* close socket, free cm structure */\r
- dapls_ib_cm_free(cm, cm->ep);\r
- return DAT_INSUFFICIENT_RESOURCES;\r
-}\r
-\r
-/*\r
- * ACTIVE: exchange QP information, called from CR thread\r
- */\r
-static void ucm_connect_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg)\r
-{\r
- DAPL_EP *ep = cm->ep;\r
- ib_cm_events_t event = IB_CME_CONNECTED;\r
-\r
- dapl_os_lock(&cm->lock);\r
- if (cm->state != DCM_REP_PENDING) {\r
- dapl_log(DAPL_DBG_TYPE_WARN, \r
- " CONN_RTU: UNEXPECTED state:"\r
- " op %d, st %s <- lid %d sqpn %d sport %d\n", \r
- ntohs(msg->op), dapl_cm_state_str(cm->state), \r
- ntohs(msg->saddr.ib.lid), ntohl(msg->saddr.ib.qpn), \r
- ntohs(msg->sport));\r
- dapl_os_unlock(&cm->lock);\r
- return;\r
- }\r
-\r
- /* save remote address information to EP and CM */\r
- dapl_os_memcpy(&ep->remote_ia_address,\r
- &msg->saddr, sizeof(union dcm_addr));\r
- dapl_os_memcpy(&cm->msg.daddr, \r
- &msg->saddr, sizeof(union dcm_addr));\r
-\r
- /* validate private data size, and copy if necessary */\r
- if (msg->p_size) {\r
- if (ntohs(msg->p_size) > DCM_MAX_PDATA_SIZE) {\r
- dapl_log(DAPL_DBG_TYPE_WARN, \r
- " CONN_RTU: invalid p_size %d:"\r
- " st %s <- lid %d sqpn %d spsp %d\n", \r
- ntohs(msg->p_size), \r
- dapl_cm_state_str(cm->state), \r
- ntohs(msg->saddr.ib.lid), \r
- ntohl(msg->saddr.ib.qpn), \r
- ntohs(msg->sport));\r
- dapl_os_unlock(&cm->lock);\r
- goto bail;\r
- }\r
- dapl_os_memcpy(cm->msg.p_data, \r
- msg->p_data, ntohs(msg->p_size));\r
- }\r
- \r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " CONN_RTU: DST lid=%x,"\r
- " iqp=%x, qp_type=%d, port=%d psize=%d\n",\r
- ntohs(cm->msg.daddr.ib.lid),\r
- ntohl(cm->msg.daddr.ib.qpn), cm->msg.daddr.ib.qp_type,\r
- ntohs(msg->sport), ntohs(msg->p_size));\r
-\r
- if (ntohs(msg->op) == DCM_REP)\r
- event = IB_CME_CONNECTED;\r
- else if (ntohs(msg->op) == DCM_REJ_USER) \r
- event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA;\r
- else \r
- event = IB_CME_DESTINATION_REJECT;\r
- \r
- if (event != IB_CME_CONNECTED) {\r
- cm->state = DCM_REJECTED;\r
- dapl_os_unlock(&cm->lock);\r
-\r
-#ifdef DAT_EXTENSIONS\r
- if (cm->msg.daddr.ib.qp_type == IBV_QPT_UD) \r
- goto ud_bail;\r
- else\r
-#endif\r
- goto bail;\r
- }\r
- dapl_os_unlock(&cm->lock);\r
-\r
- /* modify QP to RTR and then to RTS with remote info */\r
- dapl_os_lock(&cm->ep->header.lock);\r
- if (dapls_modify_qp_state(cm->ep->qp_handle,\r
- IBV_QPS_RTR, \r
- cm->msg.daddr.ib.qpn,\r
- cm->msg.daddr.ib.lid,\r
- NULL) != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " CONN_RTU: QPS_RTR ERR %s <- lid %x iqp %x\n",\r
- strerror(errno), ntohs(cm->msg.daddr.ib.lid),\r
- ntohl(cm->msg.daddr.ib.qpn));\r
- dapl_os_unlock(&cm->ep->header.lock);\r
- event = IB_CME_LOCAL_FAILURE;\r
- goto bail;\r
- }\r
- if (dapls_modify_qp_state(cm->ep->qp_handle,\r
- IBV_QPS_RTS, \r
- cm->msg.daddr.ib.qpn,\r
- cm->msg.daddr.ib.lid,\r
- NULL) != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " CONN_RTU: QPS_RTS ERR %s <- lid %x iqp %x\n",\r
- strerror(errno), ntohs(cm->msg.daddr.ib.lid),\r
- ntohl(cm->msg.daddr.ib.qpn));\r
- dapl_os_unlock(&cm->ep->header.lock);\r
- event = IB_CME_LOCAL_FAILURE;\r
- goto bail;\r
- }\r
- dapl_os_unlock(&cm->ep->header.lock);\r
- \r
- /* Send RTU, no private data */\r
- cm->msg.op = htons(DCM_RTU);\r
- \r
- dapl_os_lock(&cm->lock);\r
- cm->state = DCM_CONNECTED;\r
- dapl_os_unlock(&cm->lock);\r
-\r
- if (ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0)) \r
- goto bail;\r
-\r
- /* init cm_handle and post the event with private data */\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP, " ACTIVE: connected!\n");\r
-\r
-#ifdef DAT_EXTENSIONS\r
-ud_bail:\r
- if (cm->msg.daddr.ib.qp_type == IBV_QPT_UD) {\r
- DAT_IB_EXTENSION_EVENT_DATA xevent;\r
- uint16_t lid = ntohs(cm->msg.daddr.ib.lid);\r
- \r
- /* post EVENT, modify_qp, AH already created, ucm msg */\r
- xevent.status = 0;\r
- xevent.type = DAT_IB_UD_REMOTE_AH;\r
- xevent.remote_ah.qpn = ntohl(cm->msg.daddr.ib.qpn);\r
- xevent.remote_ah.ah = dapls_create_ah(cm->hca, \r
- cm->ep->qp_handle->pd, \r
- cm->ep->qp_handle, \r
- htons(lid), \r
- NULL);\r
- if (xevent.remote_ah.ah == NULL) {\r
- event = IB_CME_LOCAL_FAILURE;\r
- goto bail;\r
- }\r
- cm->ah = xevent.remote_ah.ah; /* keep ref to destroy */\r
-\r
- dapl_os_memcpy(&xevent.remote_ah.ia_addr,\r
- &cm->msg.daddr,\r
- sizeof(union dcm_addr));\r
-\r
- /* remote ia_addr reference includes ucm qpn, not IB qpn */\r
- ((union dcm_addr*)\r
- &xevent.remote_ah.ia_addr)->ib.qpn = cm->msg.dqpn;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " ACTIVE: UD xevent ah %p qpn 0x%x lid 0x%x\n",\r
- xevent.remote_ah.ah, xevent.remote_ah.qpn, lid);\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " ACTIVE: UD xevent ia_addr qp_type %d"\r
- " lid 0x%x qpn 0x%x gid 0x"F64x" 0x"F64x" \n",\r
- ((union dcm_addr*)\r
- &xevent.remote_ah.ia_addr)->ib.qp_type,\r
- ntohs(((union dcm_addr*)\r
- &xevent.remote_ah.ia_addr)->ib.lid),\r
- ntohl(((union dcm_addr*)\r
- &xevent.remote_ah.ia_addr)->ib.qpn),\r
- ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[0]),\r
- ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[8]));\r
-\r
- if (event == IB_CME_CONNECTED)\r
- event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED;\r
- else {\r
- xevent.type = DAT_IB_UD_CONNECT_REJECT;\r
- event = DAT_IB_UD_CONNECTION_REJECT_EVENT;\r
- }\r
-\r
- dapls_evd_post_connection_event_ext(\r
- (DAPL_EVD *)cm->ep->param.connect_evd_handle,\r
- event,\r
- (DAT_EP_HANDLE)ep,\r
- (DAT_COUNT)ntohs(cm->msg.p_size),\r
- (DAT_PVOID *)cm->msg.p_data,\r
- (DAT_PVOID *)&xevent);\r
-\r
- /* we are done, don't destroy cm_ptr, need pdata */\r
- dapl_os_lock(&cm->lock);\r
- cm->state = DCM_RELEASED;\r
- dapl_os_unlock(&cm->lock);\r
- \r
- } else\r
-#endif\r
- {\r
- cm->ep->cm_handle = cm; /* only RC, multi CR's on UD */\r
- dapl_evd_connection_callback(cm,\r
- IB_CME_CONNECTED,\r
- cm->msg.p_data, ntohs(cm->msg.p_size), cm->ep);\r
- }\r
- return;\r
-bail:\r
- if (cm->msg.saddr.ib.qp_type != IBV_QPT_UD) \r
- dapls_ib_reinit_ep(cm->ep); /* reset QP state */\r
-\r
- dapl_evd_connection_callback(NULL, event, cm->msg.p_data, ntohs(cm->msg.p_size), cm->ep);\r
- dapls_ib_cm_free(cm, NULL); \r
-}\r
-\r
-/*\r
- * PASSIVE: Accept on listen CM PSP.\r
- * create new CM object for this CR, \r
- * receive peer QP information, private data, \r
- * and post cr_event \r
- */\r
-static void ucm_accept(ib_cm_srvc_handle_t cm, ib_cm_msg_t *msg)\r
-{\r
- dp_ib_cm_handle_t acm;\r
-\r
- /* Allocate accept CM and setup passive references */\r
- if ((acm = dapls_ib_cm_create(NULL)) == NULL) {\r
- dapl_log(DAPL_DBG_TYPE_WARN, " accept: ERR cm_create\n");\r
- return;\r
- }\r
-\r
- /* dest CM info from CR msg, source CM info from listen */\r
- acm->sp = cm->sp;\r
- acm->hca = cm->hca;\r
- acm->msg.dport = msg->sport;\r
- acm->msg.dqpn = msg->sqpn;\r
- acm->msg.sport = cm->msg.sport; \r
- acm->msg.sqpn = cm->msg.sqpn;\r
- acm->msg.p_size = msg->p_size;\r
-\r
- /* CR saddr is CM daddr info, need EP for local saddr */\r
- dapl_os_memcpy(&acm->msg.daddr, &msg->saddr, sizeof(union dcm_addr));\r
- \r
- dapl_log(DAPL_DBG_TYPE_CM,\r
- " accept: DST port=%d lid=%x, iqp=%x, psize=%d\n",\r
- ntohs(acm->msg.dport), ntohs(acm->msg.daddr.ib.lid), \r
- htonl(acm->msg.daddr.ib.qpn), htons(acm->msg.p_size));\r
-\r
- /* validate private data size before reading */\r
- if (ntohs(msg->p_size) > DCM_MAX_PDATA_SIZE) {\r
- dapl_log(DAPL_DBG_TYPE_WARN, " accept: psize (%d) wrong\n",\r
- ntohs(msg->p_size));\r
- goto bail;\r
- }\r
-\r
- /* read private data into cm_handle if any present */\r
- if (msg->p_size) \r
- dapl_os_memcpy(acm->msg.p_data, \r
- msg->p_data, ntohs(msg->p_size));\r
- \r
- acm->state = DCM_ACCEPTING;\r
- ucm_queue_conn(acm);\r
-\r
-#ifdef DAT_EXTENSIONS\r
- if (acm->msg.daddr.ib.qp_type == IBV_QPT_UD) {\r
- DAT_IB_EXTENSION_EVENT_DATA xevent;\r
-\r
- /* post EVENT, modify_qp created ah */\r
- xevent.status = 0;\r
- xevent.type = DAT_IB_UD_CONNECT_REQUEST;\r
-\r
- dapls_evd_post_cr_event_ext(acm->sp,\r
- DAT_IB_UD_CONNECTION_REQUEST_EVENT,\r
- acm,\r
- (DAT_COUNT)ntohs(acm->msg.p_size),\r
- (DAT_PVOID *)acm->msg.p_data,\r
- (DAT_PVOID *)&xevent);\r
- } else\r
-#endif\r
- /* trigger CR event and return SUCCESS */\r
- dapls_cr_callback(acm,\r
- IB_CME_CONNECTION_REQUEST_PENDING,\r
- acm->msg.p_data, ntohs(msg->p_size), acm->sp);\r
- return;\r
-\r
-bail:\r
- /* free cm object */\r
- dapls_ib_cm_free(acm, NULL);\r
- return;\r
-}\r
-\r
-/*\r
- * PASSIVE: read RTU from active peer, post CONN event\r
- */\r
-static void ucm_accept_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg)\r
-{\r
- dapl_os_lock(&cm->lock);\r
- if ((ntohs(msg->op) != DCM_RTU) || (cm->state != DCM_RTU_PENDING)) {\r
- dapl_log(DAPL_DBG_TYPE_WARN, \r
- " accept_rtu: UNEXPECTED op, state:"\r
- " op %d, st %s <- lid %x iqp %x sport %d\n", \r
- ntohs(msg->op), dapl_cm_state_str(cm->state), \r
- ntohs(msg->saddr.ib.lid), ntohl(msg->saddr.ib.qpn), \r
- ntohs(msg->sport));\r
- dapl_os_unlock(&cm->lock);\r
- goto bail;\r
- }\r
- cm->state = DCM_CONNECTED;\r
- dapl_os_unlock(&cm->lock);\r
- \r
- /* final data exchange if remote QP state is good to go */\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " PASSIVE: connected!\n");\r
-\r
-#ifdef DAT_EXTENSIONS\r
- if (cm->msg.saddr.ib.qp_type == IBV_QPT_UD) {\r
- DAT_IB_EXTENSION_EVENT_DATA xevent;\r
- uint16_t lid = ntohs(cm->msg.daddr.ib.lid);\r
- \r
- /* post EVENT, modify_qp, AH already created, ucm msg */\r
- xevent.status = 0;\r
- xevent.type = DAT_IB_UD_PASSIVE_REMOTE_AH;\r
- xevent.remote_ah.qpn = ntohl(cm->msg.daddr.ib.qpn);\r
- xevent.remote_ah.ah = dapls_create_ah(cm->hca, \r
- cm->ep->qp_handle->pd, \r
- cm->ep->qp_handle, \r
- htons(lid), \r
- NULL);\r
- if (xevent.remote_ah.ah == NULL) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " accept_rtu: ERR create_ah"\r
- " for qpn 0x%x lid 0x%x\n",\r
- xevent.remote_ah.qpn, lid);\r
- goto bail;\r
- }\r
- cm->ah = xevent.remote_ah.ah; /* keep ref to destroy */\r
- dapl_os_memcpy(&xevent.remote_ah.ia_addr,\r
- &cm->msg.daddr,\r
- sizeof(union dcm_addr));\r
-\r
- /* remote ia_addr reference includes ucm qpn, not IB qpn */\r
- ((union dcm_addr*)\r
- &xevent.remote_ah.ia_addr)->ib.qpn = cm->msg.dqpn;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " PASSIVE: UD xevent ah %p qpn 0x%x lid 0x%x\n",\r
- xevent.remote_ah.ah, xevent.remote_ah.qpn, lid);\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " PASSIVE: UD xevent ia_addr qp_type %d"\r
- " lid 0x%x qpn 0x%x gid 0x"F64x" 0x"F64x" \n",\r
- ((union dcm_addr*)\r
- &xevent.remote_ah.ia_addr)->ib.qp_type,\r
- ntohs(((union dcm_addr*)\r
- &xevent.remote_ah.ia_addr)->ib.lid),\r
- ntohl(((union dcm_addr*)\r
- &xevent.remote_ah.ia_addr)->ib.qpn),\r
- ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[0]),\r
- ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[8]));\r
-\r
- dapls_evd_post_connection_event_ext(\r
- (DAPL_EVD *)cm->ep->param.connect_evd_handle,\r
- DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED,\r
- (DAT_EP_HANDLE)cm->ep,\r
- (DAT_COUNT)ntohs(cm->msg.p_size),\r
- (DAT_PVOID *)cm->msg.p_data,\r
- (DAT_PVOID *)&xevent);\r
-\r
- /* done with CM object, don't destroy cm, need pdata */\r
- dapl_os_lock(&cm->lock);\r
- cm->state = DCM_RELEASED;\r
- dapl_os_unlock(&cm->lock);\r
- } else {\r
-#endif\r
- cm->ep->cm_handle = cm; /* only RC, multi CR's on UD */\r
- dapls_cr_callback(cm, IB_CME_CONNECTED, NULL, 0, cm->sp);\r
- }\r
- return;\r
-bail:\r
- if (cm->msg.saddr.ib.qp_type != IBV_QPT_UD) \r
- dapls_ib_reinit_ep(cm->ep); /* reset QP state */\r
- dapls_ib_cm_free(cm, cm->ep);\r
- dapls_cr_callback(cm, IB_CME_LOCAL_FAILURE, NULL, 0, cm->sp);\r
-}\r
-\r
-/*\r
- * PASSIVE: user accepted, send reply message with pdata\r
- */\r
-static int ucm_reply(dp_ib_cm_handle_t cm)\r
-{\r
- dapl_os_lock(&cm->lock);\r
- if (cm->state != DCM_RTU_PENDING) {\r
- dapl_os_unlock(&cm->lock);\r
- return -1;\r
- }\r
-\r
- if (cm->retries == cm->hca->ib_trans.retries) {\r
- dapl_log(DAPL_DBG_TYPE_ERR, \r
- " CM_REPLY: RETRIES EXHAUSTED"\r
- " 0x%x %d 0x%x -> 0x%x %d 0x%x\n",\r
- htons(cm->msg.saddr.ib.lid), \r
- htons(cm->msg.sport), \r
- htonl(cm->msg.saddr.ib.qpn), \r
- htons(cm->msg.daddr.ib.lid), \r
- htons(cm->msg.dport), \r
- htonl(cm->msg.daddr.ib.qpn));\r
- \r
- dapl_os_unlock(&cm->lock);\r
-#ifdef DAPL_COUNTERS\r
- /* called from check_timers in cm_thread, cm lock held */\r
- if (g_dapl_dbg_type & DAPL_DBG_TYPE_CM_LIST) {\r
- dapl_os_unlock(&cm->hca->ib_trans.lock);\r
- dapls_print_cm_list(dapl_llist_peek_head(&cm->hca->ia_list_head));\r
- dapl_os_lock(&cm->hca->ib_trans.lock);\r
- }\r
-#endif\r
-#ifdef DAT_EXTENSIONS\r
- if (cm->msg.saddr.ib.qp_type == IBV_QPT_UD) {\r
- DAT_IB_EXTENSION_EVENT_DATA xevent;\r
- \r
- /* post REJECT event with CONN_REQ p_data */\r
- xevent.status = 0;\r
- xevent.type = DAT_IB_UD_CONNECT_ERROR;\r
- \r
- dapls_evd_post_connection_event_ext(\r
- (DAPL_EVD *)cm->ep->param.connect_evd_handle,\r
- DAT_IB_UD_CONNECTION_ERROR_EVENT,\r
- (DAT_EP_HANDLE)cm->ep,\r
- (DAT_COUNT)ntohs(cm->msg.p_size),\r
- (DAT_PVOID *)cm->msg.p_data,\r
- (DAT_PVOID *)&xevent);\r
- } else \r
-#endif\r
- dapls_cr_callback(cm, IB_CME_LOCAL_FAILURE, \r
- NULL, 0, cm->sp);\r
- return -1;\r
- }\r
- dapl_os_get_time(&cm->timer); /* RTU expected */\r
- dapl_os_unlock(&cm->lock);\r
- if (ucm_send(&cm->hca->ib_trans, &cm->msg, cm->p_data, cm->p_size)) \r
- return -1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-/*\r
- * PASSIVE: consumer accept, send local QP information, private data, \r
- * queue on work thread to receive RTU information to avoid blocking\r
- * user thread. \r
- */\r
-DAT_RETURN\r
-dapli_accept_usr(DAPL_EP *ep, DAPL_CR *cr, DAT_COUNT p_size, DAT_PVOID p_data)\r
-{\r
- DAPL_IA *ia = ep->header.owner_ia;\r
- dp_ib_cm_handle_t cm = cr->ib_cm_handle;\r
-\r
- if (p_size > DCM_MAX_PDATA_SIZE)\r
- return DAT_LENGTH_ERROR;\r
-\r
- dapl_os_lock(&cm->lock);\r
- if (cm->state != DCM_ACCEPTING) {\r
- dapl_os_unlock(&cm->lock);\r
- return DAT_INVALID_STATE;\r
- }\r
- dapl_os_unlock(&cm->lock);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " ACCEPT_USR: remote lid=%x"\r
- " iqp=%x qp_type %d, psize=%d\n",\r
- ntohs(cm->msg.daddr.ib.lid),\r
- ntohl(cm->msg.daddr.ib.qpn), cm->msg.daddr.ib.qp_type, \r
- p_size);\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_CM,\r
- " ACCEPT_USR: remote GID subnet %016llx id %016llx\n",\r
- (unsigned long long)\r
- htonll(*(uint64_t*)&cm->msg.daddr.ib.gid[0]),\r
- (unsigned long long)\r
- htonll(*(uint64_t*)&cm->msg.daddr.ib.gid[8]));\r
-\r
-#ifdef DAT_EXTENSIONS\r
- if (cm->msg.daddr.ib.qp_type == IBV_QPT_UD &&\r
- ep->qp_handle->qp_type != IBV_QPT_UD) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT_USR: ERR remote QP is UD,"\r
- ", but local QP is not\n");\r
- return (DAT_INVALID_HANDLE | DAT_INVALID_HANDLE_EP);\r
- }\r
-#endif\r
-\r
- /* modify QP to RTR and then to RTS with remote info already read */\r
- dapl_os_lock(&ep->header.lock);\r
- if (dapls_modify_qp_state(ep->qp_handle,\r
- IBV_QPS_RTR, \r
- cm->msg.daddr.ib.qpn,\r
- cm->msg.daddr.ib.lid,\r
- NULL) != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT_USR: QPS_RTR ERR %s -> lid %x qpn %x\n",\r
- strerror(errno), ntohs(cm->msg.daddr.ib.lid),\r
- ntohl(cm->msg.daddr.ib.qpn));\r
- dapl_os_unlock(&ep->header.lock);\r
- goto bail;\r
- }\r
- if (dapls_modify_qp_state(ep->qp_handle,\r
- IBV_QPS_RTS, \r
- cm->msg.daddr.ib.qpn,\r
- cm->msg.daddr.ib.lid,\r
- NULL) != DAT_SUCCESS) {\r
- dapl_log(DAPL_DBG_TYPE_ERR,\r
- " ACCEPT_USR: QPS_RTS ERR %s -> lid %x qpn %x\n",\r
- strerror(errno), ntohs(cm->msg.daddr.ib.lid),\r
- ntohl(cm->msg.daddr.ib.qpn));\r
- dapl_os_unlock(&ep->header.lock);\r
- goto bail;\r
- }\r
- dapl_os_unlock(&ep->header.lock);\r
-\r
- /* save remote address information */\r
- dapl_os_memcpy(&ep->remote_ia_address,\r
- &cm->msg.saddr, sizeof(union dcm_addr));\r
-\r
- /* setup local QP info and type from EP, copy pdata, for reply */\r
- cm->msg.op = htons(DCM_REP);\r
- cm->msg.saddr.ib.qpn = htonl(ep->qp_handle->qp_num);\r
- cm->msg.saddr.ib.qp_type = ep->qp_handle->qp_type;\r
- cm->msg.saddr.ib.lid = cm->hca->ib_trans.addr.ib.lid; \r
- dapl_os_memcpy(&cm->msg.saddr.ib.gid[0],\r
- &cm->hca->ib_trans.addr.ib.gid, 16); \r
-\r
- /* \r
- * UD: deliver p_data with REQ and EST event, keep REQ p_data in \r
- * cm->msg.p_data and save REPLY accept data in cm->p_data for retries \r
- */\r
- cm->p_size = p_size;\r
- dapl_os_memcpy(&cm->p_data, p_data, p_size);\r
-\r
- /* save state and setup valid reference to EP, HCA */\r
- dapl_os_lock(&cm->lock);\r
- cm->ep = ep;\r
- cm->hca = ia->hca_ptr;\r
- cm->state = DCM_RTU_PENDING;\r
- dapl_os_get_time(&cm->timer); /* RTU expected */\r
- dapl_os_unlock(&cm->lock);\r
-\r
- if (ucm_reply(cm))\r
- goto bail;\r
- \r
- dapl_dbg_log(DAPL_DBG_TYPE_CM, " PASSIVE: accepted!\n");\r
- dapls_thread_signal(&cm->hca->ib_trans.signal);\r
- return DAT_SUCCESS;\r
-bail:\r
- if (cm->msg.saddr.ib.qp_type != IBV_QPT_UD)\r
- dapls_ib_reinit_ep(ep);\r
-\r
- dapls_ib_cm_free(cm, ep);\r
- return DAT_INTERNAL_ERROR;\r
-}\r
-\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\r
-dapls_ib_connect(IN DAT_EP_HANDLE ep_handle,\r
- IN DAT_IA_ADDRESS_PTR r_addr,\r
- IN DAT_CONN_QUAL r_psp,\r
- IN DAT_COUNT p_size, IN void *p_data)\r
-{\r
- DAPL_EP *ep = (DAPL_EP *)ep_handle;\r
- dp_ib_cm_handle_t cm;\r
- \r
- /* create CM object, initialize SRC info from EP */\r
- cm = dapls_ib_cm_create(ep);\r
- if (cm == NULL)\r
- return DAT_INSUFFICIENT_RESOURCES;\r
-\r
- /* remote hca and port: lid, gid, network order */\r
- dapl_os_memcpy(&cm->msg.daddr, r_addr, sizeof(union dcm_addr));\r
-\r
- /* remote uCM information, comes from consumer provider r_addr */\r
- cm->msg.dport = htons((uint16_t)r_psp);\r
- cm->msg.dqpn = cm->msg.daddr.ib.qpn;\r
- cm->msg.daddr.ib.qpn = 0; /* don't have a remote qpn until reply */\r
- \r
- if (p_size) {\r
- cm->msg.p_size = htons(p_size);\r
- dapl_os_memcpy(&cm->msg.p_data, p_data, p_size);\r
- }\r
- \r
- cm->state = DCM_REP_PENDING;\r
-\r
- /* build connect request, send to remote CM based on r_addr info */\r
- return(dapli_cm_connect(ep, cm));\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
-DAT_RETURN\r
-dapls_ib_disconnect(IN DAPL_EP *ep, IN DAT_CLOSE_FLAGS close_flags)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- "dapls_ib_disconnect(ep_handle %p ....)\n", ep);\r
-\r
- if (ep->cm_handle == NULL ||\r
- ep->param.ep_state == DAT_EP_STATE_DISCONNECTED)\r
- return DAT_SUCCESS;\r
- else\r
- return (dapli_cm_disconnect(ep->cm_handle));\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. It is also called if dat_ep_connect\r
- * times out using the consumer supplied timeout value.\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,\r
- IN DAT_BOOLEAN active,\r
- IN const ib_cm_events_t ib_cm_event)\r
-{\r
- /* NOTE: SCM will only initialize cm_handle with RC type\r
- * \r
- * For UD there can many in-flight CR's so you \r
- * cannot cleanup timed out CR's with EP reference \r
- * alone since they share the same EP. The common\r
- * code that handles connection timeout logic needs \r
- * updated for UD support.\r
- */\r
- if (ep->cm_handle)\r
- dapls_ib_cm_free(ep->cm_handle, ep);\r
-\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, \r
- IN DAT_UINT64 sid, \r
- IN DAPL_SP *sp)\r
-{\r
- ib_cm_srvc_handle_t cm = NULL;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " listen(ia %p ServiceID %d sp %p)\n",\r
- ia, sid, sp);\r
-\r
- /* reserve local port, then allocate CM object */\r
- if (!ucm_get_port(&ia->hca_ptr->ib_trans, (uint16_t)sid)) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_WARN,\r
- " listen: ERROR %s on conn_qual 0x%x\n",\r
- strerror(errno), sid);\r
- return DAT_CONN_QUAL_IN_USE;\r
- }\r
-\r
- /* cm_create will setup saddr for listen server */\r
- if ((cm = dapls_ib_cm_create(NULL)) == NULL)\r
- return DAT_INSUFFICIENT_RESOURCES;\r
-\r
- /* LISTEN: init DST address and QP info to local CM server info */\r
- cm->sp = sp;\r
- cm->hca = ia->hca_ptr;\r
- cm->msg.sport = htons((uint16_t)sid);\r
- cm->msg.sqpn = htonl(ia->hca_ptr->ib_trans.qp->qp_num);\r
- cm->msg.saddr.ib.qp_type = IBV_QPT_UD;\r
- cm->msg.saddr.ib.lid = ia->hca_ptr->ib_trans.addr.ib.lid; \r
- dapl_os_memcpy(&cm->msg.saddr.ib.gid[0],\r
- &cm->hca->ib_trans.addr.ib.gid, 16); \r
- \r
- /* save cm_handle reference in service point */\r
- sp->cm_srvc_handle = cm;\r
-\r
- /* queue up listen socket to process inbound CR's */\r
- cm->state = DCM_LISTEN;\r
- ucm_queue_listen(cm);\r
-\r
- return DAT_SUCCESS;\r
-}\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, IN DAPL_SP *sp)\r
-{\r
- ib_cm_srvc_handle_t cm = sp->cm_srvc_handle;\r
- ib_hca_transport_t *tp = &ia->hca_ptr->ib_trans;\r
-\r
- /* free cm_srvc_handle and port, and mark CM for cleanup */\r
- if (cm) {\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " remove_listener(ia %p sp %p cm %p psp=%d)\n",\r
- ia, sp, cm, ntohs(cm->msg.dport));\r
-\r
- sp->cm_srvc_handle = NULL;\r
- dapl_os_lock(&cm->lock);\r
- ucm_free_port(tp, ntohs(cm->msg.dport));\r
- cm->msg.dport = 0;\r
- cm->state = DCM_DESTROY;\r
- dapl_os_unlock(&cm->lock);\r
- ucm_dequeue_listen(cm);\r
- dapl_os_lock_destroy(&cm->lock);\r
- dapl_os_free(cm, sizeof(*cm));\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, \r
- IN const DAT_PVOID p_data)\r
-{\r
- DAPL_CR *cr = (DAPL_CR *)cr_handle;\r
- DAPL_EP *ep = (DAPL_EP *)ep_handle;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " accept_connection(cr %p ep %p prd %p,%d)\n",\r
- cr, ep, p_data, p_size);\r
-\r
- /* allocate and attach a QP if necessary */\r
- if (ep->qp_state == DAPL_QP_STATE_UNATTACHED) {\r
- DAT_RETURN status;\r
- status = dapls_ib_qp_alloc(ep->header.owner_ia,\r
- ep, ep);\r
- if (status != DAT_SUCCESS)\r
- return status;\r
- }\r
- return (dapli_accept_usr(ep, cr, p_size, p_data));\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,\r
- IN int reason,\r
- IN DAT_COUNT psize, IN const DAT_PVOID pdata)\r
-{\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- " reject(cm %p reason %x, pdata %p, psize %d)\n",\r
- cm, reason, pdata, psize);\r
-\r
- if (psize > DCM_MAX_PDATA_SIZE)\r
- return DAT_LENGTH_ERROR;\r
-\r
- /* cr_thread will destroy CR, update saddr lid, gid, qp_type info */\r
- dapl_os_lock(&cm->lock);\r
- cm->state = DCM_REJECTED;\r
- cm->msg.saddr.ib.lid = cm->hca->ib_trans.addr.ib.lid; \r
- cm->msg.saddr.ib.qp_type = cm->msg.daddr.ib.qp_type;\r
- dapl_os_memcpy(&cm->msg.saddr.ib.gid[0],\r
- &cm->hca->ib_trans.addr.ib.gid, 16); \r
- cm->msg.op = htons(DCM_REJ_USER);\r
- \r
- if (ucm_send(&cm->hca->ib_trans, &cm->msg, pdata, psize)) {\r
- dapl_log(DAPL_DBG_TYPE_WARN,\r
- " cm_reject: ERR: %s\n", strerror(errno));\r
- return DAT_INTERNAL_ERROR;\r
- }\r
- dapl_os_unlock(&cm->lock);\r
- \r
- /* cleanup and destroy CM resources */ \r
- dapls_ib_cm_free(cm, NULL);\r
-\r
- return DAT_SUCCESS;\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,\r
- OUT DAT_SOCK_ADDR6 * remote_ia_address)\r
-{\r
- DAPL_HEADER *header;\r
- dp_ib_cm_handle_t ib_cm_handle;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_EP,\r
- "dapls_ib_cm_remote_addr(dat_handle %p, ....)\n",\r
- dat_handle);\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
- dapl_os_memcpy(remote_ia_address,\r
- &ib_cm_handle->msg.daddr, sizeof(DAT_SOCK_ADDR6));\r
-\r
- return DAT_SUCCESS;\r
-}\r
-\r
-int dapls_ib_private_data_size(\r
- IN DAPL_HCA *hca_ptr)\r
-{\r
- return DCM_MAX_PDATA_SIZE;\r
-}\r
-\r
-/*\r
- * Map all socket CM event codes to the DAT equivelent.\r
- */\r
-#define DAPL_IB_EVENT_CNT 10\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 */ {IB_CME_CONNECTED, \r
- DAT_CONNECTION_EVENT_ESTABLISHED},\r
-/* 01 */ {IB_CME_DISCONNECTED, \r
- DAT_CONNECTION_EVENT_DISCONNECTED},\r
-/* 02 */ {IB_CME_DISCONNECTED_ON_LINK_DOWN,\r
- DAT_CONNECTION_EVENT_DISCONNECTED},\r
-/* 03 */ {IB_CME_CONNECTION_REQUEST_PENDING, \r
- DAT_CONNECTION_REQUEST_EVENT},\r
-/* 04 */ {IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA,\r
- DAT_CONNECTION_REQUEST_EVENT},\r
-/* 05 */ {IB_CME_DESTINATION_REJECT,\r
- DAT_CONNECTION_EVENT_NON_PEER_REJECTED},\r
-/* 06 */ {IB_CME_DESTINATION_REJECT_PRIVATE_DATA,\r
- DAT_CONNECTION_EVENT_PEER_REJECTED},\r
-/* 07 */ {IB_CME_DESTINATION_UNREACHABLE, \r
- DAT_CONNECTION_EVENT_UNREACHABLE},\r
-/* 08 */ {IB_CME_TOO_MANY_CONNECTION_REQUESTS,\r
- DAT_CONNECTION_EVENT_NON_PEER_REJECTED},\r
-/* 09 */ {IB_CME_LOCAL_FAILURE, \r
- DAT_CONNECTION_EVENT_BROKEN}\r
-};\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
- if (ib_cm_event > IB_CME_LOCAL_FAILURE)\r
- return (DAT_EVENT_NUMBER) 0;\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 translate(%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
-#if defined(_WIN32) || defined(_WIN64)\r
-\r
-void cm_thread(void *arg)\r
-{\r
- struct dapl_hca *hca = arg;\r
- dp_ib_cm_handle_t cm, next;\r
- DWORD time_ms;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread: ENTER hca %p\n", hca);\r
- dapl_os_lock(&hca->ib_trans.lock);\r
- for (hca->ib_trans.cm_state = IB_THREAD_RUN;\r
- hca->ib_trans.cm_state == IB_THREAD_RUN ||\r
- !dapl_llist_is_empty(&hca->ib_trans.list);\r
- dapl_os_lock(&hca->ib_trans.lock)) {\r
-\r
- time_ms = INFINITE;\r
- CompSetZero(&hca->ib_trans.signal.set);\r
- CompSetAdd(&hca->ib_hca_handle->channel, &hca->ib_trans.signal.set);\r
- CompSetAdd(&hca->ib_trans.rch->comp_channel, &hca->ib_trans.signal.set);\r
- CompSetAdd(&hca->ib_trans.ib_cq->comp_channel, &hca->ib_trans.signal.set);\r
-\r
- next = dapl_llist_is_empty(&hca->ib_trans.list) ? NULL :\r
- dapl_llist_peek_head(&hca->ib_trans.list);\r
-\r
- while (next) {\r
- cm = next;\r
- next = dapl_llist_next_entry(&hca->ib_trans.list,\r
- (DAPL_LLIST_ENTRY *)&cm->entry);\r
- dapl_os_lock(&cm->lock);\r
- if (cm->state == DCM_DESTROY || \r
- hca->ib_trans.cm_state != IB_THREAD_RUN) {\r
- dapl_llist_remove_entry(&hca->ib_trans.list,\r
- (DAPL_LLIST_ENTRY *)&cm->entry);\r
- dapl_os_unlock(&cm->lock);\r
- dapl_os_lock_destroy(&cm->lock);\r
- dapl_os_free(cm, sizeof(*cm));\r
- continue;\r
- }\r
- dapl_os_unlock(&cm->lock);\r
- ucm_check_timers(cm, &time_ms);\r
- }\r
-\r
- dapl_os_unlock(&hca->ib_trans.lock);\r
-\r
- hca->ib_hca_handle->channel.Milliseconds = time_ms;\r
- hca->ib_trans.rch->comp_channel.Milliseconds = time_ms;\r
- hca->ib_trans.ib_cq->comp_channel.Milliseconds = time_ms;\r
- CompSetPoll(&hca->ib_trans.signal.set, time_ms);\r
-\r
- hca->ib_hca_handle->channel.Milliseconds = 0;\r
- hca->ib_trans.rch->comp_channel.Milliseconds = 0;\r
- hca->ib_trans.ib_cq->comp_channel.Milliseconds = 0;\r
-\r
- ucm_recv(&hca->ib_trans);\r
- ucm_async_event(hca);\r
- dapli_cq_event_cb(&hca->ib_trans);\r
- }\r
-\r
- dapl_os_unlock(&hca->ib_trans.lock);\r
- hca->ib_trans.cm_state = IB_THREAD_EXIT;\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread(hca %p) exit\n", hca);\r
-}\r
-\r
-#else // _WIN32 || _WIN64\r
-\r
-void cm_thread(void *arg)\r
-{\r
- struct dapl_hca *hca = arg;\r
- dp_ib_cm_handle_t cm, next;\r
- struct dapl_fd_set *set;\r
- char rbuf[2];\r
- int time_ms;\r
-\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread: ENTER hca %p\n", hca);\r
- set = dapl_alloc_fd_set();\r
- if (!set)\r
- goto out;\r
-\r
- dapl_os_lock(&hca->ib_trans.lock);\r
- hca->ib_trans.cm_state = IB_THREAD_RUN;\r
-\r
- while (1) {\r
- time_ms = -1; /* reset to blocking */\r
- dapl_fd_zero(set);\r
- dapl_fd_set(hca->ib_trans.signal.scm[0], set, DAPL_FD_READ); \r
- dapl_fd_set(hca->ib_hca_handle->async_fd, set, DAPL_FD_READ);\r
- dapl_fd_set(hca->ib_trans.rch->fd, set, DAPL_FD_READ);\r
- dapl_fd_set(hca->ib_trans.ib_cq->fd, set, DAPL_FD_READ);\r
- \r
- if (!dapl_llist_is_empty(&hca->ib_trans.list))\r
- next = dapl_llist_peek_head(&hca->ib_trans.list);\r
- else\r
- next = NULL;\r
-\r
- while (next) {\r
- cm = next;\r
- next = dapl_llist_next_entry(\r
- &hca->ib_trans.list,\r
- (DAPL_LLIST_ENTRY *)&cm->entry);\r
- dapl_os_lock(&cm->lock);\r
- if (cm->state == DCM_DESTROY || \r
- hca->ib_trans.cm_state != IB_THREAD_RUN) {\r
- dapl_llist_remove_entry(\r
- &hca->ib_trans.list,\r
- (DAPL_LLIST_ENTRY *)&cm->entry);\r
- dapl_os_unlock(&cm->lock);\r
- dapl_os_lock_destroy(&cm->lock);\r
- dapl_os_free(cm, sizeof(*cm));\r
- continue;\r
- }\r
- dapl_os_unlock(&cm->lock);\r
- ucm_check_timers(cm, &time_ms);\r
- }\r
-\r
- /* set to exit and all resources destroyed */\r
- if ((hca->ib_trans.cm_state != IB_THREAD_RUN) &&\r
- (dapl_llist_is_empty(&hca->ib_trans.list)))\r
- break;\r
-\r
- dapl_os_unlock(&hca->ib_trans.lock);\r
- dapl_select(set, time_ms);\r
-\r
- /* Process events: CM, ASYNC, NOTIFY THREAD */\r
- if (dapl_poll(hca->ib_trans.rch->fd, \r
- DAPL_FD_READ) == DAPL_FD_READ) {\r
- ucm_recv(&hca->ib_trans);\r
- }\r
- if (dapl_poll(hca->ib_hca_handle->async_fd, \r
- DAPL_FD_READ) == DAPL_FD_READ) {\r
- ucm_async_event(hca);\r
- }\r
- if (dapl_poll(hca->ib_trans.ib_cq->fd, \r
- DAPL_FD_READ) == DAPL_FD_READ) {\r
- dapli_cq_event_cb(&hca->ib_trans);\r
- }\r
- while (dapl_poll(hca->ib_trans.signal.scm[0], \r
- DAPL_FD_READ) == DAPL_FD_READ) {\r
- recv(hca->ib_trans.signal.scm[0], rbuf, 2, 0);\r
- }\r
-\r
- dapl_os_lock(&hca->ib_trans.lock);\r
- \r
- /* set to exit and all resources destroyed */\r
- if ((hca->ib_trans.cm_state != IB_THREAD_RUN) &&\r
- (dapl_llist_is_empty(&hca->ib_trans.list)))\r
- break;\r
- }\r
-\r
- dapl_os_unlock(&hca->ib_trans.lock);\r
- free(set);\r
-out:\r
- hca->ib_trans.cm_state = IB_THREAD_EXIT;\r
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread(hca %p) exit\n", hca);\r
-}\r
-#endif\r
-\r
-#ifdef DAPL_COUNTERS\r
-/* Debug aid: List all Connections in process and state */\r
-void dapls_print_cm_list(IN DAPL_IA *ia_ptr)\r
-{\r
- /* Print in process CM's for this IA, if debug type set */\r
- int i = 0;\r
- dp_ib_cm_handle_t cm, next_cm;\r
- struct dapl_llist_entry **list;\r
- DAPL_OS_LOCK *lock;\r
- \r
- /* LISTEN LIST */\r
- list = &ia_ptr->hca_ptr->ib_trans.llist;\r
- lock = &ia_ptr->hca_ptr->ib_trans.llock;\r
-\r
- dapl_os_lock(lock);\r
- if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)list))\r
- next_cm = dapl_llist_peek_head((DAPL_LLIST_HEAD*)list);\r
- else\r
- next_cm = NULL;\r
-\r
- printf("\n DAPL IA LISTEN/CONNECTIONS IN PROCESS:\n");\r
- while (next_cm) {\r
- cm = next_cm;\r
- next_cm = dapl_llist_next_entry((DAPL_LLIST_HEAD*)list,\r
- (DAPL_LLIST_ENTRY*)&cm->entry);\r
-\r
- printf( " LISTEN[%d]: sp %p %s uCM_QP: 0x%x %d 0x%x l_pid %x,%d\n",\r
- i, cm->sp, dapl_cm_state_str(cm->state),\r
- ntohs(cm->msg.saddr.ib.lid), ntohs(cm->msg.sport),\r
- ntohl(cm->msg.sqpn), ntohl(*(DAT_UINT32*)cm->msg.resv), \r
- ntohl(*(DAT_UINT32*)cm->msg.resv)); \r
- i++;\r
- }\r
- dapl_os_unlock(lock);\r
-\r
- /* CONNECTION LIST */\r
- list = &ia_ptr->hca_ptr->ib_trans.list;\r
- lock = &ia_ptr->hca_ptr->ib_trans.lock;\r
-\r
- dapl_os_lock(lock);\r
- if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)list))\r
- next_cm = dapl_llist_peek_head((DAPL_LLIST_HEAD*)list);\r
- else\r
- next_cm = NULL;\r
-\r
- while (next_cm) {\r
- cm = next_cm;\r
- next_cm = dapl_llist_next_entry((DAPL_LLIST_HEAD*)list,\r
- (DAPL_LLIST_ENTRY*)&cm->entry);\r
-\r
- printf( " CONN[%d]: ep %p cm %p %s %s"\r
- " %x %x %x %s %x %x %x r_pid %x,%d\n",\r
- i, cm->ep, cm,\r
- cm->msg.saddr.ib.qp_type == IBV_QPT_RC ? "RC" : "UD",\r
- dapl_cm_state_str(cm->state),\r
- ntohs(cm->msg.saddr.ib.lid),\r
- ntohs(cm->msg.sport),\r
- ntohl(cm->msg.saddr.ib.qpn), \r
- cm->sp ? "<-" : "->",\r
- ntohs(cm->msg.daddr.ib.lid),\r
- ntohs(cm->msg.dport),\r
- ntohl(cm->msg.daddr.ib.qpn),\r
- ntohs(cm->msg.op) == DCM_REQ ? 0 : ntohl(*(DAT_UINT32*)cm->msg.resv), \r
- ntohs(cm->msg.op) == DCM_REQ ? 0 : ntohl(*(DAT_UINT32*)cm->msg.resv)); \r
- i++;\r
- }\r
- printf("\n");\r
- dapl_os_unlock(lock);\r
-}\r
-#endif\r
+ dapli_cm_dealloc(cm);\r
+}
+
+dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep)
+{
+ dp_ib_cm_handle_t cm;
+
+ /* Allocate CM, init lock, and initialize */
+ if ((cm = dapl_os_alloc(sizeof(*cm))) == NULL)
+ return NULL;
+
+ (void)dapl_os_memzero(cm, sizeof(*cm));
+ if (dapl_os_lock_init(&cm->lock))
+ goto bail;
+
+ if (dapl_os_wait_object_init(&cm->event)) {
+ dapl_os_lock_destroy(&cm->lock);
+ goto bail;
+ }
+ dapls_cm_acquire(cm);
+
+ cm->msg.ver = htons(DCM_VER);
+ *(DAT_UINT32*)cm->msg.resv = htonl(dapl_os_getpid()); /* exchange PID for debugging */
+
+ /* ACTIVE: init source address QP info from local EP */
+ if (ep) {
+ DAPL_HCA *hca = ep->header.owner_ia->hca_ptr;
+
+ cm->msg.sport = htons(ucm_get_port(&hca->ib_trans, 0));
+ if (!cm->msg.sport) {
+ dapl_os_wait_object_destroy(&cm->event);
+ dapl_os_lock_destroy(&cm->lock);
+ goto bail;
+ }
+ /* link CM object to EP */
+ dapl_ep_link_cm(ep, cm);
+ cm->hca = hca;
+ cm->ep = ep;
+
+ /* IB info in network order */
+ cm->msg.sqpn = htonl(hca->ib_trans.qp->qp_num); /* ucm */
+ cm->msg.saddr.ib.qpn = htonl(ep->qp_handle->qp_num); /* ep */
+ cm->msg.saddr.ib.qp_type = ep->qp_handle->qp_type;
+ cm->msg.saddr.ib.lid = hca->ib_trans.addr.ib.lid;
+ dapl_os_memcpy(&cm->msg.saddr.ib.gid[0],
+ &hca->ib_trans.addr.ib.gid, 16);
+ }
+ return cm;
+bail:
+ dapl_os_free(cm, sizeof(*cm));
+ return NULL;
+}
+
+/* schedule destruction of CM object */
+void dapli_cm_free(dp_ib_cm_handle_t cm)
+{
+ dapl_os_lock(&cm->lock);
+ cm->state = DCM_FREE;
+ dapls_thread_signal(&cm->hca->ib_trans.signal);
+ dapl_os_unlock(&cm->lock);
+}
+
+/* Blocking, ONLY called from dat_ep_free */
+void dapls_cm_free(dp_ib_cm_handle_t cm)
+{
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " cm_free: cm %p %s ep %p refs=%d\n",
+ cm, dapl_cm_state_str(cm->state),
+ cm->ep, cm->ref_count);
+
+ /* free from internal workq, wait until EP is last ref */
+ dapl_os_lock(&cm->lock);
+ cm->state = DCM_FREE;
+ while (cm->ref_count != 1) {
+ dapl_os_unlock(&cm->lock);
+ dapl_os_sleep_usec(10000);
+ dapl_os_lock(&cm->lock);
+ }
+ dapl_os_unlock(&cm->lock);
+
+ /* unlink, dequeue from EP. Final ref so release will destroy */
+ dapl_ep_unlink_cm(cm->ep, cm);
+}
+
+/* ACTIVE/PASSIVE: queue up connection object on CM list */
+static void dapli_queue_conn(dp_ib_cm_handle_t cm)
+{
+ /* add to work queue, list, for cm thread processing */
+ dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm->local_entry);
+ dapl_os_lock(&cm->hca->ib_trans.lock);
+ dapls_cm_acquire(cm);
+ dapl_llist_add_tail(&cm->hca->ib_trans.list,
+ (DAPL_LLIST_ENTRY *)&cm->local_entry, cm);
+ dapl_os_unlock(&cm->hca->ib_trans.lock);
+ dapls_thread_signal(&cm->hca->ib_trans.signal);
+}
+
+/* PASSIVE: queue up listen object on listen list */
+static void dapli_queue_listen(dp_ib_cm_handle_t cm)
+{
+ /* add to work queue, llist, for cm thread processing */
+ dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm->local_entry);
+ dapl_os_lock(&cm->hca->ib_trans.llock);
+ dapls_cm_acquire(cm);
+ dapl_llist_add_tail(&cm->hca->ib_trans.llist,
+ (DAPL_LLIST_ENTRY *)&cm->local_entry, cm);
+ dapl_os_unlock(&cm->hca->ib_trans.llock);
+}
+
+static void dapli_dequeue_listen(dp_ib_cm_handle_t cm)
+{
+ DAPL_HCA *hca = cm->hca;
+
+ dapl_os_lock(&hca->ib_trans.llock);
+ dapl_llist_remove_entry(&hca->ib_trans.llist,
+ (DAPL_LLIST_ENTRY *)&cm->local_entry);
+ dapls_cm_release(cm);
+ dapl_os_unlock(&hca->ib_trans.llock);
+}
+
+/* called with local LIST and CM object lock */
+static void dapli_cm_dequeue(dp_ib_cm_handle_t cm)
+{
+ /* Remove from work queue, cr thread processing */
+ dapl_llist_remove_entry(&cm->hca->ib_trans.list,
+ (DAPL_LLIST_ENTRY *)&cm->local_entry);
+ dapls_cm_release(cm);
+}
+
+static void ucm_disconnect_final(dp_ib_cm_handle_t cm)
+{
+ /* no EP attachment or not RC, nothing to process */
+ if (cm->ep == NULL ||
+ cm->ep->param.ep_attr.service_type != DAT_SERVICE_TYPE_RC)
+ return;
+
+ dapl_os_lock(&cm->lock);
+ if (cm->state == DCM_DISCONNECTED) {
+ dapl_os_unlock(&cm->lock);
+ return;
+ }
+
+ cm->state = DCM_DISCONNECTED;
+ dapl_os_unlock(&cm->lock);
+
+ if (cm->sp)
+ dapls_cr_callback(cm, IB_CME_DISCONNECTED, NULL, 0, cm->sp);
+ else
+ dapl_evd_connection_callback(cm, IB_CME_DISCONNECTED, NULL, 0, cm->ep);
+
+ /* free local resources, EP ref will prevent destory until dat_ep_free */
+ dapls_cm_release(cm);
+}
+
+/*
+ * called from consumer thread via ep_disconnect/ep_free or
+ * from cm_thread when receiving DREQ
+ */
+DAT_RETURN dapli_cm_disconnect(dp_ib_cm_handle_t cm)
+{
+ int finalize = 1;
+
+ dapl_os_lock(&cm->lock);
+ switch (cm->state) {
+ case DCM_CONNECTED:
+ /* CONSUMER: move to err state to flush, if not UD */
+ if (cm->ep->qp_handle->qp_type != IBV_QPT_UD)
+ dapls_modify_qp_state(cm->ep->qp_handle, IBV_QPS_ERR,0,0,0);
+
+ /* send DREQ, event after DREP or DREQ timeout */
+ cm->state = DCM_DISC_PENDING;
+ cm->msg.op = htons(DCM_DREQ);
+ finalize = 0; /* wait for DREP, wakeup timer thread */
+ dapls_thread_signal(&cm->hca->ib_trans.signal);
+ break;
+ case DCM_DISC_PENDING:
+ /* DREQ timeout, resend until retries exhausted */
+ cm->msg.op = htons(DCM_DREQ);
+ if (cm->retries >= cm->hca->ib_trans.retries) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CM_DREQ: RETRIES EXHAUSTED:"
+ " 0x%x %d 0x%x -> 0x%x %d 0x%x\n",
+ htons(cm->msg.saddr.ib.lid),
+ htonl(cm->msg.saddr.ib.qpn),
+ htons(cm->msg.sport),
+ htons(cm->msg.daddr.ib.lid),
+ htonl(cm->msg.dqpn),
+ htons(cm->msg.dport));
+ finalize = 1;
+ }
+ break;
+ case DCM_DISC_RECV:
+ /* CM_THREAD: move to err state to flush, if not UD */
+ if (cm->ep->qp_handle->qp_type != IBV_QPT_UD)
+ dapls_modify_qp_state(cm->ep->qp_handle, IBV_QPS_ERR,0,0,0);
+
+ /* DREQ received, send DREP and schedule event */
+ cm->msg.op = htons(DCM_DREP);
+ break;
+ default:
+ dapl_os_unlock(&cm->lock);
+ return DAT_SUCCESS;
+ }
+
+ dapl_os_get_time(&cm->timer); /* reply expected */
+ ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0);
+ dapl_os_unlock(&cm->lock);
+
+ if (finalize)
+ ucm_disconnect_final(cm);
+
+ return DAT_SUCCESS;
+}
+
+/*
+ * ACTIVE: get remote CM SID server info from r_addr.
+ * send, or resend CM msg via UD CM QP
+ */
+DAT_RETURN
+dapli_cm_connect(DAPL_EP *ep, dp_ib_cm_handle_t cm)
+{
+ dapl_log(DAPL_DBG_TYPE_EP,
+ " connect: lid %x i_qpn %x lport %d p_sz=%d -> "
+ " lid %x c_qpn %x rport %d\n",
+ htons(cm->msg.saddr.ib.lid), htonl(cm->msg.saddr.ib.qpn),
+ htons(cm->msg.sport), htons(cm->msg.p_size),
+ htons(cm->msg.daddr.ib.lid), htonl(cm->msg.dqpn),
+ htons(cm->msg.dport));
+
+ dapl_os_lock(&cm->lock);
+ if (cm->state != DCM_REP_PENDING) {
+ dapl_os_unlock(&cm->lock);
+ return DAT_INVALID_STATE;
+ }
+
+ if (cm->retries == cm->hca->ib_trans.retries) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CM_REQ: RETRIES EXHAUSTED:"
+ " 0x%x %d 0x%x -> 0x%x %d 0x%x\n",
+ htons(cm->msg.saddr.ib.lid),
+ htonl(cm->msg.saddr.ib.qpn),
+ htons(cm->msg.sport),
+ htons(cm->msg.daddr.ib.lid),
+ htonl(cm->msg.dqpn),
+ htons(cm->msg.dport));
+
+ dapl_os_unlock(&cm->lock);
+
+#ifdef DAPL_COUNTERS
+ /* called from check_timers in cm_thread, cm lock held */
+ if (g_dapl_dbg_type & DAPL_DBG_TYPE_CM_LIST) {
+ dapl_os_unlock(&cm->hca->ib_trans.lock);
+ dapls_print_cm_list(ep->header.owner_ia);
+ dapl_os_lock(&cm->hca->ib_trans.lock);
+ }
+#endif
+ dapl_evd_connection_callback(cm,
+ IB_CME_DESTINATION_UNREACHABLE,
+ NULL, 0, ep);
+
+ return DAT_ERROR(DAT_INVALID_ADDRESS,
+ DAT_INVALID_ADDRESS_UNREACHABLE);
+ }
+ dapl_os_unlock(&cm->lock);
+
+ cm->msg.op = htons(DCM_REQ);
+ dapl_os_get_time(&cm->timer); /* reply expected */
+ if (ucm_send(&cm->hca->ib_trans, &cm->msg,
+ &cm->msg.p_data, ntohs(cm->msg.p_size)))
+ goto bail;
+
+ /* first time through, link EP and CM, put on work queue */
+ if (!cm->retries) {
+ dapli_queue_conn(cm);
+ }
+ return DAT_SUCCESS;
+
+bail:
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " connect: ERR %s -> cm_lid %d cm_qpn %d r_psp %d p_sz=%d\n",
+ strerror(errno), htons(cm->msg.daddr.ib.lid),
+ htonl(cm->msg.dqpn), htons(cm->msg.dport),
+ htonl(cm->msg.p_size));
+
+ dapli_cm_free(cm);
+ return DAT_INSUFFICIENT_RESOURCES;
+}
+
+/*
+ * ACTIVE: exchange QP information, called from CR thread
+ */
+static void ucm_connect_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg)
+{
+ DAPL_EP *ep = cm->ep;
+ ib_cm_events_t event = IB_CME_CONNECTED;
+
+ dapl_os_lock(&cm->lock);
+ if (cm->state != DCM_REP_PENDING) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " CONN_RTU: UNEXPECTED state:"
+ " op %d, st %s <- lid %d sqpn %d sport %d\n",
+ ntohs(msg->op), dapl_cm_state_str(cm->state),
+ ntohs(msg->saddr.ib.lid), ntohl(msg->saddr.ib.qpn),
+ ntohs(msg->sport));
+ dapl_os_unlock(&cm->lock);
+ return;
+ }
+
+ /* save remote address information to EP and CM */
+ dapl_os_memcpy(&ep->remote_ia_address,
+ &msg->saddr, sizeof(union dcm_addr));
+ dapl_os_memcpy(&cm->msg.daddr,
+ &msg->saddr, sizeof(union dcm_addr));
+
+ /* validate private data size, and copy if necessary */
+ if (msg->p_size) {
+ if (ntohs(msg->p_size) > DCM_MAX_PDATA_SIZE) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " CONN_RTU: invalid p_size %d:"
+ " st %s <- lid %d sqpn %d spsp %d\n",
+ ntohs(msg->p_size),
+ dapl_cm_state_str(cm->state),
+ ntohs(msg->saddr.ib.lid),
+ ntohl(msg->saddr.ib.qpn),
+ ntohs(msg->sport));
+ dapl_os_unlock(&cm->lock);
+ goto bail;
+ }
+ dapl_os_memcpy(cm->msg.p_data,
+ msg->p_data, ntohs(msg->p_size));
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " CONN_RTU: DST lid=%x,"
+ " iqp=%x, qp_type=%d, port=%d psize=%d\n",
+ ntohs(cm->msg.daddr.ib.lid),
+ ntohl(cm->msg.daddr.ib.qpn), cm->msg.daddr.ib.qp_type,
+ ntohs(msg->sport), ntohs(msg->p_size));
+
+ if (ntohs(msg->op) == DCM_REP)
+ event = IB_CME_CONNECTED;
+ else if (ntohs(msg->op) == DCM_REJ_USER)
+ event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA;
+ else
+ event = IB_CME_DESTINATION_REJECT;
+
+ if (event != IB_CME_CONNECTED) {
+ cm->state = DCM_REJECTED;
+ dapl_os_unlock(&cm->lock);
+
+#ifdef DAT_EXTENSIONS
+ if (cm->msg.daddr.ib.qp_type == IBV_QPT_UD)
+ goto ud_bail;
+ else
+#endif
+ goto bail;
+ }
+ dapl_os_unlock(&cm->lock);
+
+ /* modify QP to RTR and then to RTS with remote info */
+ dapl_os_lock(&cm->ep->header.lock);
+ if (dapls_modify_qp_state(cm->ep->qp_handle,
+ IBV_QPS_RTR,
+ cm->msg.daddr.ib.qpn,
+ cm->msg.daddr.ib.lid,
+ (ib_gid_handle_t)cm->msg.daddr.ib.gid) != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CONN_RTU: QPS_RTR ERR %s <- lid %x iqp %x\n",
+ strerror(errno), ntohs(cm->msg.daddr.ib.lid),
+ ntohl(cm->msg.daddr.ib.qpn));
+ dapl_os_unlock(&cm->ep->header.lock);
+ event = IB_CME_LOCAL_FAILURE;
+ goto bail;
+ }
+ if (dapls_modify_qp_state(cm->ep->qp_handle,
+ IBV_QPS_RTS,
+ cm->msg.daddr.ib.qpn,
+ cm->msg.daddr.ib.lid,
+ NULL) != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CONN_RTU: QPS_RTS ERR %s <- lid %x iqp %x\n",
+ strerror(errno), ntohs(cm->msg.daddr.ib.lid),
+ ntohl(cm->msg.daddr.ib.qpn));
+ dapl_os_unlock(&cm->ep->header.lock);
+ event = IB_CME_LOCAL_FAILURE;
+ goto bail;
+ }
+ dapl_os_unlock(&cm->ep->header.lock);
+
+ /* Send RTU, no private data */
+ cm->msg.op = htons(DCM_RTU);
+
+ dapl_os_lock(&cm->lock);
+ cm->state = DCM_CONNECTED;
+ dapl_os_unlock(&cm->lock);
+
+ if (ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0))
+ goto bail;
+
+ /* init cm_handle and post the event with private data */
+ dapl_dbg_log(DAPL_DBG_TYPE_EP, " ACTIVE: connected!\n");
+
+#ifdef DAT_EXTENSIONS
+ud_bail:
+ if (cm->msg.daddr.ib.qp_type == IBV_QPT_UD) {
+ DAT_IB_EXTENSION_EVENT_DATA xevent;
+ uint16_t lid = ntohs(cm->msg.daddr.ib.lid);
+
+ /* post EVENT, modify_qp, AH already created, ucm msg */
+ xevent.status = 0;
+ xevent.type = DAT_IB_UD_REMOTE_AH;
+ xevent.remote_ah.qpn = ntohl(cm->msg.daddr.ib.qpn);
+ xevent.remote_ah.ah = dapls_create_ah(cm->hca,
+ cm->ep->qp_handle->pd,
+ cm->ep->qp_handle,
+ htons(lid),
+ NULL);
+ if (xevent.remote_ah.ah == NULL) {
+ event = IB_CME_LOCAL_FAILURE;
+ goto bail;
+ }
+ cm->ah = xevent.remote_ah.ah; /* keep ref to destroy */
+
+ dapl_os_memcpy(&xevent.remote_ah.ia_addr,
+ &cm->msg.daddr,
+ sizeof(union dcm_addr));
+
+ /* remote ia_addr reference includes ucm qpn, not IB qpn */
+ ((union dcm_addr*)
+ &xevent.remote_ah.ia_addr)->ib.qpn = cm->msg.dqpn;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " ACTIVE: UD xevent ah %p qpn 0x%x lid 0x%x\n",
+ xevent.remote_ah.ah, xevent.remote_ah.qpn, lid);
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " ACTIVE: UD xevent ia_addr qp_type %d"
+ " lid 0x%x qpn 0x%x gid 0x"F64x" 0x"F64x" \n",
+ ((union dcm_addr*)
+ &xevent.remote_ah.ia_addr)->ib.qp_type,
+ ntohs(((union dcm_addr*)
+ &xevent.remote_ah.ia_addr)->ib.lid),
+ ntohl(((union dcm_addr*)
+ &xevent.remote_ah.ia_addr)->ib.qpn),
+ ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[0]),
+ ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[8]));
+
+ if (event == IB_CME_CONNECTED)
+ event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED;
+ else {
+ xevent.type = DAT_IB_UD_CONNECT_REJECT;
+ event = DAT_IB_UD_CONNECTION_REJECT_EVENT;
+ }
+
+ dapls_evd_post_connection_event_ext(
+ (DAPL_EVD *)cm->ep->param.connect_evd_handle,
+ event,
+ (DAT_EP_HANDLE)ep,
+ (DAT_COUNT)ntohs(cm->msg.p_size),
+ (DAT_PVOID *)cm->msg.p_data,
+ (DAT_PVOID *)&xevent);
+
+ /* release cm_ptr, EP refs will prevent destroy */
+ dapli_cm_free(cm);
+
+ } else
+#endif
+ {
+ dapl_evd_connection_callback(cm,
+ IB_CME_CONNECTED,
+ cm->msg.p_data, ntohs(cm->msg.p_size), cm->ep);
+ }
+ return;
+bail:
+ dapl_evd_connection_callback(NULL, event, cm->msg.p_data, ntohs(cm->msg.p_size), cm->ep);
+ dapli_cm_free(cm);
+}
+
+/*
+ * PASSIVE: Accept on listen CM PSP.
+ * create new CM object for this CR,
+ * receive peer QP information, private data,
+ * and post cr_event
+ */
+static void ucm_accept(ib_cm_srvc_handle_t cm, ib_cm_msg_t *msg)
+{
+ dp_ib_cm_handle_t acm;
+
+ /* Allocate accept CM and setup passive references */
+ if ((acm = dapls_ib_cm_create(NULL)) == NULL) {
+ dapl_log(DAPL_DBG_TYPE_WARN, " accept: ERR cm_create\n");
+ return;
+ }
+
+ /* dest CM info from CR msg, source CM info from listen */
+ acm->sp = cm->sp;
+ acm->hca = cm->hca;
+ acm->msg.dport = msg->sport;
+ acm->msg.dqpn = msg->sqpn;
+ acm->msg.sport = cm->msg.sport;
+ acm->msg.sqpn = cm->msg.sqpn;
+ acm->msg.p_size = msg->p_size;
+
+ /* CR saddr is CM daddr info, need EP for local saddr */
+ dapl_os_memcpy(&acm->msg.daddr, &msg->saddr, sizeof(union dcm_addr));
+
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " accept: DST port=%d lid=%x, iqp=%x, psize=%d\n",
+ ntohs(acm->msg.dport), ntohs(acm->msg.daddr.ib.lid),
+ htonl(acm->msg.daddr.ib.qpn), htons(acm->msg.p_size));
+
+ /* validate private data size before reading */
+ if (ntohs(msg->p_size) > DCM_MAX_PDATA_SIZE) {
+ dapl_log(DAPL_DBG_TYPE_WARN, " accept: psize (%d) wrong\n",
+ ntohs(msg->p_size));
+ goto bail;
+ }
+
+ /* read private data into cm_handle if any present */
+ if (msg->p_size)
+ dapl_os_memcpy(acm->msg.p_data,
+ msg->p_data, ntohs(msg->p_size));
+
+ acm->state = DCM_ACCEPTING;
+ dapli_queue_conn(acm);
+
+#ifdef DAT_EXTENSIONS
+ if (acm->msg.daddr.ib.qp_type == IBV_QPT_UD) {
+ DAT_IB_EXTENSION_EVENT_DATA xevent;
+
+ /* post EVENT, modify_qp created ah */
+ xevent.status = 0;
+ xevent.type = DAT_IB_UD_CONNECT_REQUEST;
+
+ dapls_evd_post_cr_event_ext(acm->sp,
+ DAT_IB_UD_CONNECTION_REQUEST_EVENT,
+ acm,
+ (DAT_COUNT)ntohs(acm->msg.p_size),
+ (DAT_PVOID *)acm->msg.p_data,
+ (DAT_PVOID *)&xevent);
+ } else
+#endif
+ /* trigger CR event and return SUCCESS */
+ dapls_cr_callback(acm,
+ IB_CME_CONNECTION_REQUEST_PENDING,
+ acm->msg.p_data, ntohs(msg->p_size), acm->sp);
+ return;
+
+bail:
+ /* schedule work thread cleanup */
+ dapli_cm_free(acm);
+ return;
+}
+
+/*
+ * PASSIVE: read RTU from active peer, post CONN event
+ */
+static void ucm_accept_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg)
+{
+ dapl_os_lock(&cm->lock);
+ if ((ntohs(msg->op) != DCM_RTU) || (cm->state != DCM_RTU_PENDING)) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " accept_rtu: UNEXPECTED op, state:"
+ " op %d, st %s <- lid %x iqp %x sport %d\n",
+ ntohs(msg->op), dapl_cm_state_str(cm->state),
+ ntohs(msg->saddr.ib.lid), ntohl(msg->saddr.ib.qpn),
+ ntohs(msg->sport));
+ dapl_os_unlock(&cm->lock);
+ goto bail;
+ }
+ cm->state = DCM_CONNECTED;
+ dapl_os_unlock(&cm->lock);
+
+ /* final data exchange if remote QP state is good to go */
+ dapl_dbg_log(DAPL_DBG_TYPE_CM, " PASSIVE: connected!\n");
+
+#ifdef DAT_EXTENSIONS
+ if (cm->msg.saddr.ib.qp_type == IBV_QPT_UD) {
+ DAT_IB_EXTENSION_EVENT_DATA xevent;
+ uint16_t lid = ntohs(cm->msg.daddr.ib.lid);
+
+ /* post EVENT, modify_qp, AH already created, ucm msg */
+ xevent.status = 0;
+ xevent.type = DAT_IB_UD_PASSIVE_REMOTE_AH;
+ xevent.remote_ah.qpn = ntohl(cm->msg.daddr.ib.qpn);
+ xevent.remote_ah.ah = dapls_create_ah(cm->hca,
+ cm->ep->qp_handle->pd,
+ cm->ep->qp_handle,
+ htons(lid),
+ NULL);
+ if (xevent.remote_ah.ah == NULL) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " accept_rtu: ERR create_ah"
+ " for qpn 0x%x lid 0x%x\n",
+ xevent.remote_ah.qpn, lid);
+ goto bail;
+ }
+ cm->ah = xevent.remote_ah.ah; /* keep ref to destroy */
+ dapl_os_memcpy(&xevent.remote_ah.ia_addr,
+ &cm->msg.daddr,
+ sizeof(union dcm_addr));
+
+ /* remote ia_addr reference includes ucm qpn, not IB qpn */
+ ((union dcm_addr*)
+ &xevent.remote_ah.ia_addr)->ib.qpn = cm->msg.dqpn;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " PASSIVE: UD xevent ah %p qpn 0x%x lid 0x%x\n",
+ xevent.remote_ah.ah, xevent.remote_ah.qpn, lid);
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " PASSIVE: UD xevent ia_addr qp_type %d"
+ " lid 0x%x qpn 0x%x gid 0x"F64x" 0x"F64x" \n",
+ ((union dcm_addr*)
+ &xevent.remote_ah.ia_addr)->ib.qp_type,
+ ntohs(((union dcm_addr*)
+ &xevent.remote_ah.ia_addr)->ib.lid),
+ ntohl(((union dcm_addr*)
+ &xevent.remote_ah.ia_addr)->ib.qpn),
+ ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[0]),
+ ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[8]));
+
+ dapls_evd_post_connection_event_ext(
+ (DAPL_EVD *)cm->ep->param.connect_evd_handle,
+ DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED,
+ (DAT_EP_HANDLE)cm->ep,
+ (DAT_COUNT)ntohs(cm->msg.p_size),
+ (DAT_PVOID *)cm->msg.p_data,
+ (DAT_PVOID *)&xevent);
+
+ /* done with CM object, EP ref will hold object for pdata */
+ dapli_cm_free(cm);
+
+ } else {
+#endif
+ dapls_cr_callback(cm, IB_CME_CONNECTED, NULL, 0, cm->sp);
+ }
+ return;
+bail:
+ dapls_cr_callback(cm, IB_CME_LOCAL_FAILURE, NULL, 0, cm->sp);
+ dapli_cm_free(cm);
+}
+
+/*
+ * PASSIVE: user accepted, send reply message with pdata
+ */
+static int ucm_reply(dp_ib_cm_handle_t cm)
+{
+ dapl_os_lock(&cm->lock);
+ if (cm->state != DCM_RTU_PENDING) {
+ dapl_os_unlock(&cm->lock);
+ return -1;
+ }
+
+ if (cm->retries == cm->hca->ib_trans.retries) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " CM_REPLY: RETRIES EXHAUSTED"
+ " 0x%x %d 0x%x -> 0x%x %d 0x%x\n",
+ htons(cm->msg.saddr.ib.lid),
+ htons(cm->msg.sport),
+ htonl(cm->msg.saddr.ib.qpn),
+ htons(cm->msg.daddr.ib.lid),
+ htons(cm->msg.dport),
+ htonl(cm->msg.daddr.ib.qpn));
+
+ dapl_os_unlock(&cm->lock);
+#ifdef DAPL_COUNTERS
+ /* called from check_timers in cm_thread, cm lock held */
+ if (g_dapl_dbg_type & DAPL_DBG_TYPE_CM_LIST) {
+ dapl_os_unlock(&cm->hca->ib_trans.lock);
+ dapls_print_cm_list(dapl_llist_peek_head(&cm->hca->ia_list_head));
+ dapl_os_lock(&cm->hca->ib_trans.lock);
+ }
+#endif
+#ifdef DAT_EXTENSIONS
+ if (cm->msg.saddr.ib.qp_type == IBV_QPT_UD) {
+ DAT_IB_EXTENSION_EVENT_DATA xevent;
+
+ /* post REJECT event with CONN_REQ p_data */
+ xevent.status = 0;
+ xevent.type = DAT_IB_UD_CONNECT_ERROR;
+
+ dapls_evd_post_connection_event_ext(
+ (DAPL_EVD *)cm->ep->param.connect_evd_handle,
+ DAT_IB_UD_CONNECTION_ERROR_EVENT,
+ (DAT_EP_HANDLE)cm->ep,
+ (DAT_COUNT)ntohs(cm->msg.p_size),
+ (DAT_PVOID *)cm->msg.p_data,
+ (DAT_PVOID *)&xevent);
+ } else
+#endif
+ dapls_cr_callback(cm, IB_CME_LOCAL_FAILURE,
+ NULL, 0, cm->sp);
+ return -1;
+ }
+ dapl_os_get_time(&cm->timer); /* RTU expected */
+ dapl_os_unlock(&cm->lock);
+ if (ucm_send(&cm->hca->ib_trans, &cm->msg, cm->p_data, cm->p_size))
+ return -1;
+
+ return 0;
+}
+
+
+/*
+ * PASSIVE: consumer accept, send local QP information, private data,
+ * queue on work thread to receive RTU information to avoid blocking
+ * user thread.
+ */
+DAT_RETURN
+dapli_accept_usr(DAPL_EP *ep, DAPL_CR *cr, DAT_COUNT p_size, DAT_PVOID p_data)
+{
+ DAPL_IA *ia = ep->header.owner_ia;
+ dp_ib_cm_handle_t cm = cr->ib_cm_handle;
+
+ if (p_size > DCM_MAX_PDATA_SIZE)
+ return DAT_LENGTH_ERROR;
+
+ dapl_os_lock(&cm->lock);
+ if (cm->state != DCM_ACCEPTING) {
+ dapl_os_unlock(&cm->lock);
+ return DAT_INVALID_STATE;
+ }
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " ACCEPT_USR: remote lid=%x"
+ " iqp=%x qp_type %d, psize=%d\n",
+ ntohs(cm->msg.daddr.ib.lid),
+ ntohl(cm->msg.daddr.ib.qpn), cm->msg.daddr.ib.qp_type,
+ p_size);
+
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " ACCEPT_USR: remote GID subnet %016llx id %016llx\n",
+ (unsigned long long)
+ htonll(*(uint64_t*)&cm->msg.daddr.ib.gid[0]),
+ (unsigned long long)
+ htonll(*(uint64_t*)&cm->msg.daddr.ib.gid[8]));
+
+#ifdef DAT_EXTENSIONS
+ if (cm->msg.daddr.ib.qp_type == IBV_QPT_UD &&
+ ep->qp_handle->qp_type != IBV_QPT_UD) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT_USR: ERR remote QP is UD,"
+ ", but local QP is not\n");
+ return (DAT_INVALID_HANDLE | DAT_INVALID_HANDLE_EP);
+ }
+#endif
+
+ /* modify QP to RTR and then to RTS with remote info already read */
+ if (dapls_modify_qp_state(ep->qp_handle,
+ IBV_QPS_RTR,
+ cm->msg.daddr.ib.qpn,
+ cm->msg.daddr.ib.lid,
+ (ib_gid_handle_t)cm->msg.daddr.ib.gid) != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT_USR: QPS_RTR ERR %s -> lid %x qpn %x\n",
+ strerror(errno), ntohs(cm->msg.daddr.ib.lid),
+ ntohl(cm->msg.daddr.ib.qpn));
+ dapl_os_unlock(&cm->lock);
+ goto bail;
+ }
+ if (dapls_modify_qp_state(ep->qp_handle,
+ IBV_QPS_RTS,
+ cm->msg.daddr.ib.qpn,
+ cm->msg.daddr.ib.lid,
+ NULL) != DAT_SUCCESS) {
+ dapl_log(DAPL_DBG_TYPE_ERR,
+ " ACCEPT_USR: QPS_RTS ERR %s -> lid %x qpn %x\n",
+ strerror(errno), ntohs(cm->msg.daddr.ib.lid),
+ ntohl(cm->msg.daddr.ib.qpn));
+ dapl_os_unlock(&cm->lock);
+ goto bail;
+ }
+
+ /* save remote address information */
+ dapl_os_memcpy(&ep->remote_ia_address,
+ &cm->msg.saddr, sizeof(union dcm_addr));
+
+ /* setup local QP info and type from EP, copy pdata, for reply */
+ cm->msg.op = htons(DCM_REP);
+ cm->msg.saddr.ib.qpn = htonl(ep->qp_handle->qp_num);
+ cm->msg.saddr.ib.qp_type = ep->qp_handle->qp_type;
+ cm->msg.saddr.ib.lid = cm->hca->ib_trans.addr.ib.lid;
+ dapl_os_memcpy(&cm->msg.saddr.ib.gid[0],
+ &cm->hca->ib_trans.addr.ib.gid, 16);
+
+ /*
+ * UD: deliver p_data with REQ and EST event, keep REQ p_data in
+ * cm->msg.p_data and save REPLY accept data in cm->p_data for retries
+ */
+ cm->p_size = p_size;
+ dapl_os_memcpy(&cm->p_data, p_data, p_size);
+
+ /* save state and setup valid reference to EP, HCA */
+ dapl_ep_link_cm(ep, cm);
+ cm->ep = ep;
+ cm->hca = ia->hca_ptr;
+ cm->state = DCM_RTU_PENDING;
+ dapl_os_get_time(&cm->timer); /* RTU expected */
+ dapl_os_unlock(&cm->lock);
+
+ if (ucm_reply(cm)) {
+ dapl_ep_link_cm(ep, cm);
+ goto bail;
+ }
+ dapl_dbg_log(DAPL_DBG_TYPE_CM, " PASSIVE: accepted!\n");
+ dapls_thread_signal(&cm->hca->ib_trans.signal);
+ return DAT_SUCCESS;
+bail:
+ dapli_cm_free(cm);
+ return DAT_INTERNAL_ERROR;
+}
+
+
+/*
+ * 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_psp,
+ IN DAT_COUNT p_size, IN void *p_data)
+{
+ DAPL_EP *ep = (DAPL_EP *)ep_handle;
+ dp_ib_cm_handle_t cm;
+
+ /* create CM object, initialize SRC info from EP */
+ cm = dapls_ib_cm_create(ep);
+ if (cm == NULL)
+ return DAT_INSUFFICIENT_RESOURCES;
+
+ /* remote hca and port: lid, gid, network order */
+ dapl_os_memcpy(&cm->msg.daddr, r_addr, sizeof(union dcm_addr));
+
+ /* remote uCM information, comes from consumer provider r_addr */
+ cm->msg.dport = htons((uint16_t)r_psp);
+ cm->msg.dqpn = cm->msg.daddr.ib.qpn;
+ cm->msg.daddr.ib.qpn = 0; /* don't have a remote qpn until reply */
+
+ if (p_size) {
+ cm->msg.p_size = htons(p_size);
+ dapl_os_memcpy(&cm->msg.p_data, p_data, p_size);
+ }
+
+ cm->state = DCM_REP_PENDING;
+
+ /* build connect request, send to remote CM based on r_addr info */
+ return (dapli_cm_connect(ep, cm));
+}
+
+/*
+ * 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 cm_ptr = dapl_get_cm_from_ep(ep_ptr);
+
+ if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED ||
+ ep_ptr->param.ep_attr.service_type != DAT_SERVICE_TYPE_RC) {
+ return DAT_SUCCESS;
+ }
+
+ /* RC. Transition to error state to flush queue */
+ dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0, 0, 0);
+
+ return (dapli_cm_disconnect(cm_ptr));
+}
+
+/*
+ * 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. It is also called if dat_ep_connect
+ * times out using the consumer supplied timeout value.
+ *
+ * Input:
+ * ep_ptr DAPL_EP
+ * active Indicates active side of connection
+ *
+ * Output:
+ * none
+ *
+ * Returns:
+ * void
+ *
+ */
+void
+dapls_ib_disconnect_clean(IN DAPL_EP *ep,
+ IN DAT_BOOLEAN active,
+ IN const ib_cm_events_t ib_cm_event)
+{
+ /* nothing to cleanup */
+}
+
+/*
+ * 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,
+ IN DAT_UINT64 sid,
+ IN DAPL_SP *sp)
+{
+ ib_cm_srvc_handle_t cm = NULL;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " listen(ia %p ServiceID %d sp %p)\n",
+ ia, sid, sp);
+
+ /* reserve local port, then allocate CM object */
+ if (!ucm_get_port(&ia->hca_ptr->ib_trans, (uint16_t)sid)) {
+ dapl_dbg_log(DAPL_DBG_TYPE_WARN,
+ " listen: ERROR %s on conn_qual 0x%x\n",
+ strerror(errno), sid);
+ return DAT_CONN_QUAL_IN_USE;
+ }
+
+ /* cm_create will setup saddr for listen server */
+ if ((cm = dapls_ib_cm_create(NULL)) == NULL)
+ return DAT_INSUFFICIENT_RESOURCES;
+
+ /* LISTEN: init DST address and QP info to local CM server info */
+ cm->sp = sp;
+ cm->hca = ia->hca_ptr;
+ cm->msg.sport = htons((uint16_t)sid);
+ cm->msg.sqpn = htonl(ia->hca_ptr->ib_trans.qp->qp_num);
+ cm->msg.saddr.ib.qp_type = IBV_QPT_UD;
+ cm->msg.saddr.ib.lid = ia->hca_ptr->ib_trans.addr.ib.lid;
+ dapl_os_memcpy(&cm->msg.saddr.ib.gid[0],
+ &cm->hca->ib_trans.addr.ib.gid, 16);
+
+ /* save cm_handle reference in service point */
+ sp->cm_srvc_handle = cm;
+
+ /* queue up listen socket to process inbound CR's */
+ cm->state = DCM_LISTEN;
+ dapli_queue_listen(cm);
+
+ return DAT_SUCCESS;
+}
+
+
+/*
+ * 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, IN DAPL_SP *sp)
+{
+ ib_cm_srvc_handle_t cm = sp->cm_srvc_handle;
+
+ /* free cm_srvc_handle and port, and mark CM for cleanup */
+ if (cm) {
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " remove_listener(ia %p sp %p cm %p psp=%d)\n",
+ ia, sp, cm, ntohs(cm->msg.dport));
+
+ sp->cm_srvc_handle = NULL;
+ dapli_dequeue_listen(cm);
+ dapls_cm_release(cm); /* last ref, dealloc */
+ }
+ 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 = (DAPL_CR *)cr_handle;
+ DAPL_EP *ep = (DAPL_EP *)ep_handle;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " accept_connection(cr %p ep %p prd %p,%d)\n",
+ cr, ep, p_data, p_size);
+
+ /* allocate and attach a QP if necessary */
+ if (ep->qp_state == DAPL_QP_STATE_UNATTACHED) {
+ DAT_RETURN status;
+ status = dapls_ib_qp_alloc(ep->header.owner_ia,
+ ep, ep);
+ if (status != DAT_SUCCESS)
+ return status;
+ }
+ return (dapli_accept_usr(ep, cr, p_size, p_data));
+}
+
+/*
+ * 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,
+ IN int reason,
+ IN DAT_COUNT psize, IN const DAT_PVOID pdata)
+{
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ " reject(cm %p reason %x, pdata %p, psize %d)\n",
+ cm, reason, pdata, psize);
+
+ if (psize > DCM_MAX_PDATA_SIZE)
+ return DAT_LENGTH_ERROR;
+
+ /* cr_thread will destroy CR, update saddr lid, gid, qp_type info */
+ dapl_os_lock(&cm->lock);
+ cm->state = DCM_REJECTED;
+ cm->msg.saddr.ib.lid = cm->hca->ib_trans.addr.ib.lid;
+ cm->msg.saddr.ib.qp_type = cm->msg.daddr.ib.qp_type;
+ dapl_os_memcpy(&cm->msg.saddr.ib.gid[0],
+ &cm->hca->ib_trans.addr.ib.gid, 16);
+ cm->msg.op = htons(DCM_REJ_USER);
+
+ if (ucm_send(&cm->hca->ib_trans, &cm->msg, pdata, psize)) {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ " cm_reject: ERR: %s\n", strerror(errno));
+ dapl_os_unlock(&cm->lock);
+ return DAT_INTERNAL_ERROR;
+ }
+ dapl_os_unlock(&cm->lock);
+ dapli_cm_free(cm);
+ return DAT_SUCCESS;
+}
+
+/*
+ * 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 * remote_ia_address)
+{
+ DAPL_HEADER *header;
+ dp_ib_cm_handle_t cm;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_EP,
+ "dapls_ib_cm_remote_addr(dat_handle %p, ....)\n",
+ dat_handle);
+
+ header = (DAPL_HEADER *) dat_handle;
+
+ if (header->magic == DAPL_MAGIC_EP)
+ cm = dapl_get_cm_from_ep((DAPL_EP *) dat_handle);
+ else if (header->magic == DAPL_MAGIC_CR)
+ cm = ((DAPL_CR *) dat_handle)->ib_cm_handle;
+ else
+ return DAT_INVALID_HANDLE;
+
+ dapl_os_memcpy(remote_ia_address,
+ &cm->msg.daddr, sizeof(DAT_SOCK_ADDR6));
+
+ return DAT_SUCCESS;
+}
+
+int dapls_ib_private_data_size(
+ IN DAPL_HCA *hca_ptr)
+{
+ return DCM_MAX_PDATA_SIZE;
+}
+
+#if defined(_WIN32) || defined(_WIN64)
+
+void cm_thread(void *arg)
+{
+ struct dapl_hca *hca = arg;
+ dp_ib_cm_handle_t cm, next;
+ DWORD time_ms;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread: ENTER hca %p\n", hca);
+ dapl_os_lock(&hca->ib_trans.lock);
+ for (hca->ib_trans.cm_state = IB_THREAD_RUN;
+ hca->ib_trans.cm_state == IB_THREAD_RUN ||
+ !dapl_llist_is_empty(&hca->ib_trans.list);
+ dapl_os_lock(&hca->ib_trans.lock)) {
+
+ time_ms = INFINITE;
+ CompSetZero(&hca->ib_trans.signal.set);
+ CompSetAdd(&hca->ib_hca_handle->channel, &hca->ib_trans.signal.set);
+ CompSetAdd(&hca->ib_trans.rch->comp_channel, &hca->ib_trans.signal.set);
+ CompSetAdd(&hca->ib_trans.ib_cq->comp_channel, &hca->ib_trans.signal.set);
+
+ next = dapl_llist_is_empty(&hca->ib_trans.list) ? NULL :
+ dapl_llist_peek_head(&hca->ib_trans.list);
+
+ while (next) {
+ cm = next;
+ next = dapl_llist_next_entry(&hca->ib_trans.list,
+ (DAPL_LLIST_ENTRY *)&cm->local_entry);
+ dapls_cm_acquire(cm); /* hold thread ref */
+ dapl_os_lock(&cm->lock);
+ if (cm->state == DCM_FREE ||
+ hca->ib_trans.cm_state != IB_THREAD_RUN) {
+ dapl_os_unlock(&cm->lock);
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " CM FREE: %p ep=%p st=%s refs=%d\n",
+ cm, cm->ep, dapl_cm_state_str(cm->state),
+ cm->ref_count);
+
+ dapls_cm_release(cm); /* release alloc ref */
+ dapli_cm_dequeue(cm); /* release workq ref */
+ dapls_cm_release(cm); /* release thread ref */
+ continue;
+ }
+ dapl_os_unlock(&cm->lock);
+ ucm_check_timers(cm, &time_ms);
+ dapls_cm_release(cm); /* release thread ref */
+ }
+
+ dapl_os_unlock(&hca->ib_trans.lock);
+
+ hca->ib_hca_handle->channel.Milliseconds = time_ms;
+ hca->ib_trans.rch->comp_channel.Milliseconds = time_ms;
+ hca->ib_trans.ib_cq->comp_channel.Milliseconds = time_ms;
+ CompSetPoll(&hca->ib_trans.signal.set, time_ms);
+
+ hca->ib_hca_handle->channel.Milliseconds = 0;
+ hca->ib_trans.rch->comp_channel.Milliseconds = 0;
+ hca->ib_trans.ib_cq->comp_channel.Milliseconds = 0;
+
+ ucm_recv(&hca->ib_trans);
+ ucm_async_event(hca);
+ dapli_cq_event_cb(&hca->ib_trans);
+ }
+
+ dapl_os_unlock(&hca->ib_trans.lock);
+ hca->ib_trans.cm_state = IB_THREAD_EXIT;
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread(hca %p) exit\n", hca);
+}
+
+#else // _WIN32 || _WIN64
+
+void cm_thread(void *arg)
+{
+ struct dapl_hca *hca = arg;
+ dp_ib_cm_handle_t cm, next;
+ struct dapl_fd_set *set;
+ char rbuf[2];
+ int time_ms;
+
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread: ENTER hca %p\n", hca);
+ set = dapl_alloc_fd_set();
+ if (!set)
+ goto out;
+
+ dapl_os_lock(&hca->ib_trans.lock);
+ hca->ib_trans.cm_state = IB_THREAD_RUN;
+
+ while (1) {
+ time_ms = -1; /* reset to blocking */
+ dapl_fd_zero(set);
+ dapl_fd_set(hca->ib_trans.signal.scm[0], set, DAPL_FD_READ);
+ dapl_fd_set(hca->ib_hca_handle->async_fd, set, DAPL_FD_READ);
+ dapl_fd_set(hca->ib_trans.rch->fd, set, DAPL_FD_READ);
+ dapl_fd_set(hca->ib_trans.ib_cq->fd, set, DAPL_FD_READ);
+
+ if (!dapl_llist_is_empty(&hca->ib_trans.list))
+ next = dapl_llist_peek_head(&hca->ib_trans.list);
+ else
+ next = NULL;
+
+ while (next) {
+ cm = next;
+ next = dapl_llist_next_entry(
+ &hca->ib_trans.list,
+ (DAPL_LLIST_ENTRY *)&cm->local_entry);
+ dapls_cm_acquire(cm); /* hold thread ref */
+ dapl_os_lock(&cm->lock);
+ if (cm->state == DCM_FREE ||
+ hca->ib_trans.cm_state != IB_THREAD_RUN) {
+ dapl_os_unlock(&cm->lock);
+ dapl_log(DAPL_DBG_TYPE_CM,
+ " CM FREE: %p ep=%p st=%s refs=%d\n",
+ cm, cm->ep, dapl_cm_state_str(cm->state),
+ cm->ref_count);
+
+ dapls_cm_release(cm); /* release alloc ref */
+ dapli_cm_dequeue(cm); /* release workq ref */
+ dapls_cm_release(cm); /* release thread ref */
+ continue;
+ }
+ dapl_os_unlock(&cm->lock);
+ ucm_check_timers(cm, &time_ms);
+ dapls_cm_release(cm); /* release thread ref */
+ }
+
+ /* set to exit and all resources destroyed */
+ if ((hca->ib_trans.cm_state != IB_THREAD_RUN) &&
+ (dapl_llist_is_empty(&hca->ib_trans.list)))
+ break;
+
+ dapl_os_unlock(&hca->ib_trans.lock);
+ dapl_select(set, time_ms);
+
+ /* Process events: CM, ASYNC, NOTIFY THREAD */
+ if (dapl_poll(hca->ib_trans.rch->fd,
+ DAPL_FD_READ) == DAPL_FD_READ) {
+ ucm_recv(&hca->ib_trans);
+ }
+ if (dapl_poll(hca->ib_hca_handle->async_fd,
+ DAPL_FD_READ) == DAPL_FD_READ) {
+ ucm_async_event(hca);
+ }
+ if (dapl_poll(hca->ib_trans.ib_cq->fd,
+ DAPL_FD_READ) == DAPL_FD_READ) {
+ dapli_cq_event_cb(&hca->ib_trans);
+ }
+ while (dapl_poll(hca->ib_trans.signal.scm[0],
+ DAPL_FD_READ) == DAPL_FD_READ) {
+ recv(hca->ib_trans.signal.scm[0], rbuf, 2, 0);
+ }
+ dapl_os_lock(&hca->ib_trans.lock);
+
+ /* set to exit and all resources destroyed */
+ if ((hca->ib_trans.cm_state != IB_THREAD_RUN) &&
+ (dapl_llist_is_empty(&hca->ib_trans.list)))
+ break;
+ }
+
+ dapl_os_unlock(&hca->ib_trans.lock);
+ free(set);
+out:
+ hca->ib_trans.cm_state = IB_THREAD_EXIT;
+ dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread(hca %p) exit\n", hca);
+}
+#endif
+
+#ifdef DAPL_COUNTERS
+/* Debug aid: List all Connections in process and state */
+void dapls_print_cm_list(IN DAPL_IA *ia_ptr)
+{
+ /* Print in process CM's for this IA, if debug type set */
+ int i = 0;
+ dp_ib_cm_handle_t cm, next_cm;
+ struct dapl_llist_entry **list;
+ DAPL_OS_LOCK *lock;
+
+ /* LISTEN LIST */
+ list = &ia_ptr->hca_ptr->ib_trans.llist;
+ lock = &ia_ptr->hca_ptr->ib_trans.llock;
+
+ dapl_os_lock(lock);
+ if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)list))
+ next_cm = dapl_llist_peek_head((DAPL_LLIST_HEAD*)list);
+ else
+ next_cm = NULL;
+
+ printf("\n DAPL IA LISTEN/CONNECTIONS IN PROCESS:\n");
+ while (next_cm) {
+ cm = next_cm;
+ next_cm = dapl_llist_next_entry((DAPL_LLIST_HEAD*)list,
+ (DAPL_LLIST_ENTRY*)&cm->local_entry);
+
+ printf( " LISTEN[%d]: sp %p %s uCM_QP: 0x%x %d 0x%x l_pid %x,%d\n",
+ i, cm->sp, dapl_cm_state_str(cm->state),
+ ntohs(cm->msg.saddr.ib.lid), ntohs(cm->msg.sport),
+ ntohl(cm->msg.sqpn), ntohl(*(DAT_UINT32*)cm->msg.resv),
+ ntohl(*(DAT_UINT32*)cm->msg.resv));
+ i++;
+ }
+ dapl_os_unlock(lock);
+
+ /* CONNECTION LIST */
+ list = &ia_ptr->hca_ptr->ib_trans.list;
+ lock = &ia_ptr->hca_ptr->ib_trans.lock;
+
+ dapl_os_lock(lock);
+ if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)list))
+ next_cm = dapl_llist_peek_head((DAPL_LLIST_HEAD*)list);
+ else
+ next_cm = NULL;
+
+ while (next_cm) {
+ cm = next_cm;
+ next_cm = dapl_llist_next_entry((DAPL_LLIST_HEAD*)list,
+ (DAPL_LLIST_ENTRY*)&cm->local_entry);
+
+ printf( " CONN[%d]: ep %p cm %p %s %s"
+ " %x %x %x %s %x %x %x r_pid %x,%d\n",
+ i, cm->ep, cm,
+ cm->msg.saddr.ib.qp_type == IBV_QPT_RC ? "RC" : "UD",
+ dapl_cm_state_str(cm->state),
+ ntohs(cm->msg.saddr.ib.lid),
+ ntohs(cm->msg.sport),
+ ntohl(cm->msg.saddr.ib.qpn),
+ cm->sp ? "<-" : "->",
+ ntohs(cm->msg.daddr.ib.lid),
+ ntohs(cm->msg.dport),
+ ntohl(cm->msg.daddr.ib.qpn),
+ ntohs(cm->msg.op) == DCM_REQ ? 0 : ntohl(*(DAT_UINT32*)cm->msg.resv),
+ ntohs(cm->msg.op) == DCM_REQ ? 0 : ntohl(*(DAT_UINT32*)cm->msg.resv));
+ i++;
+ }
+ printf("\n");
+ dapl_os_unlock(lock);
+}
+#endif
#include "openib_osd.h"
#include "dapl_ib_common.h"
+/* DAPL CM objects MUST include list_entry, ref_count, event for EP linking */
struct ib_cm_handle
{
- struct dapl_llist_entry entry;
+ struct dapl_llist_entry list_entry;
+ struct dapl_llist_entry local_entry;
+ DAPL_OS_WAIT_OBJECT event;
DAPL_OS_LOCK lock;
DAPL_OS_TIMEVAL timer;
+ int ref_count;
int state;
int retries;
struct dapl_hca *hca;
void cm_thread(void *arg);
void ucm_async_event(struct dapl_hca *hca);
void dapli_cq_event_cb(struct _ib_hca_transport *tp);
-dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep);
-void dapls_ib_cm_free(dp_ib_cm_handle_t cm, DAPL_EP *ep);
+void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr);
+void dapls_cm_release(dp_ib_cm_handle_t cm_ptr);
+void dapls_cm_free(dp_ib_cm_handle_t cm_ptr);
+
+#ifdef DAPL_COUNTERS
void dapls_print_cm_list(IN DAPL_IA *ia_ptr);
+#endif
#endif /* _DAPL_IB_UTIL_H_ */
destroy_os_signal(hca_ptr);
ucm_service_destroy(hca_ptr);
- if (hca_ptr->ib_trans.ib_cq)\r
- ibv_destroy_comp_channel(hca_ptr->ib_trans.ib_cq);\r
-\r
- if (hca_ptr->ib_trans.ib_cq_empty) {\r
- struct ibv_comp_channel *channel;\r
- channel = hca_ptr->ib_trans.ib_cq_empty->channel;\r
- ibv_destroy_cq(hca_ptr->ib_trans.ib_cq_empty);\r
- ibv_destroy_comp_channel(channel);\r
- }\r
+ if (hca_ptr->ib_trans.ib_cq)
+ ibv_destroy_comp_channel(hca_ptr->ib_trans.ib_cq);
+
+ if (hca_ptr->ib_trans.ib_cq_empty) {
+ struct ibv_comp_channel *channel;
+ channel = hca_ptr->ib_trans.ib_cq_empty->channel;
+ ibv_destroy_cq(hca_ptr->ib_trans.ib_cq_empty);
+ ibv_destroy_comp_channel(channel);
+ }
if (hca_ptr->ib_hca_handle != IB_INVALID_HANDLE) {
if (ibv_close_device(hca_ptr->ib_hca_handle))
rem set DAT_OVERRIDE=D:\dapl2\dat.conf\r
rem favor DAT 2.0 (dapl2test.exe) over DAT 1.1 (dapltest.exe)\r
\r
-set PF="%ProgramFiles%\OFED"\r
+set PF="%ProgramFiles%\WinOF"\r
\r
if NOT EXIST %PF%\dapl2test.exe (\r
echo Missing file %PF%\dapl2test.exe ?\r
\r
rem set DAT_OVERRIDE=C:\DAT\dat.conf\r
\r
-set PF="%ProgramFiles%\OFED"\r
+set PF="%ProgramFiles%\WinOF"\r
\r
if NOT EXIST %PF%\dapl2test.exe (\r
echo Missing file %PF%\dapl2test.exe ?\r